From 5b5273b0b692297542ab09f9a66ce8e5aa0706af Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 17 Aug 2016 15:47:35 -0700 Subject: [PATCH 001/239] First cdms2 documentation revamp --- docs/Makefile | 192 ++++++++++++++++ docs/createRST.sh | 15 ++ docs/generate_modules.py | 262 ++++++++++++++++++++++ docs/source/Lib.rst | 6 + docs/source/MV2.rst | 6 + docs/source/Makefile | 192 ++++++++++++++++ docs/source/api.rst | 6 + docs/source/auxcoord.rst | 6 + docs/source/avariable.rst | 6 + docs/source/axis.rst | 6 + docs/source/bindex.rst | 6 + docs/source/cache.rst | 6 + docs/source/cdmsobj.rst | 6 + docs/source/conf.py | 367 +++++++++++++++++++++++++++++++ docs/source/convention.rst | 6 + docs/source/coord.rst | 6 + docs/source/database.rst | 6 + docs/source/dataset.rst | 6 + docs/source/error.rst | 6 + docs/source/fvariable.rst | 6 + docs/source/gengrid.rst | 6 + docs/source/grid.rst | 6 + docs/source/gsHost.rst | 6 + docs/source/gsStaticVariable.rst | 6 + docs/source/gsTimeVariable.rst | 6 + docs/source/hgrid.rst | 6 + docs/source/index.rst | 50 +++++ docs/source/mvBaseWriter.rst | 6 + docs/source/mvCdmsRegrid.rst | 6 + docs/source/mvSphereMesh.rst | 6 + docs/source/mvVsWriter.rst | 6 + docs/source/selectors.rst | 6 + docs/source/sliceut.rst | 6 + docs/source/tvariable.rst | 6 + docs/source/variable.rst | 6 + 35 files changed, 1252 insertions(+) create mode 100644 docs/Makefile create mode 100755 docs/createRST.sh create mode 100644 docs/generate_modules.py create mode 100644 docs/source/Lib.rst create mode 100644 docs/source/MV2.rst create mode 100644 docs/source/Makefile create mode 100644 docs/source/api.rst create mode 100644 docs/source/auxcoord.rst create mode 100644 docs/source/avariable.rst create mode 100644 docs/source/axis.rst create mode 100644 docs/source/bindex.rst create mode 100644 docs/source/cache.rst create mode 100644 docs/source/cdmsobj.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/convention.rst create mode 100644 docs/source/coord.rst create mode 100644 docs/source/database.rst create mode 100644 docs/source/dataset.rst create mode 100644 docs/source/error.rst create mode 100644 docs/source/fvariable.rst create mode 100644 docs/source/gengrid.rst create mode 100644 docs/source/grid.rst create mode 100644 docs/source/gsHost.rst create mode 100644 docs/source/gsStaticVariable.rst create mode 100644 docs/source/gsTimeVariable.rst create mode 100644 docs/source/hgrid.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/mvBaseWriter.rst create mode 100644 docs/source/mvCdmsRegrid.rst create mode 100644 docs/source/mvSphereMesh.rst create mode 100644 docs/source/mvVsWriter.rst create mode 100644 docs/source/selectors.rst create mode 100644 docs/source/sliceut.rst create mode 100644 docs/source/tvariable.rst create mode 100644 docs/source/variable.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..2aa9c4d2 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdms.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdms.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cdms" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdms" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/createRST.sh b/docs/createRST.sh new file mode 100755 index 00000000..f77af08c --- /dev/null +++ b/docs/createRST.sh @@ -0,0 +1,15 @@ +#!/bin/bash +a=('cdmsobj' 'axis' 'coord' 'grid' 'hgrid' 'avariable' 'sliceut' 'error' 'variable' 'fvariable' 'tvariable' 'dataset' 'database' 'cache' 'selectors' 'MV2' 'convention' 'bindex' 'auxcoord' 'gengrid' 'gsHost' 'gsStaticVariable' 'gsTimeVariable' 'mvBaseWriter' 'mvSphereMesh' 'mvVsWriter' 'mvCdmsRegrid') + +for i in "${a[@]}"; do +echo "creating "$i".rst" +echo "cdms $i +======== + +.. automodule:: cdms2.$i + :members: +" >$i.rst + + +done + diff --git a/docs/generate_modules.py b/docs/generate_modules.py new file mode 100644 index 00000000..e38c943e --- /dev/null +++ b/docs/generate_modules.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +sphinx-autopackage-script + +This script parses a directory tree looking for python modules and packages and +creates ReST files appropriately to create code documentation with Sphinx. +It also creates a modules index (named modules.). +""" + +# Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/ +# Copyright 2010 Thomas Waldmann +# All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import os +import optparse + + +# automodule options +OPTIONS = ['members', + 'undoc-members', + # 'inherited-members', # disabled because there's a bug in sphinx + 'show-inheritance', + ] + +INIT = '__init__.py' + +def makename(package, module): + """Join package and module with a dot.""" + # Both package and module can be None/empty. + if package: + name = package + if module: + name += '.' + module + else: + name = module + return name + +def write_file(name, text, opts): + """Write the output file for module/package .""" + if opts.dryrun: + return + fname = os.path.join(opts.destdir, "%s.%s" % (name, opts.suffix)) + if not opts.force and os.path.isfile(fname): + print 'File %s already exists, skipping.' % fname + else: + print 'Creating file %s.' % fname + f = open(fname, 'w') + f.write(text) + f.close() + +def format_heading(level, text): + """Create a heading of [1, 2 or 3 supported].""" + underlining = ['=', '-', '~', ][level-1] * len(text) + return '%s\n%s\n\n' % (text, underlining) + +def format_directive(module, package=None): + """Create the automodule directive and add the options.""" + directive = '.. automodule:: %s\n' % makename(package, module) + for option in OPTIONS: + directive += ' :%s:\n' % option + return directive + +def create_module_file(package, module, opts): + """Build the text of the file and write the file.""" + text = format_heading(1, '%s Module' % module) + text += format_heading(2, ':mod:`%s` Module' % module) + text += format_directive(module, package) + write_file(makename(package, module), text, opts) + +def create_package_file(root, master_package, subroot, py_files, opts, subs): + """Build the text of the file and write the file.""" + package = os.path.split(root)[-1] + text = format_heading(1, '%s Package' % package) + # add each package's module + for py_file in py_files: + if shall_skip(os.path.join(root, py_file)): + continue + is_package = py_file == INIT + py_file = os.path.splitext(py_file)[0] + py_path = makename(subroot, py_file) + if is_package: + heading = ':mod:`%s` Package' % package + else: + heading = ':mod:`%s` Module' % py_file + text += format_heading(2, heading) + text += format_directive(is_package and subroot or py_path, master_package) + text += '\n' + + # build a list of directories that are packages (they contain an INIT file) + subs = [sub for sub in subs if os.path.isfile(os.path.join(root, sub, INIT))] + # if there are some package directories, add a TOC for theses subpackages + if subs: + text += format_heading(2, 'Subpackages') + text += '.. toctree::\n\n' + for sub in subs: + text += ' %s.%s\n' % (makename(master_package, subroot), sub) + text += '\n' + + write_file(makename(master_package, subroot), text, opts) + +def create_modules_toc_file(master_package, modules, opts, name='modules'): + """ + Create the module's index. + """ + text = format_heading(1, '%s Modules' % opts.header) + text += '.. toctree::\n' + text += ' :maxdepth: %s\n\n' % opts.maxdepth + + modules.sort() + prev_module = '' + for module in modules: + # look if the module is a subpackage and, if yes, ignore it + if module.startswith(prev_module + '.'): + continue + prev_module = module + text += ' %s\n' % module + + write_file(name, text, opts) + +def shall_skip(module): + """ + Check if we want to skip this module. + """ + # skip it, if there is nothing (or just \n or \r\n) in the file + return os.path.getsize(module) < 3 + +def recurse_tree(path, excludes, opts): + """ + Look for every file in the directory tree and create the corresponding + ReST files. + """ + # use absolute path for root, as relative paths like '../../foo' cause + # 'if "/." in root ...' to filter out *all* modules otherwise + path = os.path.abspath(path) + # check if the base directory is a package and get is name + if INIT in os.listdir(path): + package_name = path.split(os.path.sep)[-1] + else: + package_name = None + + toc = [] + tree = os.walk(path, False) + for root, subs, files in tree: + # keep only the Python script files + py_files = sorted([f for f in files if os.path.splitext(f)[1] == '.py']) + if INIT in py_files: + py_files.remove(INIT) + py_files.insert(0, INIT) + # remove hidden ('.') and private ('_') directories + subs = sorted([sub for sub in subs if sub[0] not in ['.', '_']]) + # check if there are valid files to process + # TODO: could add check for windows hidden files + if "/." in root or "/_" in root \ + or not py_files \ + or is_excluded(root, excludes): + continue + if INIT in py_files: + # we are in package ... + if (# ... with subpackage(s) + subs + or + # ... with some module(s) + len(py_files) > 1 + or + # ... with a not-to-be-skipped INIT file + not shall_skip(os.path.join(root, INIT)) + ): + subroot = root[len(path):].lstrip(os.path.sep).replace(os.path.sep, '.') + create_package_file(root, package_name, subroot, py_files, opts, subs) + toc.append(makename(package_name, subroot)) + elif root == path: + # if we are at the root level, we don't require it to be a package + for py_file in py_files: + if not shall_skip(os.path.join(path, py_file)): + module = os.path.splitext(py_file)[0] + create_module_file(package_name, module, opts) + toc.append(makename(package_name, module)) + + # create the module's index + if not opts.notoc: + create_modules_toc_file(package_name, toc, opts) + +def normalize_excludes(rootpath, excludes): + """ + Normalize the excluded directory list: + * must be either an absolute path or start with rootpath, + * otherwise it is joined with rootpath + * with trailing slash + """ + sep = os.path.sep + f_excludes = [] + for exclude in excludes: + if not os.path.isabs(exclude) and not exclude.startswith(rootpath): + exclude = os.path.join(rootpath, exclude) + if not exclude.endswith(sep): + exclude += sep + f_excludes.append(exclude) + return f_excludes + +def is_excluded(root, excludes): + """ + Check if the directory is in the exclude list. + + Note: by having trailing slashes, we avoid common prefix issues, like + e.g. an exlude "foo" also accidentally excluding "foobar". + """ + sep = os.path.sep + if not root.endswith(sep): + root += sep + for exclude in excludes: + if root.startswith(exclude): + return True + return False + +def main(): + """ + Parse and check the command line arguments. + """ + parser = optparse.OptionParser(usage="""usage: %prog [options] [exclude paths, ...] + +Note: By default this script will not overwrite already created files.""") + parser.add_option("-n", "--doc-header", action="store", dest="header", help="Documentation Header (default=Project)", default="Project") + parser.add_option("-d", "--dest-dir", action="store", dest="destdir", help="Output destination directory", default="") + parser.add_option("-s", "--suffix", action="store", dest="suffix", help="module suffix (default=txt)", default="txt") + parser.add_option("-m", "--maxdepth", action="store", dest="maxdepth", help="Maximum depth of submodules to show in the TOC (default=4)", type="int", default=4) + parser.add_option("-r", "--dry-run", action="store_true", dest="dryrun", help="Run the script without creating the files") + parser.add_option("-f", "--force", action="store_true", dest="force", help="Overwrite all the files") + parser.add_option("-t", "--no-toc", action="store_true", dest="notoc", help="Don't create the table of content file") + (opts, args) = parser.parse_args() + if not args: + parser.error("package path is required.") + else: + rootpath, excludes = args[0], args[1:] + if os.path.isdir(rootpath): + # check if the output destination is a valid directory + if opts.destdir and os.path.isdir(opts.destdir): + excludes = normalize_excludes(rootpath, excludes) + recurse_tree(rootpath, excludes, opts) + else: + print '%s is not a valid output destination directory.' % opts.destdir + else: + print '%s is not a valid directory.' % rootpath + + +if __name__ == '__main__': + main() + diff --git a/docs/source/Lib.rst b/docs/source/Lib.rst new file mode 100644 index 00000000..8f8e34d3 --- /dev/null +++ b/docs/source/Lib.rst @@ -0,0 +1,6 @@ +Lib +======== + +.. automodule:: cdms2.Lib + :members: + diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst new file mode 100644 index 00000000..d9c3a216 --- /dev/null +++ b/docs/source/MV2.rst @@ -0,0 +1,6 @@ +MV2 +======== + +.. automodule:: cdms2.MV2 + :members: + diff --git a/docs/source/Makefile b/docs/source/Makefile new file mode 100644 index 00000000..314da453 --- /dev/null +++ b/docs/source/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdms2.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdms2.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cdms2" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdms2" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 00000000..5a561c63 --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,6 @@ +MV2 +======== + +.. automodule:: cdms2.MV2 + :members: + diff --git a/docs/source/auxcoord.rst b/docs/source/auxcoord.rst new file mode 100644 index 00000000..892cff84 --- /dev/null +++ b/docs/source/auxcoord.rst @@ -0,0 +1,6 @@ +auxcoord +======== + +.. automodule:: cdms2.auxcoord + :members: + diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst new file mode 100644 index 00000000..ae0cb3ca --- /dev/null +++ b/docs/source/avariable.rst @@ -0,0 +1,6 @@ +avariable +======== + +.. automodule:: cdms2.avariable + :members: + diff --git a/docs/source/axis.rst b/docs/source/axis.rst new file mode 100644 index 00000000..1d0e9aee --- /dev/null +++ b/docs/source/axis.rst @@ -0,0 +1,6 @@ +axis +======== + +.. automodule:: cdms2.axis + :members: + diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst new file mode 100644 index 00000000..84f1d88a --- /dev/null +++ b/docs/source/bindex.rst @@ -0,0 +1,6 @@ +bindex +======== + +.. automodule:: cdms2.bindex + :members: + diff --git a/docs/source/cache.rst b/docs/source/cache.rst new file mode 100644 index 00000000..9904d1fa --- /dev/null +++ b/docs/source/cache.rst @@ -0,0 +1,6 @@ +cache +======== + +.. automodule:: cdms2.cache + :members: + diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst new file mode 100644 index 00000000..84c1be56 --- /dev/null +++ b/docs/source/cdmsobj.rst @@ -0,0 +1,6 @@ +cdmsobj +======== + +.. automodule:: cdms2.cdmsobj + :members: + diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..b96215c2 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- +# +# cdms2 documentation build configuration file, created by +# sphinx-quickstart on Wed Aug 17 14:33:12 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.todo', + 'sphinx.ext.viewcode', +] + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'cdms2' +copyright = u'2016, Author' +author = u'Author' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '' +# The full version, including alpha/beta/rc tags. +release = '' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', '_templates'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'alabaster' +html_theme = 'sphinxdoc' +#html_theme = 'nature' +#html_theme = 'agogo' +#html_theme = 'pyramid' +#html_theme = 'epub' +#html_theme = 'haiku' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = { +# "rightsidebar": "false", +# "relbarbgcolor": "black"} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'cdms2doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'cdms2.tex', u'cdms2 Documentation', + u'Author', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'cdms2', u'cdms2 Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'cdms2', u'cdms2 Documentation', + author, 'cdms2', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not optimized +# for small screen space, using the same theme for HTML and epub output is +# usually not wise. This defaults to 'epub', a theme designed to save visual +# space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True diff --git a/docs/source/convention.rst b/docs/source/convention.rst new file mode 100644 index 00000000..e4079a75 --- /dev/null +++ b/docs/source/convention.rst @@ -0,0 +1,6 @@ +convention +======== + +.. automodule:: cdms2.convention + :members: + diff --git a/docs/source/coord.rst b/docs/source/coord.rst new file mode 100644 index 00000000..0cb886a2 --- /dev/null +++ b/docs/source/coord.rst @@ -0,0 +1,6 @@ +coord +======== + +.. automodule:: cdms2.coord + :members: + diff --git a/docs/source/database.rst b/docs/source/database.rst new file mode 100644 index 00000000..ae772ae8 --- /dev/null +++ b/docs/source/database.rst @@ -0,0 +1,6 @@ +database +======== + +.. automodule:: cdms2.database + :members: + diff --git a/docs/source/dataset.rst b/docs/source/dataset.rst new file mode 100644 index 00000000..b59562aa --- /dev/null +++ b/docs/source/dataset.rst @@ -0,0 +1,6 @@ +dataset +======== + +.. automodule:: cdms2.dataset + :members: + diff --git a/docs/source/error.rst b/docs/source/error.rst new file mode 100644 index 00000000..8b37e9cd --- /dev/null +++ b/docs/source/error.rst @@ -0,0 +1,6 @@ +error +======== + +.. automodule:: cdms2.error + :members: + diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst new file mode 100644 index 00000000..18b3288e --- /dev/null +++ b/docs/source/fvariable.rst @@ -0,0 +1,6 @@ +fvariable +======== + +.. automodule:: cdms2.fvariable + :members: + diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst new file mode 100644 index 00000000..41b08364 --- /dev/null +++ b/docs/source/gengrid.rst @@ -0,0 +1,6 @@ +gengrid +======== + +.. automodule:: cdms2.gengrid + :members: + diff --git a/docs/source/grid.rst b/docs/source/grid.rst new file mode 100644 index 00000000..a40f294b --- /dev/null +++ b/docs/source/grid.rst @@ -0,0 +1,6 @@ +grid +======== + +.. automodule:: cdms2.grid + :members: + diff --git a/docs/source/gsHost.rst b/docs/source/gsHost.rst new file mode 100644 index 00000000..4ed66a10 --- /dev/null +++ b/docs/source/gsHost.rst @@ -0,0 +1,6 @@ +gsHost +======== + +.. automodule:: cdms2.gsHost + :members: + diff --git a/docs/source/gsStaticVariable.rst b/docs/source/gsStaticVariable.rst new file mode 100644 index 00000000..e173b1cd --- /dev/null +++ b/docs/source/gsStaticVariable.rst @@ -0,0 +1,6 @@ +gsStaticVariable +======== + +.. automodule:: cdms2.gsStaticVariable + :members: + diff --git a/docs/source/gsTimeVariable.rst b/docs/source/gsTimeVariable.rst new file mode 100644 index 00000000..3ca7de75 --- /dev/null +++ b/docs/source/gsTimeVariable.rst @@ -0,0 +1,6 @@ +gsTimeVariable +======== + +.. automodule:: cdms2.gsTimeVariable + :members: + diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst new file mode 100644 index 00000000..f39233ee --- /dev/null +++ b/docs/source/hgrid.rst @@ -0,0 +1,6 @@ +hgrid +======== + +.. automodule:: cdms2.hgrid + :members: + diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..4f3924bb --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,50 @@ +.. cdms2 documentation master file, created by + sphinx-quickstart on Wed Aug 17 14:33:12 2016. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to cdms2's documentation! +================================= + +Contents: + +.. toctree:: + MV2 + tvariable + avariable + cdmsobj + axis + coord + grid + hgrid + avariable + sliceut + error + variable + fvariable + tvariable + dataset + database + cache + selectors + MV2 + convention + bindex + auxcoord + gengrid + gsHost + gsStaticVariable + gsTimeVariable + mvBaseWriter + mvSphereMesh + mvVsWriter + mvCdmsRegrid + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst new file mode 100644 index 00000000..43aa0530 --- /dev/null +++ b/docs/source/mvBaseWriter.rst @@ -0,0 +1,6 @@ +mvBaseWriter +======== + +.. automodule:: cdms2.mvBaseWriter + :members: + diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst new file mode 100644 index 00000000..3d2de85f --- /dev/null +++ b/docs/source/mvCdmsRegrid.rst @@ -0,0 +1,6 @@ +mvCdmsRegrid +======== + +.. automodule:: cdms2.mvCdmsRegrid + :members: + diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst new file mode 100644 index 00000000..057ed975 --- /dev/null +++ b/docs/source/mvSphereMesh.rst @@ -0,0 +1,6 @@ +mvSphereMesh +======== + +.. automodule:: cdms2.mvSphereMesh + :members: + diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst new file mode 100644 index 00000000..e8c41c17 --- /dev/null +++ b/docs/source/mvVsWriter.rst @@ -0,0 +1,6 @@ +mvVsWriter +======== + +.. automodule:: cdms2.mvVsWriter + :members: + diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst new file mode 100644 index 00000000..89fef4aa --- /dev/null +++ b/docs/source/selectors.rst @@ -0,0 +1,6 @@ +selectors +======== + +.. automodule:: cdms2.selectors + :members: + diff --git a/docs/source/sliceut.rst b/docs/source/sliceut.rst new file mode 100644 index 00000000..e14aab4e --- /dev/null +++ b/docs/source/sliceut.rst @@ -0,0 +1,6 @@ +sliceut +======== + +.. automodule:: cdms2.sliceut + :members: + diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst new file mode 100644 index 00000000..8fd37354 --- /dev/null +++ b/docs/source/tvariable.rst @@ -0,0 +1,6 @@ +tvariable +======== + +.. automodule:: cdms2.tvariable + :members: + diff --git a/docs/source/variable.rst b/docs/source/variable.rst new file mode 100644 index 00000000..8438c35d --- /dev/null +++ b/docs/source/variable.rst @@ -0,0 +1,6 @@ +variable +======== + +.. automodule:: cdms2.variable + :members: + From 5b686f16dba112cfb9a79b8de49e1e600acc2e5c Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 30 Aug 2016 09:58:59 -0700 Subject: [PATCH 002/239] latest changes --- docs/source/cdmsobj.rst | 6 ++++-- docs/source/conf.py | 4 ++++ docs/source/index.rst | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst index 84c1be56..c66c4576 100644 --- a/docs/source/cdmsobj.rst +++ b/docs/source/cdmsobj.rst @@ -1,6 +1,8 @@ cdmsobj -======== +======= -.. automodule:: cdms2.cdmsobj +.. py:currentmodule:: cdms2.cdmsobj + +.. autoclass:: CdmsObj :members: diff --git a/docs/source/conf.py b/docs/source/conf.py index b96215c2..4d994678 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,6 +20,10 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) +#sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) +#sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) +sys.path.insert(0,"/software/anaconda2/envs/uvcdat-2.6.1/lib/python2.7/site-packages") +print os.path.join(sys.prefix,"lib","python2.7","site-packages") # -- General configuration ------------------------------------------------ diff --git a/docs/source/index.rst b/docs/source/index.rst index 4f3924bb..dded7a9b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -11,13 +11,13 @@ Contents: .. toctree:: MV2 tvariable + AbstractVariable avariable cdmsobj axis coord grid hgrid - avariable sliceut error variable From f639376a432f2705bbc47503f1147c3a082f5caf Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 10 Oct 2016 16:09:18 -0700 Subject: [PATCH 003/239] add new files and work on avariable documentations --- .gitignore | 41 ++++ Lib/avariable.py | 364 ++++++++++++++++++++----------- docs/source/AbstractVariable.rst | 8 + docs/source/conf.py | 99 ++------- docs/source/globe.png | Bin 0 -> 30178 bytes docs/source/uvcdat.png | Bin 0 -> 37672 bytes 6 files changed, 307 insertions(+), 205 deletions(-) create mode 100644 .gitignore create mode 100644 docs/source/AbstractVariable.rst create mode 100644 docs/source/globe.png create mode 100644 docs/source/uvcdat.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8a1cb485 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +#**************************************************************** +#Copyright (c) 2009 Larence Livermore National Security (LLNS) +#All rights reserved. +#**************************************************************** +# +# Organization: Lawrence Livermore National Lab (LLNL) +# Directorate: Computation +# Department: Computing Applications and Research +# Division: S&T Global Security +# Matrix: Atmospheric, Earth and Energy Division +# Program: PCMDI +# Project: Earth Systems Grid +# +# Description: +# +# Files that git should ignore... +#**************************************************************** + +TAGS +.ant-targets-build.xml +*~ +*swp +*.cache +*.DS_Store +*.a +*.o +*.class +*.pyc +*.project +*.cproject +*.pydevproject +*.egg +*#* +*.md5 +semantic.cache* +generated/ +build/ +/dist +/test-results +Makefile +checked_get.sh diff --git a/Lib/avariable.py b/Lib/avariable.py index f15d7a06..d5a66b65 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -38,8 +38,15 @@ def getMinHorizontalMask(var): """ Get the minimum mask associated with 'x' and 'y' (i.e. with the min number of ones) across all axes - @param var CDMS variable with a mask - @return mask array or None if order 'x' and 'y' were not found + + Parameters + ---------- + var + CDMS variable with a mask + + Return + ------ + mask array or None if order 'x' and 'y' were not found """ from distarray import MultiArrayIter @@ -142,7 +149,9 @@ def __array__ (self, t=None, context=None): #Numeric, ufuncs call this return numpy.ma.filled(self.getValue(squeeze=0)) def __call__ (self, *args, **kwargs): - "Selection of a subregion using selectors" + """ + Selection of a subregion using selectors. + """ # separate options from selector specs d = kwargs.copy() raw = d.setdefault('raw', 0) @@ -228,7 +237,7 @@ def _returnArray(self, ar, squeeze, singles=None): return result def generateGridkey(self, convention, vardict): - """ generateGridkey(): Determine if the variable is gridded, + """ Determine if the variable is gridded, and generate ((latname, lonname, order, maskname, class), lat, lon) if gridded, or (None, None, None) if not gridded. vardict is the variable dictionary of the parent""" @@ -296,7 +305,7 @@ def generateGridkey(self, convention, vardict): return None, lat, lon def generateRectGridkey(self, lat, lon): - """ generateRectGridkey(): Determine if the variable is gridded, rectilinear, + """Determine if the variable is gridded, rectilinear, and generate (latname, lonname, order, maskname, class) if gridded, or None if not gridded""" @@ -355,9 +364,11 @@ def getAxis(self, n): return self.getDomain()[n][0] def getAxisIndex (self, axis_spec): - """Return the index of the axis specificed by axis_spec. - Argument axis_spec and be as for axisMatches - Return -1 if no match. + """Get the index of the axis specificed by axis_spec. + + Return + ------ + the axis index or -1 if no match is found. """ for i in range(self.rank()): if axisMatches(self.getAxis(i), axis_spec): @@ -365,10 +376,10 @@ def getAxisIndex (self, axis_spec): return -1 def hasCellData(self): - ''' + """ If any of the variable's axis has explicit bounds, we have cell data otherwise we have point data. - ''' + """ for axis in self.getAxisList(): if (axis.getExplicitBounds() is not None): return True @@ -376,25 +387,35 @@ def hasCellData(self): def getAxisListIndex (self, axes=None, omit=None, order=None): """Return a list of indices of axis objects; - If axes is not None, include only certain axes. - less the ones specified in omit. If axes is None, - use all axes of this variable. + + Note + ---- + If axes is **not** `None`, include only certain axes. + less the ones specified in omit. + + If axes is `None`, use all axes of this variable. + Other specificiations are as for axisMatchIndex. """ return axisMatchIndex(self.getAxisList(), axes, omit, order) def getAxisList(self, axes = None, omit=None, order=None): """Get the list of axis objects; - If axes is not None, include only certain axes. - If omit is not None, omit those specified by omit. - Arguments omit or axes may be as specified in axisMatchAxis - order is an optional string determining the output order + + Note + ---- + If axes is **not** `None`, include only certain axes. + If omit is **not** `None`, omit those specified by omit. + + Arguments omit or axes may be as specified in axisMatchAxis + + order is an optional string determining the output order """ alist = [d[0] for d in self.getDomain()] return axisMatchAxis (alist, axes, omit, order) def getAxisIds(self): - "Get a list of axis identifiers" + """Get a list of axis identifiers.""" return [x[0].id for x in self.getDomain()] # Return the grid @@ -402,8 +423,16 @@ def getGrid(self): return self._grid_ def getMissing(self, asarray=0): - """Return the missing value as a scalar, or as - a numpy array if asarray==1""" + """ + Parameters + ---------- + asarray : + '0' : scalar + '1' : numpy array + Return + ------ + the missing value as a scalar, or as a numpy array if asarray==1""" + try: mv = self.missing_value.item() except: @@ -422,9 +451,16 @@ def _setmissing(self, name, value): self.setMissing(value) def setMissing(self, value): - """Set the missing value, which may be a scalar, - a single-valued numpy array, or None. The value is - cast to the same type as the variable.""" + """Set the missing value. + + Parameters + ---------- + value + scalar, a single-valued numpy array, or None. + + Note + ---- + The value is cast to the same type as the variable.""" # Check for None first, so that constructors can # set missing_value before typecode() is initialized. @@ -452,7 +488,7 @@ def setMissing(self, value): def getTime(self): - "Get the first time dimension, or None if not found" + "Get the first time dimension, or `None` if not found" for k in range(self.rank()): axis = self.getAxis(k) if axis.isTime(): @@ -462,7 +498,7 @@ def getTime(self): return None def getForecastTime(self): - "Get the first forecast time dimension, or None if not found" + "Get the first forecast time dimension, or `None` if not found" for k in range(self.rank()): axis = self.getAxis(k) if axis.isForecast(): @@ -475,7 +511,7 @@ def getForecast(self): def getLevel(self): """Get the first vertical level dimension in the domain, - or None if not found. + or `None` if not found. """ for k in range(self.rank()): axis = self.getAxis(k) @@ -486,7 +522,7 @@ def getLevel(self): return None def getLatitude(self): - "Get the first latitude dimension, or None if not found." + "Get the first latitude dimension, or `None` if not found." grid = self.getGrid() if grid is not None: result = grid.getLatitude() @@ -504,7 +540,7 @@ def getLatitude(self): return result def getLongitude(self): - "Get the first latitude dimension, or None if not found." + "Get the first latitude dimension, or `None` if not found." grid = self.getGrid() if grid is not None: result = grid.getLongitude() @@ -523,18 +559,23 @@ def getLongitude(self): # Get an order string, such as "tzyx" def getOrder(self, ids=0): - """getOrder(ids=0) returns the order string, such as tzyx. - - if ids == 0 (the default) for an axis that is not t,z,x,y - the order string will contain a '-' in that location. - The result string will be of the same length as the number - of axes. This makes it easy to loop over the dimensions. - - if ids == 1 those axes will be represented in the order - string as (id) where id is that axis' id. The result will - be suitable for passing to order2index to get the - corresponding axes, and to orderparse for dividing up into - components. + """ + returns + ------- + the order string, such as t, z, y, x (time, level, lat, lon). + + Note + ---- + * if ids == 0 (the default) for an axis that is not t,z,x,y + the order string will contain a (-) character in that location. + The result string will be of the same length as the number + of axes. This makes it easy to loop over the dimensions. + + * if ids == 1 those axes will be represented in the order + string as (id) where id is that axis' id. The result will + be suitable for passing to order2index to get the + corresponding axes, and to orderparse for dividing up into + components. """ order = "" for k in range(self.rank()): @@ -640,27 +681,47 @@ def subSlice (self, *specs, **keys): return resultArray def getSlice (self, *specs, **keys): - """x.getSlice takes arguments of the following forms and produces - a return array. The keyword argument squeeze determines whether - or not the shape of the returned array contains dimensions whose - length is 1; by default this argument is 1, and such dimensions - are 'squeezed out'. + """getSlice takes arguments of the following forms and produces + a return array. + + Parameter + --------- + squeeze : default 1 + Determines whether or not the shape + of the returned array contains dimensions whose length is 1, such + dimensions are 'squeezed out' by default. + numericSqueeze + + + raw + + order + + grid + + isitem + + + Note + ---- + There can be zero or more positional arguments, each of the form: - (a) a single integer n, meaning slice(n, n+1) - (b) an instance of the slice class - (c) a tuple, which will be used as arguments to create a slice - (d) None or ':', which means a slice covering that entire dimension - (e) Ellipsis (...), which means to fill the slice list with ':' - leaving only enough room at the end for the remaining - positional arguments + + #. a single integer n, meaning slice(n, n+1) + #. an instance of the slice class + #. a tuple, which will be used as arguments to create a slice + #. `None` or `:`, which means a slice covering that entire dimension + #. Ellipsis (...), which means to fill the slice list with `:` + leaving only enough room at the end for the remaining positional arguments + There can be keyword arguments of the form key = value, where - key can be one of the names 'time', 'level', 'latitude', or - 'longitude'. The corresponding value can be any of (a)-(d) above. + key can be one of the names `time`, `level`, `latitude`, or + `longitude`. The corresponding value can be any of (1)-(5) above. There must be no conflict between the positional arguments and the keywords. - In (a)-(c) negative numbers are treated as offsets from the end + In (1)-(5) negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing. """ # Turn on squeeze and raw options by default. @@ -681,36 +742,42 @@ def expertSlice(self, slicelist): raise CDMSError, NotImplemented + 'expertSlice' def getRegion(self, *specs, **keys): - """getRegion - Read a region of data. A region is an n-dimensional - rectangular region specified in coordinate space. - 'slices' is an argument list, each item of which has one of the following forms: - - x, where x is a scalar - Map the scalar to the index of the closest coordinate value - - (x,y) - Map the half-open coordinate interval [x,y) to index interval - - (x,y,'cc') - Map the closed interval [x,y] to index interval. Other options are 'oo' (open), - 'oc' (open on the left), and 'co' (open on the right, the default). - - (x,y,'co',cycle) - Map the coordinate interval with wraparound. If no cycle is specified, wraparound - will occur iff axis.isCircular() is true. - NOTE: Only one dimension may be wrapped. - - Ellipsis - Represents the full range of all dimensions bracketed by non-Ellipsis items. - - ':' or None - Represents the full range of one dimension. - - For example, suppose the variable domain is (time,level,lat,lon). Then - - getRegion((10,20),850,Ellipsis,(-180,180)) - - retrieves: - - all times t such that 10.<=t<20. - - level 850 - - all values of all dimensions between level and lon (namely, lat) - - longitudes x such that -180<=x<180. This will be wrapped unless - lon.topology=='linear' + """ Read a region of data. A region is an n-dimensional rectangular region specified in coordinate space. + + Parameters + ---------- + slice + is an argument list, each item of which has one of the following forms: + * x, where x is a scalar + * Map the scalar to the index of the closest coordinate value. + * (x, y) + * Map the half-open coordinate interval [x,y) to index interval. + * (x, y, 'cc') + * Map the closed interval [x,y] to index interval. Other options are 'oo' (open), 'oc' (open on the left), and 'co' (open on the right, the default). + * (x, y, 'co', cycle) + * Map the coordinate interval with wraparound. If no cycle is specified, wraparound will occur iff axis.isCircular() is true. + Ellipsis + Represents the full range of all dimensions bracketed by non-Ellipsis items. + None, colon + Represents the full range of one dimension. + + Note + ---- + Only one dimension may be wrapped. + + + Example + ------- + Suppose the variable domain is `(time, level, lat, lon)`. Then + + >>> getRegion((10, 20), 850, Ellipsis,(-180, 180)) + + retrieves: + + * all times t such that 10.<=t<20. + * level 850. + * all values of all dimensions between level and lon (namely, lat). + * longitudes x such that -180<=x<180. This will be wrapped unless lon.topology=='linear'. """ # By default, squeeze and raw options are on @@ -955,7 +1022,7 @@ def subRegion (self, *specs, **keys): return result.getSlice(squeeze=0, raw=1) def getValue(self, squeeze=1): - """Return the entire set of values.""" + """Get the entire set of values.""" return self.getSlice(Ellipsis, squeeze=squeeze) def assignValue(self,data): @@ -975,17 +1042,27 @@ def regrid (self, togrid, missing=None, order=None, mask=None, **keywords): """return self regridded to the new grid. One can use the regrid2.Regridder optional arguments as well. - Example: - new_cdmsVar = cdmsVar.regrid(newGrid) # uses libcf - new_cdmsVar = cdmsVar.regrid(newGrid, regridMethod = 'conserve', - coordSys = 'cart') - - @param togrid destination grid. CDMS grid - @param missing missing values - @param order axis order - @param mask grid/data mask - @param keywords optional keyword arguments dependent on regridTool - @return regridded variable + Example + ------- + >>> new_cdmsVar = cdmsVar.regrid(newGrid) # uses libcf + >>> new_cdmsVar = cdmsVar.regrid(newGrid, regridMethod = 'conserve', coordSys = 'cart') + + Parameters + ---------- + togrid + togrid destination grid. CDMS grid + missing : Optional + missing missing values + order : Optional + order axis order + mask : Optional + mask grid/data mask + **keyords + keywords optional keyword arguments dependent on regridTool + + Returns + ------- + regridded variable """ # there is a circular dependency between cdms2 and regrid2. In # principle, cdms2 files should not import regrid2, we're bending @@ -1131,10 +1208,16 @@ def regrid (self, togrid, missing=None, order=None, mask=None, **keywords): def pressureRegrid (self, newLevel, missing=None, order=None, method="log"): """Return the variable regridded to new pressure levels. The variable should be a function of lat, lon, pressure, and (optionally) time. - is an axis of the result pressure levels. - is optional, either "log" to interpolate in the log of pressure (default), - or "linear" for linear interpolation. - and are as for regrid.PressureRegridder. + + Parameters + ---------- + newLevel : + is an axis of the result pressure levels. + method : + is optional, either `log` to interpolate in the log of pressure (default), or `linear` for linear interpolation. + missing and order : + are as for regrid.PressureRegridder. + """ from regrid2 import PressureRegridder @@ -1148,11 +1231,19 @@ def pressureRegrid (self, newLevel, missing=None, order=None, method="log"): def crossSectionRegrid(self, newLevel, newLatitude, missing=None, order=None, method="log"): """Return the variable regridded to new pressure levels and latitudes. The variable should be a function of lat, level, and (optionally) time. - is an axis of the result pressure levels. - is an axis of latitude values. - is optional, either "log" to interpolate in the log of pressure (default), - or "linear" for linear interpolation. - and are as for regrid.CrossSectionRegridder. + + Parameters + ----------- + newLevel : + is an axis of the result pressure levels. + newLatitude : + is an axis of latitude values. + method : Optional + either "log" to interpolate in the log of pressure (default), + or "linear" for linear interpolation. + missing and order: + are as for regrid.CrossSectionRegridder. + """ from regrid2 import CrossSectionRegridder @@ -1168,9 +1259,12 @@ def crossSectionRegrid(self, newLevel, newLatitude, missing=None, order=None, me def _process_specs (self, specs, keys): """Process the arguments for a getSlice, getRegion, etc. - Returns an array of specifications for all dimensions. - Any Ellipsis has been eliminated. time, level, latitude, longitude keywords handled here + + Return + ------ + An array of specifications for all dimensions. + Any Ellipsis has been eliminated. """ myrank = self.rank() nsupplied = len(specs) @@ -1224,14 +1318,17 @@ def _single_specs (self, specs): return singles def specs2slices (self, speclist, force=None): - """Create an equivalent list of slices from an index specification + """Create an equivalent list of slices from an index specification. An index specification is a list of acceptable items, which are - -- an integer - -- a slice instance (slice(start, stop, stride)) - -- the object "unspecified" - -- the object None - -- a colon + + * an integer + * a slice instance (slice(start, stop, stride)) + * the object "unspecified" + * the object None + * a colon + The size of the speclist must be self.rank() + """ if len(speclist) != self.rank(): raise CDMSError, "Incorrect length of speclist in specs2slices." @@ -1359,11 +1456,16 @@ def _decodedType(self): return result def isEncoded(self): - "True iff self is represented as packed data." + "True if self is represented as packed data." return (hasattr(self,"scale_factor") or hasattr(self,"add_offset")) def decode(self, ar): - "Decode compressed data. ar is a masked array, scalar, or numpy.ma.masked" + """Decode compressed data. + + Parameter + --------- + ar is a masked array, scalar, or numpy.ma.masked.""" + resulttype = self._decodedType() if hasattr(self, 'scale_factor'): scale_factor = self.scale_factor @@ -1388,7 +1490,9 @@ def decode(self, ar): return ar def getGridIndices(self): - """Return a tuple of indices corresponding to the variable grid.""" + """Return + ------ + a tuple of indices corresponding to the variable grid.""" grid = self.getGrid() result = [] if grid is not None: @@ -1512,13 +1616,14 @@ def astype (self, tc): __crp = re.compile(__rp) def orderparse (order): """Parse an order string. Returns a list of axes specifiers. + Note + ---- Order elements can be: - Letters t, x, y, z meaning time, longitude, latitude, level - Numbers 0-9 representing position in axes - The letter - meaning insert the next available axis here. - The ellipsis ... meaning fill these positions with any - remaining axes. - (name) meaning an axis whose id is name + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * The letter - meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name """ if not isinstance(order, types.StringType): raise CDMSError, 'order arguments must be strings.' @@ -1547,13 +1652,14 @@ def orderparse (order): def order2index (axes, order): """Find the index permutation of axes to match order. The argument order is a string. + Note + ---- Order elements can be: - Letters t, x, y, z meaning time, longitude, latitude, level - Numbers 0-9 representing position in axes - The letter - meaning insert the next available axis here. - The ellipsis ... meaning fill these positions with any - remaining axes. - (name) meaning an axis whose id is name + * Letters t, x, y, z meaning time, longitude, latitude, level. + * Numbers 0-9 representing position in axes + * The letter - meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name. """ if isinstance(order, types.StringType): result = orderparse(order) diff --git a/docs/source/AbstractVariable.rst b/docs/source/AbstractVariable.rst new file mode 100644 index 00000000..a7db97e0 --- /dev/null +++ b/docs/source/AbstractVariable.rst @@ -0,0 +1,8 @@ +AbstractVariable +================ + +.. py:currentmodule:: cdms2.avariable + +.. autoclass:: AbstractVariable + :members: + diff --git a/docs/source/conf.py b/docs/source/conf.py index 4d994678..8338e6f2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -37,8 +37,19 @@ 'sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon' ] +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -73,7 +84,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -118,19 +129,18 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. #html_theme = 'alabaster' -html_theme = 'sphinxdoc' +#html_theme = 'sphinxdoc' #html_theme = 'nature' #html_theme = 'agogo' #html_theme = 'pyramid' #html_theme = 'epub' #html_theme = 'haiku' +html_theme = 'classic' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = { -# "rightsidebar": "false", -# "relbarbgcolor": "black"} +html_theme_options = { "stickysidebar" : "true" } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -144,12 +154,12 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = 'uvcdat.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = 'globe.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -186,7 +196,7 @@ #html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True @@ -233,6 +243,7 @@ # Latex figure (float) alignment #'figure_align': 'htbp', + 'classoptions': ',oneside', } # Grouping the document tree into LaTeX files. List of tuples @@ -245,11 +256,11 @@ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +latex_logo = "uvcdat.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +latex_toplevel_sectioning = "chapter" # If true, show page references after internal links. #latex_show_pagerefs = False @@ -301,71 +312,7 @@ #texinfo_no_detailmenu = False -# -- Options for Epub output ---------------------------------------------- +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} -# Bibliographic Dublin Core info. -epub_title = project -epub_author = author -epub_publisher = author -epub_copyright = copyright -# The basename for the epub file. It defaults to the project name. -#epub_basename = project - -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. -#epub_theme = 'epub' - -# The language of the text. It defaults to the language option -# or 'en' if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# A sequence of (type, uri, title) tuples for the guide element of content.opf. -#epub_guide = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Choose between 'default' and 'includehidden'. -#epub_tocscope = 'default' - -# Fix unsupported image types using the Pillow. -#epub_fix_images = False - -# Scale large images. -#epub_max_image_width = 0 - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#epub_show_urls = 'inline' - -# If false, no index is generated. -#epub_use_index = True diff --git a/docs/source/globe.png b/docs/source/globe.png new file mode 100644 index 0000000000000000000000000000000000000000..75f6d8bd5d0c5ad550a606c5ace024d48aef6c47 GIT binary patch literal 30178 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 literal 0 HcmV?d00001 From a7d61672274f645bdbb27bdfb530db049e3df40e Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 10 Oct 2016 16:18:45 -0700 Subject: [PATCH 004/239] fix index order --- docs/source/index.rst | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index dded7a9b..1d7e6535 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,36 +9,31 @@ Welcome to cdms2's documentation! Contents: .. toctree:: - MV2 - tvariable AbstractVariable avariable - cdmsobj + auxcoord axis - coord - grid - hgrid - sliceut - error - variable - fvariable - tvariable - dataset - database + bindex cache - selectors - MV2 + cdmsobj convention - bindex - auxcoord + database + dataset + fvariable gengrid + grid gsHost gsStaticVariable gsTimeVariable - mvBaseWriter + hgrid + MV2 mvSphereMesh mvVsWriter mvCdmsRegrid + selectors + sliceut + tvariable + variable Indices and tables From d57b0005d013bd7fec7b2c6ec5c626cb2c143140 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 13 Oct 2016 16:22:58 -0700 Subject: [PATCH 005/239] revamp documentation --- Lib/avariable.py | 175 +++++++++++++++++++++------- Lib/axis.py | 260 +++++++++++++++++++++++++++++------------- Lib/bindex.py | 34 ++++-- Lib/cdmsobj.py | 143 +++++++++++++---------- docs/source/conf.py | 8 +- docs/source/index.rst | 5 +- 6 files changed, 429 insertions(+), 196 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index d5a66b65..a599c159 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -151,6 +151,21 @@ def __array__ (self, t=None, context=None): #Numeric, ufuncs call this def __call__ (self, *args, **kwargs): """ Selection of a subregion using selectors. + + Parameters + ---------- + raw: + if set to 1, return numpy.ma only + squeeze: + if set to 1, eliminate any dimension of length 1 + grid: + if given, result is regridded ont this grid. + order: + if given, result is permuted into this order + + Returns + ------- + Subregion selected """ # separate options from selector specs d = kwargs.copy() @@ -237,9 +252,19 @@ def _returnArray(self, ar, squeeze, singles=None): return result def generateGridkey(self, convention, vardict): - """ Determine if the variable is gridded, - and generate ((latname, lonname, order, maskname, class), lat, lon) if gridded, - or (None, None, None) if not gridded. vardict is the variable dictionary of the parent""" + """Determine if the variable is gridded. + + Parameters + ---------- + convention: + Metadata convention class + vardict: + Variable metedata + + Returns + ------- + ((latname, lonname, order, maskname, class), lat, lon) if gridded + (None, None, None) if not gridded """ lat, nlat = convention.getVarLatId(self, vardict) lon, nlon = convention.getVarLonId(self, vardict) @@ -305,9 +330,19 @@ def generateGridkey(self, convention, vardict): return None, lat, lon def generateRectGridkey(self, lat, lon): - """Determine if the variable is gridded, rectilinear, - and generate (latname, lonname, order, maskname, class) if gridded, - or None if not gridded""" + """Determine if the variable is gridded, rectilinear. + + Parameters + ---------- + lat: + latitude axis + lon: + longitude axis + + Returns + ------- + (latname, lonname, order, maskname, class) if gridded, + None if not gridded.""" ilat = ilon = -1 k = 0 @@ -346,7 +381,7 @@ def setGrid(self, grid): self._grid_ = grid def getDomain (self): - "Get the list of axes" + "Get the list of axes." raise CDMSError, "getDomain not overriden in child" def getConvention(self): @@ -359,15 +394,25 @@ def getConvention(self): # A child class may want to override this def getAxis(self, n): - "Get the n-th axis" - if n < 0: n = n + self.rank() - return self.getDomain()[n][0] + """Get the n-th axis. + Parameters + ---------- + n: + Axis number + Returns + ------- + if n < 0: n = n + self.rank() + self.getDomain()[n][0]""" def getAxisIndex (self, axis_spec): """Get the index of the axis specificed by axis_spec. - Return - ------ + Parameters + ---------- + axis_spec: + + Returns + ------- the axis index or -1 if no match is found. """ for i in range(self.rank()): @@ -379,6 +424,10 @@ def hasCellData(self): """ If any of the variable's axis has explicit bounds, we have cell data otherwise we have point data. + + Returns + ------- + True or False if axis has cell data. """ for axis in self.getAxisList(): if (axis.getExplicitBounds() is not None): @@ -415,7 +464,12 @@ def getAxisList(self, axes = None, omit=None, order=None): return axisMatchAxis (alist, axes, omit, order) def getAxisIds(self): - """Get a list of axis identifiers.""" + """Get a list of axis identifiers. + + Returns + ------- + array list of axis ids""" + return [x[0].id for x in self.getDomain()] # Return the grid @@ -426,9 +480,9 @@ def getMissing(self, asarray=0): """ Parameters ---------- - asarray : - '0' : scalar - '1' : numpy array + asarray : + '0' : scalar + '1' : numpy array Return ------ the missing value as a scalar, or as a numpy array if asarray==1""" @@ -455,8 +509,8 @@ def setMissing(self, value): Parameters ---------- - value - scalar, a single-valued numpy array, or None. + value + scalar, a single-valued numpy array, or None. Note ---- @@ -488,7 +542,12 @@ def setMissing(self, value): def getTime(self): - "Get the first time dimension, or `None` if not found" + """Get the first time dimension. + + Returns + ------- + First Time dimension axis or `None`. + """ for k in range(self.rank()): axis = self.getAxis(k) if axis.isTime(): @@ -498,7 +557,12 @@ def getTime(self): return None def getForecastTime(self): - "Get the first forecast time dimension, or `None` if not found" + """Get the first forecast time dimension. + + Returns + ------- + First forecast time dimension axis or `None`. + """ for k in range(self.rank()): axis = self.getAxis(k) if axis.isForecast(): @@ -510,8 +574,11 @@ def getForecast(self): return self.getForecastTime() def getLevel(self): - """Get the first vertical level dimension in the domain, - or `None` if not found. + """Get the first vertical level dimension in the domain. + + Returns + ------- + First vertical level dimension axis or `None`. """ for k in range(self.rank()): axis = self.getAxis(k) @@ -522,7 +589,12 @@ def getLevel(self): return None def getLatitude(self): - "Get the first latitude dimension, or `None` if not found." + """Get the first latitude dimension. + + Returns + ------- + First latitude dimension axis or `None`. + """ grid = self.getGrid() if grid is not None: result = grid.getLatitude() @@ -540,7 +612,14 @@ def getLatitude(self): return result def getLongitude(self): - "Get the first latitude dimension, or `None` if not found." + """Get the first longitude dimension. + + Returns + ------- + First longitude dimension axis or `None`. + + """ + grid = self.getGrid() if grid is not None: result = grid.getLongitude() @@ -560,6 +639,10 @@ def getLongitude(self): # Get an order string, such as "tzyx" def getOrder(self, ids=0): """ + parameters + ---------- + id: + 0 or 1 returns ------- the order string, such as t, z, y, x (time, level, lat, lon). @@ -686,20 +769,18 @@ def getSlice (self, *specs, **keys): Parameter --------- - squeeze : default 1 - Determines whether or not the shape - of the returned array contains dimensions whose length is 1, such - dimensions are 'squeezed out' by default. - numericSqueeze - - - raw - - order - - grid - - isitem + raw: + if set to 1, return numpy.ma only + squeeze: + if set to 1, eliminate any dimension of length 1 + grid: + if given, result is regridded ont this grid. + order: + if given, result is permuted into this order + numericSqueeze: + if index slice is given, eliminate that dimension. + isitem: + if given, result is return as a scaler for 0-D data Note @@ -1022,14 +1103,28 @@ def subRegion (self, *specs, **keys): return result.getSlice(squeeze=0, raw=1) def getValue(self, squeeze=1): - """Get the entire set of values.""" + """Get the entire set of values. + Returns + ------- + All values and elimite the 1-D dimension. + """ return self.getSlice(Ellipsis, squeeze=squeeze) def assignValue(self,data): raise CDMSError, NotImplemented + 'assignValue' def reorder (self, order): - """return self reordered per the specification order""" + """Reorder per the specification order. + + Parameters + ---------- + order: string + can be "tzyx" with all possible axes permutation. + + Returns + ------- + New reordered variable. + """ if order is None: return self axes = self.getAxisList() diff --git a/Lib/axis.py b/Lib/axis.py index cddee3da..c4492eaa 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -165,19 +165,25 @@ def mapLinearIntersection(xind,yind,iind, boundLeft,nodeSubI,boundRight): """ - Return true iff the coordinate interval (a,b) intersects the node - nodeSubI or cell bounds [boundLeft,boundRight], where the interval - (a,b) is defined by: + Parameters + ---------- + xind: + 'c' if (a,b) is closed on the left, 'o' if open, + yind: + same for right endpoint - xind = 'c' if (a,b) is closed on the left, 'o' if open, - yind same for right endpoint - aMinusEps,aPlusEps = a +/- epsilon - bPlusEps,bMinusEps = b +/- epsilon + Returns + ------- + True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: - and the intersection option iind = 'n','b','e','s' specifies - whether the intersection is with respect to the node value - nodeSubI ('n' or 'e') or the cell bounds [boundLeft,boundRight]. - See mapLinearExt. + * aMinusEps,aPlusEps = a +/- epsilon + * bPlusEps,bMinusEps = b +/- epsilon + + and the intersection option iind = 'n','b','e','s' specifies whether the intersection is with respect to the node value nodeSubI ('n' or 'e') or the cell bounds [boundLeft,boundRight]. + + See Also + -------- + mapLinearExt """ @@ -211,8 +217,8 @@ def mapLinearIntersection(xind,yind,iind, def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride=1, wrapped=0): """Map coordinate interval to index interval, without - wraparound. interval has the form (x,y) where x and y are the - endpoints in coordinate space. indicator is a three-character + wraparound. Interval has the form (x,y) where x and y are the + endpoints in coordinate space. Indicator is a three-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. The third character indicates @@ -223,9 +229,9 @@ def mapLinearExt(axis, bounds, interval, indicator ='ccn', epsilon=None, stride= 's' - the cell bounds are a subset of the interval 'e' - same as 'n', plus an extra node on either side. - Returns the corresponding index interval (i,j), where i ar[index], index==len(ar) - (b) ar is monotonically decreasing: - value >= ar[index], index==0..len(ar)-1 - value < ar[index], index==len(ar) + """Lookup value in array ar. + + Parameters + ---------- + ar: + Input array + value: + Value to search + Returns + ------- + index: + * ar is monotonically increasing. + * value <= ar[index], index==0..len(ar)-1 + * value > ar[index], index==len(ar) + * ar is monotonically decreasing: + * value >= ar[index], index==0..len(ar)-1 + * value < ar[index], index==len(ar) """ ar = numpy.ma.filled(ar) ascending = (ar[0]vec2[len(vec2)-1] + """ + Parameters + ---------- + vec1: + Input arrays to compare + vec2: + Input arrays to compare + atol: float, optional + Absolute tolerance, The absolute differenc is equal to **atol** Default is 1e-8 + + Returns + ------- + (isoverlap, index) : + where isoverlap is true if a leading portion of vec1 is a subset of vec2; + * index is the index such that vec1[0] <= vec2[index] + * If indexl == len(vec2), then vec1[0] > vec2[len(vec2) - 1] """ index = lookupArray(vec2,vec1[0]) if index==0 and abs(vec1[0]-vec2[0]): @@ -595,8 +623,32 @@ def isOverlapVector(vec1, vec2, atol=1.e-8): return (0,index) def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): - """True if all elements of axes ax1 and ax2 are close, - in the sense of numpy.ma.allclose.""" + """ + Paramerers + ---------- + ax1, ax2: array_like + + Returns + ------- + bool + True if all elements of axes ax1 and ax2 are close, + in the sense of numpy.ma.allclose. + + See Also + -------- + all, any + + Examples + -------- + >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) + >>> a + masked_array(data = [10000000000.0 1e-07 --], + mask = [False False True], + fill_value = 1e+20) + >>> b = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) + >>> ma.allclose(a, b) + False + """ return ((ax1 is ax2) or numpy.ma.allclose(ax1[:],ax2[:],rtol=rtol,atol=atol)) # AbstractAxis defines the common axis interface. @@ -1073,16 +1125,16 @@ def getModulo(self): def mapInterval(self,interval,indicator='ccn',cycle=None): """ - Map coordinate interval to index interval. interval has one of the forms: + Map coordinate interval to index interval. interval has one of the forms - (x,y) - (x,y,indicator): indicator overrides keywork argument - (x,y,indicator,cycle): indicator, cycle override keyword arguments - None: indicates the full interval + * `(x,y)` + * `(x,y,indicator)`: indicator overrides keywork argument + * `(x,y,indicator,cycle)`: indicator, cycle override keyword arguments + * `None`: indicates the full interval - where x and y are the endpoints in coordinate space. indicator is a - two-character string, where the first character is 'c' if the interval - is closed on the left, 'o' if open, and the second character has the + where `x` and `y` are the endpoints in coordinate space. indicator is a + two-character string, where the first character is `c` if the interval + is closed on the left, `o` if open, and the second character has the same meaning for the right-hand point. Set cycle to a nonzero value to force wraparound. @@ -1095,12 +1147,14 @@ def mapInterval(self,interval,indicator='ccn',cycle=None): (1) if j<=N, the interval does not wrap around the axis endpoint (2) if j>N, the interval wraps around, and is equivalent to the two consecutive intervals [i,N), [0,j-N) + For example, if the vector is [0,2,4,...,358] of length 180, and the coordinate interval is [-5,5), the return index interval is [178,183). This is equivalent to the two intervals [178,180) and [0,3). - Note: if the interval is interior to the axis, but does not span any - axis element, a singleton (i,i+1) indicating an adjacent index is returned. +.. note:: + if the interval is interior to the axis, but does not span any axis element, + a singleton (i,i+1) indicating an adjacent index is returned. """ i,j,k = self.mapIntervalExt(interval,indicator,cycle) j = min(j, i+len(self)) @@ -2144,47 +2198,61 @@ def isVirtual(self): ######## Functions for selecting axes def axisMatchAxis (axes, specifications=None, omit=None, order=None): - """Given a list of axes and a specification or list of + """Match a list of axes following a specification or list of specificatons, and a specification or list of specifications - of those axes to omit, return a list of - those axes in the list that match the specification but - do not include in the list any axes that matches an omit - specification. + of those axes to omit. + + Parameters + ---------- + specifications: + * is None, include all axes less the omitted ones. + + * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. - If specifications is None, include all axes less the omitted ones. + omit: + * is None, do not omit any axis. - Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. - Axes are returned in the order they occur in the axes argument unless - order is given. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. + + Return + ------ + A list of axes that match the specification omitting any axes that matches an omit specification. + + Axes are returned in the order they occur in the axes argument unless order is given. - order can be a string containing the symbols t,x,y,z, or -. - If a - is given, any elements of the result not chosen otherwise are - filled in from left to right with remaining candidates. """ return [axes[i] for i in \ axisMatchIndex(axes, specifications, omit, order)] def axisMatchIndex (axes, specifications=None, omit=None, order=None): - """Given a list of axes and a specification or list of + """Match a list of axes following a specification or list of specificatons, and a specification or list of specifications - of those axes to omit, return a list of the indices of - those axes in the list that match the specification but - do not include in the list any axes that matches an omit - specification. + of those axes to omit. + + Parameters + ---------- + specifications: + * is None, include all axes less the omitted ones. + + * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. + + omit: + * is None, do not omit any axis. - If specifications is None, include all axes less the omitted ones. + * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. - Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. - The indices of axes are returned in the order the axes - occur in the axes argument, unless order is given. + Return + ------ + A list of axis' indices which match the specification omitting any axes that matches an omit specification. + + Axes are returned in the order they occur in the axes argument unless order is given. - order can be a string containing the symbols t,x,y,z, or -. - If a - is given, any elements of the result not chosen otherwise are - filled in from left to right with remaining candidates. """ if specifications is None: speclist = axes @@ -2295,22 +2363,34 @@ def axisMatchIndex (axes, specifications=None, omit=None, order=None): def axisMatches(axis, specification): - """Return 1 or 0 depending on whether axis matches the specification. + """ + Parameters + ---------- + axis: + See note below + specifications: + See note below + + Returns + ------- + 1 or 0 depending on whether axis matches the specification. + + Note + ---- Specification must be one of: - 1. a string representing an axis id or one of - the keywords time, fctau0, latitude or lat, longitude or lon, or - lev or level. - axis may be surrounded with parentheses or spaces. + #. a string representing an axis id or one of the keywords time, fctau0, latitude or lat, longitude or lon, or lev or level. - We first attempt to match the axis id and the specification. - Keywords try to match using isTime, isLatitude, etc. - Comparisons to keywords and axis ids is case-insensitive. + #. Axis may be surrounded with parentheses or spaces. - 2. a function that takes an axis as an argument and returns a value. - if the value returned is true, the axis matches. + * We first attempt to match the axis id and the specification. + * Keywords try to match using isTime, isLatitude, etc. + * Comparisons to keywords and axis ids is case-insensitive. - 3. an axis object; will match if it is the same object as axis. + #. a function that takes an axis as an argument and returns a value. + * if the value returned is true, the axis matches. + + #. an axis object; will match if it is the same object as axis. """ if isinstance(specification, basestring): s = string.lower(specification) @@ -2348,7 +2428,20 @@ def axisMatches(axis, specification): + str(type(specification)) + ', ' + str(specification) def concatenate(axes, id=None, attributes=None): - """Concatenate the axes, return a transient axis.""" + """Concatenate multiple axes including boundaries. + + Parameters + ---------- + axes: + Axes to concatenate + id: + New axis identification (default None) + attributes: + Attributes to attached to the new Axis + + Returns + ------- + Transient axis.""" data = numpy.ma.concatenate([ax[:] for ax in axes]) boundsArray = [ax.getBounds() for ax in axes] @@ -2359,7 +2452,18 @@ def concatenate(axes, id=None, attributes=None): return TransientAxis(data, bounds=bounds, id=id, attributes=attributes) def take(ax, indices): - """Take values indicated by indices list, return a transient axis.""" + """Take elements form an array along an axis + Parameters + ---------- + ax: + The source array. + indices: + The indices of the values to extract. + Returns + ------- + axis: TransientAxis + The return array has the same type of ax. + """ # Bug in ma compatibility module data = numpy.ma.take(ax[:], indices) diff --git a/Lib/bindex.py b/Lib/bindex.py index 9156c970..88557b3a 100644 --- a/Lib/bindex.py +++ b/Lib/bindex.py @@ -7,10 +7,17 @@ def bindexHorizontalGrid(latlin, lonlin): """Create a bin index for a horizontal grid. - 'latlin' is the raveled latitude values. - 'lonlin' is the raveled longitude values. - Returns the index. + Parameters + ---------- + latlin: + latlin is the raveled latitude values. + latlon: + lonlin is the raveled longitude values. + + Returns + ------- + resulting index. """ lonlin = numpy.mod(lonlin,360) NI,NJ = _bindex.getLens() @@ -23,13 +30,22 @@ def bindexHorizontalGrid(latlin, lonlin): def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): """Intersect a horizontal grid with a lat-lon region. - 'latspecs' and 'lonspecs' are the latitude/longitude specs - as defined in the grid module. - 'latlin' and 'lonlin' are the raveled latitude/longitude arrays. - 'index' is the bin index as returned from bindex. + Parameters + ---------- + latspecs: + latitude specs as defined in the grid module. + lonspecs: + longitude specs as defined in the grid module. + latlin: + latlin is the raveled latitude array. + lonlin: + lonlin is the raveled longitude array. + index: + index is the bin index as returned from bindex. - Returns an array of indices, in latlin/lonlin, of the points in - the intersection. + Returns + ------- + an array of indices, in latlin/lonlin, of the points in the intersection. """ points = numpy.zeros(len(latlin),dtype='l') if latspecs is None: diff --git a/Lib/cdmsobj.py b/Lib/cdmsobj.py index 14c2d9bf..7ac472fd 100644 --- a/Lib/cdmsobj.py +++ b/Lib/cdmsobj.py @@ -503,18 +503,21 @@ def __init__(self, node = None): def searchone(self, pattern, attname): - """Return true if the attribute with name attname is a string - attribute which contains the compiled regular expression pattern, or - if attname is None and pattern matches at least one string - attribute. Return false if the attribute is not found or is not - a string. - ::: - Input::: - pattern :: (str) (0) pattern - attname :: (str/None) (1) attribute name - ::: - Output::: - result :: (int/True/False) (0) True if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute, False if the attribute is not found or is not a string + """Search if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or + if attname is None and pattern matches at least one string attribute. + + Parameters + ---------- + pattern: + (str) pattern + attname: + (str/None) attribute name + + Returns + ------- + result: (int/True/False) + * 1 or True if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute, + * 0 or False if the attribute is not found or is not a string ::: """ if attname is None: @@ -534,18 +537,19 @@ def searchone(self, pattern, attname): # attribute. Return false if the attribute is not found or is not a string def matchone(self, pattern, attname): """ - Return true if the attribute with name attname is a string - attribute which matches the compiled regular expression pattern, or - if attname is None and pattern matches at least one string - attribute. Return false if the attribute is not found or is not a string - ::: - Input::: - pattern :: (str) (0) pattern - attname :: (str/None) (1) attribute name - ::: - Output::: - result :: (int/True/False) (0) True if the attribute with name attname is a string attribute which matches the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute, False if the attribute is not found or is not a string - ::: + Search if the attribute with name attname is a string attribute which matches the compiled regular expression pattern, or + if attname is None and pattern matches at least one string attribute. + + Parameters + ---------- + pattern: (str) pattern + attname: (str/None) attribute name + + Returns + ------- + result: (int/True/False) + * True if the attribute with name attname is a string attribute which matches the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute. + * False if the attribute is not found or is not a string. """ if attname is None: for attval in self.attributes.values(): @@ -563,15 +567,21 @@ def matchone(self, pattern, attname): def searchPattern(self,pattern,attribute,tag): """ Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. - ::: - Input::: - pattern :: (str) (0) pattern - attribute :: (str/None) (1) attribute name - tag :: (str/None) (2) node tag - ::: - Output::: - result :: (list) (0) - ::: + + Parameters + ---------- + pattern: (str) + + attribute: (str/None) + attribute name + + tag: (str/None) + node tag + + Returns + ------- + result: (list) + """ if tag is None or string.lower(tag)==self._node_.tag: if self.searchone(pattern,attribute): @@ -586,15 +596,19 @@ def searchPattern(self,pattern,attribute,tag): def matchPattern(self,pattern,attribute,tag): """ Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. - ::: - Input::: - pattern :: (str) (0) pattern - attribute :: (str/None) (1) attribute name - tag :: (str/None) (2) node tag - ::: - Output::: - result :: (list) (0) - ::: + + Parameters + ---------- + pattern: (str) + pattern + attribute: (str/None) + attribute name + tag: (str/None) + node tag + Results + ------- + result: (list) + """ if tag is None or string.lower(tag)==self._node_.tag: if self.matchone(pattern,attribute): @@ -609,15 +623,17 @@ def matchPattern(self,pattern,attribute,tag): # If the predicate returns false, return an empty list def searchPredicate(self,predicate,tag): """ - Apply a truth-valued predicate. Return a list containing a single instance: [self] if the predicate is true and either tag is None or matches the object node tag. If the predicate returns false, return an empty list - ::: - Input::: - predicate :: (function) (0) predicate - tag :: (str/None) (1) node tag - ::: - Output::: - result :: (list) (0) - ::: + Apply a truth-valued predicate. + + Parameters + ---------- + predicate: (function) + tag: (str/None) + node tag + Returns + ------- + result: (list) + * Return a list containing a single instance: [self] if the predicate is true and either tag is None or matches the object node tag. If the predicate returns false, return an empty list """ if tag is None or string.lower(tag)==self._node_.tag: try: @@ -631,17 +647,22 @@ def searchPredicate(self,predicate,tag): def dump(self,path=None,format=1): """ dump(self,path=None,format=1) + Dump an XML representation of this object to a file. - 'path' is the result file name, None for standard output. - 'format'==1 if the file is formatted with newlines for readability - ::: - Input::: - path :: (None) (0) result file name, None for standard output - format :: (int) (1) 1 if the file is formatted with newlines for readability - ::: - Output::: - None :: (None) (0) nothing returned - ::: + `path` is the result file name, None for standard output. + `format`==1 if the file is formatted with newlines for readability + + Parameters + ---------- + path: (None) + result file name, None for standard output. + format: (int) + 1 if the file is formatted with newlines for readability. + + Returns + ------- + None: (None) + nothing returned """ if self._node_ is None: raise CDMSError, "No tree node found" diff --git a/docs/source/conf.py b/docs/source/conf.py index 8338e6f2..f91bc093 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -44,12 +44,12 @@ napoleon_numpy_docstring = True napoleon_include_private_with_doc = False napoleon_include_special_with_doc = True -napoleon_use_admonition_for_examples = False -napoleon_use_admonition_for_notes = False -napoleon_use_admonition_for_references = False +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True napoleon_use_ivar = False napoleon_use_param = True -napoleon_use_rtype = True +napoleon_use_rtype = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/index.rst b/docs/source/index.rst index 1d7e6535..a0cd1856 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,14 +9,13 @@ Welcome to cdms2's documentation! Contents: .. toctree:: + AbstractAxis AbstractVariable avariable - auxcoord axis bindex cache cdmsobj - convention database dataset fvariable @@ -28,12 +27,10 @@ Contents: hgrid MV2 mvSphereMesh - mvVsWriter mvCdmsRegrid selectors sliceut tvariable - variable Indices and tables From b1d1a77b6c9f9c73d845e4da3b1bf4d1a7f1f5c8 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Fri, 14 Oct 2016 16:50:39 -0700 Subject: [PATCH 006/239] Fixing cdms documentation (docstrings) --- .gitignore | 1 + Lib/dataset.py | 739 ++++++++++++++++++++++------------- docs/source/AbstractAxis.rst | 8 + docs/source/cdmsfile.rst | 8 + docs/source/conf.py | 6 +- docs/source/index.rst | 1 + 6 files changed, 489 insertions(+), 274 deletions(-) create mode 100644 docs/source/AbstractAxis.rst create mode 100644 docs/source/cdmsfile.rst diff --git a/.gitignore b/.gitignore index 8a1cb485..3e707781 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ build/ /test-results Makefile checked_get.sh +git.py diff --git a/Lib/dataset.py b/Lib/dataset.py index 977b1d8b..a3c9eedf 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -83,13 +83,16 @@ class DuplicateAxisError(CDMSError): _showCompressWarnings = True def setCompressionWarnings(value=None): - """Turn on/off the warnings for compression - Usage: - setCompressionWarning(value) - Where: - value is 0/1 False/True 'no'/'yes' or None (which sets it to the opposite - Returns: - the value it has been set to + """Turn on/off the warnings for compression. + + Parameters + ---------- + value: + * 0/1 False/True 'no'/'yes' or None (which sets it to the opposite + + Returns + ------- + Return set value. """ global _showCompressWarnings if value is None: @@ -114,7 +117,16 @@ def setCompressionWarnings(value=None): return _showCompressWarnings def setNetcdfUseNCSwitchModeFlag(value): - """ Tells cdms2 to switch constantly between netcdf define/write modes""" + """Tells cdms2 to switch constantly between netcdf define/write modes. + Parameters + ---------- + value: + 0/1, False/True. + + Returns + ------- + No return value. + """ if value not in [True,False,0,1]: raise CDMSError("Error UseNCSwitchMode flag must be 1(can use)/0(do not use) or true/False") @@ -124,7 +136,17 @@ def setNetcdfUseNCSwitchModeFlag(value): Cdunif.CdunifSetNCFLAGS("use_define_mode",1) def setNetcdfUseParallelFlag(value): - """ Sets NetCDF classic flag value""" + """Enable/Disable NetCDF MPI I/O (Paralllelism). + + Parameters + ---------- + value: + 0/1, False/True. + + Returns + ------- + No return value. + """ global CdMpi if value not in [True,False,0,1]: raise CDMSError("Error UseParallel flag must be 1(can use)/0(do not use) or true/False") @@ -138,7 +160,12 @@ def setNetcdfUseParallelFlag(value): rk = MPI.COMM_WORLD.Get_rank() def getMpiRank(): - ''' Return number of processor available ''' + """ Return number of processor available. + + Returns + ------- + rank or 0 if MPI is not enabled. + """ if CdMpi: rk = MPI.COMM_WORLD.Get_rank() return rk @@ -146,6 +173,12 @@ def getMpiRank(): return 0 def getMpiSize(): + """Return MPI size. + + Returns + ------- + MPI size or 0 if MPI is not enabled. + """ if CdMpi: sz = MPI.COMM_WORLD.Get_size() return sz @@ -153,7 +186,17 @@ def getMpiSize(): return 1 def setNetcdf4Flag(value): - """ Sets NetCDF classic flag value""" + """Enable netCDF4 (HDF5) mode in libnetcdf. + + Parameters + ---------- + value: + 0/1, False/True. + + Returns + ------- + No return value. + """ if value not in [True,False,0,1]: raise CDMSError("Error NetCDF4 flag must be 1/0 or true/False") if value in [0,False]: @@ -162,7 +205,17 @@ def setNetcdf4Flag(value): Cdunif.CdunifSetNCFLAGS("netcdf4",1) def setNetcdfClassicFlag(value): - """ Sets NetCDF classic flag value""" + """Enable netCDF3 (classic) mode in libnetcdf. + + Parameters + ---------- + value: + 0/1, False/True. + + Returns + ------- + No return value. + """ if value not in [True,False,0,1]: raise CDMSError("Error NetCDF Classic flag must be 1/0 or true/False") if value in [0,False]: @@ -171,7 +224,16 @@ def setNetcdfClassicFlag(value): Cdunif.CdunifSetNCFLAGS("classic",1) def setNetcdfShuffleFlag(value): - """ Sets NetCDF shuffle flag value""" + """Enable/Disable NetCDF shuffle. + + Parameters + ---------- + value: + 0/1, False/True. + Returns + ------- + No return value. + """ if value not in [True,False,0,1]: raise CDMSError("Error NetCDF Shuffle flag must be 1/0 or true/False") if value in [0,False]: @@ -180,7 +242,16 @@ def setNetcdfShuffleFlag(value): Cdunif.CdunifSetNCFLAGS("shuffle",1) def setNetcdfDeflateFlag(value): - """ Sets NetCDF deflate flag value""" + """Enable/Disable NetCDF deflattion. + + Parameters + ---------- + value: + 0/1, False/True. + Returns + ------- + No return value. + """ if value not in [True,False,0,1]: raise CDMSError("Error NetCDF deflate flag must be 1/0 or true/False") if value in [0,False]: @@ -189,41 +260,78 @@ def setNetcdfDeflateFlag(value): Cdunif.CdunifSetNCFLAGS("deflate",1) def setNetcdfDeflateLevelFlag(value): - """ Sets NetCDF deflate level flag value""" + """Sets NetCDF deflate level flag value + + Parameters + ---------- + value: + Deflation Level 1-9. + + Returns + ------- + No return value. + """ if value not in [0,1,2,3,4,5,6,7,8,9]: raise CDMSError("Error NetCDF deflate_level flag must be an integer < 10") Cdunif.CdunifSetNCFLAGS("deflate_level",value) def getNetcdfUseNCSwitchModeFlag(): - """ Returns NetCDF UseParallel flag value""" + """Get current netCDF define mode. + + Returns + ------- + NetCDF define mode . + """ return Cdunif.CdunifGetNCFLAGS("use_define_mode") def getNetcdfUseParallelFlag(): - """ Returns NetCDF UseParallel flag value""" + """Get NetCDF UseParallel flag value. + + Parameters + ---------- + value: + 0/1, False/True. + Returns + ------- + No return value. + """ return Cdunif.CdunifGetNCFLAGS("use_parallel") def getNetcdf4Flag(): - """ Returns NetCDF4 flag value""" + """Returns + ------- + NetCDF4 flag value.""" return Cdunif.CdunifGetNCFLAGS("netcdf4") def getNetcdfClassicFlag(): - """ Returns NetCDF classic flag value""" + """Returns + ------- + NetCDF classic flag value.""" return Cdunif.CdunifGetNCFLAGS("classic") def getNetcdfShuffleFlag(): - """ Returns NetCDF shuffle flag value""" + """Returns + ------- + NetCDF shuffle flag value.""" return Cdunif.CdunifGetNCFLAGS("shuffle") def getNetcdfDeflateFlag(): - """ Returns NetCDF deflate flag value""" + """Returns + ------- + NetCDF deflate flag value. """ return Cdunif.CdunifGetNCFLAGS("deflate") def getNetcdfDeflateLevelFlag(): - """ Returns NetCDF deflate level flag value""" + """Returns + ------- + NetCDF deflate level flag value.""" return Cdunif.CdunifGetNCFLAGS("deflate_level") def useNetcdf3(): - """ Turns off (0) NetCDF flags for shuffle/defalte/defaltelevel + """Turns off (0) NetCDF flags for shuffle/defalte/defaltelevel Output files are generated as NetCDF3 Classic after that + Returns + ------- + No return value. """ setNetcdfShuffleFlag(0) setNetcdfDeflateFlag(0) @@ -259,6 +367,19 @@ def loadURI(uri): # 'path' is the XML file name, or netCDF filename for simple file create # 'template' is a string template for the datafile(s), for dataset creation def createDataset(path,template=None): + """Create a dataset. + + Parameters + ---------- + path: + is the XML file name, or netCDF filename for simple file creation. + template: + is a string template for the datafile(s), for dataset creation. + + Returns + ------- + writing file handle. + """ return openDataset(path,'w',template) # Open an existing dataset @@ -267,18 +388,21 @@ def createDataset(path,template=None): # 'mode' is 'r', 'r+', 'a', or 'w' def openDataset(uri,mode='r',template=None,dods=1,dpath=None, hostObj=None): """ - Options::: -mode :: (str) ('r') mode to open the file in read/write/append -template :: (NoneType) (None) ??? -dods :: (int) (1) ??? -dpath :: (NoneType/str) (None) ??? -::: -Input::: -uri :: (str) (0) file to open -::: -Output::: -file :: (cdms2.dataset.CdmsFile) (0) file to read from -::: + Parameters + ---------- + uri: (str) + Filename to open + mode: (str) + Either `r`,`w`,`a` mode to open the file in read/write/append + template: + A string template for the datafile(s), for dataset creation + dods: (int) + Default set to 1 + dpath: (str) + Destination path. + Returns + ------- + file handle. """ uri = string.strip(uri) (scheme,netloc,path,parameters,query,fragment)=urlparse.urlparse(uri) @@ -374,7 +498,17 @@ def openDataset(uri,mode='r',template=None,dods=1,dpath=None, hostObj=None): # Functions for parsing the file map. def parselist(text, f): """Parse a string of the form [A, A, ...]. - f is a function which parses A and returns (A, nconsumed) + + Parameters + ---------- + text: + Input String. + f: + function which parses A and returns (A, nconsumed). + Returns + ------- + Parser results. + n number of matches. """ n = 0 @@ -402,9 +536,17 @@ def parselist(text, f): return result, n def parseIndexList(text): - """Parse a string of the form [i,j,k,l,...,path] where - i,j,k,l,... are indices or '-', and path is a filename. - Coerce the indices to integers, return (result, nconsumed). + """Parse a string of the form [i,j,k,l,...,path]. + + Parameters + ---------- + text: + i,j,k,l,... are indices or '-', and path is a filename. + Coerce the indices to integers. + Returns + ------- + Parser results. + n number of matches. """ m = _IndexList4.match(text) nindices = 4 @@ -452,12 +594,24 @@ def parseVarMap(text): return result, n def parseFileMap(text): - """Parse a CDMS filemap. having the form: - filemap :== [ varmap, varmap, ...] - varmap :== [ namelist, slicelist ] - namelist :== [name, name, ...] - slicelist :== [indexlist, indexlist, ,,,] - indexlist :== [i,j,k,l,path] + """Parse a CDMS filemap. + + Parameters + ---------- + filemap: + list [ varmap, varmap, ...] + varmap: + list [ namelist, slicelist ] + namelist: + list [name, name, ...] + slicelist: + list [indexlist, indexlist, ,,,] + indexlist: + list [i,j,k,l,path] + + Returns + ------- + Parsing results. """ result, n = parselist(text, parseVarMap) if n is the string name of the axis. - is the integer length of the axis. - Note: for netCDF output, this just creates a dimension without + Parameters + ---------- + name: + is the string name of the axis. + axislen: + is the integer length of the axis. + + Returns + ------- + axis: + file axis whose id is name (cdms2.axis.FileVirtualAxis) + + Note + ---- + For netCDF output, this just creates a dimension without the associated coordinate array. On reads the axis will look like an axis of type float with values [0.0, 1.0, ..., float(axislen-1)]. On write attempts an exception is raised. - ::: - Input::: - name :: (str) (0) dimension name - axislen :: (int) (1) - ::: - Output::: - axis :: (cdms2.axis.FileVirtualAxis) (0) file axis whose id is name - ::: """ if self._status_=="closed": raise CDMSError(FileWasClosed + self.id) @@ -1291,21 +1444,24 @@ def createVirtualAxis(self, name, axislen): # Copy axis description and data from another axis def copyAxis(self, axis, newname=None, unlimited=0, index=None, extbounds=None): - """ - Copy axis description and data from another axis - ::: - Options::: - newname :: (None/str) (None) new name for axis - unlimited :: (int/True/False) (0) unlimited dimension ? - index :: (int/None) (None) :: index - extbounds :: (None/numpy.ndarray) (None) :: new bounds to use bounds - ::: - Input::: - axis :: (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) (0) axis to copy - ::: - Output::: - axis :: (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) (0) copy of input axis - ::: + """Copy axis description and data from another axis. + + Parameters + ---------- + axis: + axis to copy (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) + newname: (None/str) + new name for axis (default None) + unlimited: (int/True/False) + unlimited dimension (default 0) + index: (int/None) + (default None) + extbounds: (numpy.ndarray) + new bounds to use bounds (default None) + + Returns + -------- + copy of input axis (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) """ if newname is None: newname=axis.id @@ -1356,21 +1512,28 @@ def copyAxis(self, axis, newname=None, unlimited=0, index=None, extbounds=None): # order and type are strings def createRectGrid(self, id, lat, lon, order, type="generic", mask=None): """ - Create an implicit rectilinear grid. lat, lon, and mask are objects. order and type are strings - ::: - Options::: - type :: (str) ('generic') grid type - mask :: (None/numpy.ndarray) (None) mask - ::: - Input::: - id :: (str) (0) grid name - lat :: (numpy.ndarray) (1) latitude array - lon :: (numpy.ndarray) (2) longitude array - order :: (str) (3) order - ::: - Output::: - grid :: (cdms2.grid.FileRectGrid) (0) file grid - ::: + Create an implicit rectilinear grid. lat, lon, and mask are objects. order and type are strings. + + + Parameters + ---------- + id: (str) + grid name (default 0) + lat: (numpy.ndarray) + latitude array (default 1) + lon: (numpy.ndarray) + longitude array (default 2) + order: (str) + order (default 3) + type: (str) + grid type (defalut `generic`) + mask: (None/numpy.ndarray) + mask (default None) + + Returns + ------- + grid (cdms2.grid.FileRectGrid) + """ grid = FileRectGrid(self, id, lat, lon, order, type, mask) self.grids[grid.id] = grid @@ -1381,17 +1544,19 @@ def createRectGrid(self, id, lat, lon, order, type="generic", mask=None): # Copy grid def copyGrid(self, grid, newname=None): """ - Create an implicit rectilinear grid. lat, lon, and mask are objects. order and type are strings - ::: - Options::: - newname :: (str/None) (None) new name for grid - ::: - Input::: - grid :: (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) (0) file grid - ::: - Output::: - grid :: (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) (0) file grid - ::: + Create an implicit rectilinear grid. lat, lon, and mask are objects. Order and type are strings. + + Parameters + ---------- + newname: (str/None) + new name for grid (default None) + grid: + file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + + Returns + ------- + file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + """ if newname is None: if hasattr(grid,'id'): @@ -1439,23 +1604,26 @@ def copyGrid(self, grid, newname=None): # Return a variable object. def createVariable(self,name,datatype,axesOrGrids,fill_value=None): """ - Create a variable - 'name' is the string name of the Variable - 'datatype' is a CDMS datatype or numpy typecode - 'axesOrGrids' is a list of axes, grids. (Note: this should be generalized to allow subintervals of axes and/or grids) - Return a variable object. - ::: - Options::: - fill_value :: (int/float/None) (None) fill_value - ::: - Input::: - name :: (str) (0) file variable name - datatype :: (str/type) (1) file variable type - axesOrGrids :: ([cdms2.axis.FileAxis]/[cdms2.grid.FileRectGrid]) (2) list of FileAxis or FileRectGrid - ::: - Output::: - axis :: (cdms2.fvariable.FileVariable) (0) file variable - ::: + Create a variable. + + Parameters + ---------- + name: + The string name of the Variable + datatype: + A CDMS datatype or numpy typecode + axesOrGrids: + is a list of axes, grids. + fill_value: + fill_value (cast into data type). + + Note + ---- + This should be generalized to allow subintervals of axes and/or grids). + + Returns + ------- + Return a variable object (cdms2.fvariable.FileVariable). """ if self._status_=="closed": raise CDMSError(FileWasClosed + self.id) @@ -1536,15 +1704,19 @@ def createVariable(self,name,datatype,axesOrGrids,fill_value=None): def searchPattern(self,pattern,attribute,tag): """ Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. - ::: - Input::: - pattern :: (str) (0) pattern - attribute :: (str/None) (1) attribute name - tag :: (str/None) (2) node tag - ::: - Output::: - result :: (list) (0) - ::: + + Parameters + ---------- + pattern: + expression pattern + attribute: + attribute name + tag: + node tag + + Returns + ------- + list of match pattern """ resultlist = [] if tag is not None: @@ -1573,15 +1745,19 @@ def searchPattern(self,pattern,attribute,tag): def matchPattern(self,pattern,attribute,tag): """ Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. - ::: - Input::: - pattern :: (str) (0) pattern - attribute :: (str/None) (1) attribute name - tag :: (str/None) (2) node tag - ::: - Output::: - result :: (list) (0) - ::: + + Parameters + ---------- + pattern: + String expression. + attribute: + Attribute Name. If `None` search all attributre. + tag: + node tag, if `cdmsFile` only match the current dataset otherwise match all object matching the tag. + + Returns + ------- + list of match patterns. """ resultlist = [] if tag is not None: @@ -1612,15 +1788,21 @@ def matchPattern(self,pattern,attribute,tag): # the dataset itself. def searchPredicate(self,predicate,tag): """ - Apply a truth-valued predicate. Return a list containing a single instance: [self] if the predicate is true and either tag is None or matches the object node tag. If the predicate returns false, return an empty list - ::: - Input::: - predicate :: (function) (0) predicate - tag :: (str/None) (1) node tag - ::: - Output::: - result :: (list) (0) - ::: + Apply a truth-valued predicate. + + Parameters + ---------- + predicate: + function use as predicate + tag: + node tag. + + Returns + ------- + List containing a single instance + [self] if the predicate is true and either tag is None or matches the object node tag. + + Empty list If the predicate returns false. """ resultlist = [] if tag is not None: @@ -1652,37 +1834,36 @@ def searchPredicate(self,predicate,tag): def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds=None, extend=0, fill_value=None, index=None, newname=None, grid=None): """Define a new variable, with the same axes and attributes as in . - This does not copy the data itself. - Keywords: - attributes: A dictionary of attributes. Default is var.attributes. - axes: The list of axis objects. Default is var.getAxisList() - extbounds: Bounds of the (portion of) the extended dimension being written. - id or newname: String identifier of the new variable. - extend: If 1, define the first dimension as the unlimited dimension. If 0, do not define - an unlimited dimension. The default is the define the first dimension as unlimited - only if it is a time dimension. - - fill_value is the missing value flag. - - index is the extended dimension index to write to. The default index is determined - by lookup relative to the existing extended dimension. - grid is the variable grid. If none, the value of var.getGrid() is used. - ::: - Input::: - var :: (cdms2.tvariable.TransientVariable/cdms2.fvariable.FileVariable) (0) variable to copy - ::: - Options::: - id :: (str/None) (None) id of copied variable - attributes :: (None/dict) (None) use these attributes instead of the original var ones - axes :: (None/[cdms2.axis.AbstractAxis]) (None) list of axes to use for the copied variable - extbounds :: (None/numpy.ndarray) (None) Bounds of the (portion of) the extended dimension being written - extend :: (int) (0) If 1, define the first dimension as the unlimited dimension. If 0, do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. - fill_value :: (None/float) (None) the missing value flag - index :: (None/int) the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension - newname :: (str/None) id/newname of new variable - grid :: (None/cdms2.grid.AbstractGrid) grid to use - ::: - Output::: - variable :: (cdms2.fvariable.FileVariable) (0) file variable - ::: + + Note + ---- + This function does not copy the data itself. + + Parameters + ---------- + var: + variable to copy (cdms2.tvariable.TransientVariable or cdms2.fvariable.FileVariable) + attributes: + A dictionary of attributes. Default is var.attributes. + axes: + The list of axis objects. Default is var.getAxisList() + extbounds: + Bounds of the (portion of) the extended dimension being written. + id or newname: + String identifier of the new variable. + extend: + * 1 define the first dimension as the unlimited dimension. + * 0 do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. + fill_value: + The missing value flag. + index: + The extended dimension index for writting. The default index is determined by lookup relative to the existing extended dimension. + grid: + Tthe variable grid. `none` the value of var.getGrid() will used. + + Returns + ------- + file variable (cdms2.fvariable.FileVariable) """ if newname is None: newname=var.id @@ -1787,43 +1968,39 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds def write(self, var, attributes=None, axes=None, extbounds=None, id=None, \ extend=None, fill_value=None, index=None, typecode=None, dtype=None, pack=False): - """Write var to the file. If the variable is not yet defined in the file, - a definition is created. By default, the time dimension of the variable is defined as the - 'extended dimension' of the file. The function returns the corresponding file variable. - - Keywords: - - attributes is the attribute dictionary for the variable. The default is var.attributes. - - axes is the list of file axes comprising the domain of the variable. The default is to - copy var.getAxisList(). - - extbounds is the extended dimension bounds. Defaults to var.getAxis(0).getBounds() - - id is the variable name in the file. Default is var.id. - - extend=1 causes the first dimension to be 'extensible': iteratively writeable. - The default is None, in which case the first dimension is extensible if it is time. - Set to 0 to turn off this behaviour. - - fill_value is the missing value flag. - - index is the extended dimension index to write to. The default index is determined - by lookup relative to the existing extended dimension. - - dtype is the numpy dtype - - typecode is deprecated, for backward compatibility only - ::: - Input::: - var :: (cdms2.tvariable.TransientVariable/cdms2.fvariable.FileVariable) (0) variable to copy - ::: - Options::: - attributes :: (None/dict) (None) use these attributes instead of the original var ones - axes :: (None/[cdms2.axis.AbstractAxis]) (None) list of axes to use for the copied variable - extbounds :: (None/numpy.ndarray) (None) Bounds of the (portion of) the extended dimension being written - id :: (str/None) (None) id of copied variable - extend :: (int) (0) If 1, define the first dimension as the unlimited dimension. If 0, do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. - fill_value :: (None/float) (None) the missing value flag - index :: (None/int) the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension - typecode :: (None/str) (None) typdecode to write the variable as - dtype :: (None/numpy.dtype) type to write the variable as; overwrites typecode - pack :: (False/True/numpy/numpy.int8/numpy.int16/numpy.int32/numpy.int64) pack the data to save up space - ::: - Output::: - variable :: (cdms2.fvariable.FileVariable) (0) file variable - ::: + """Write var to the file. + + Note + ---- + If the variable is not yet defined in the file, a definition is created. + By default, the time dimension of the variable is defined as the + `extended dimension` of the file. The function returns the corresponding file variable. + + Parameters + ---------- + var: + variable to copy. + attributes: + The attribute dictionary for the variable. The default is var.attributes. + axes: + The list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). + extbounds: + The extended dimension bounds. Defaults to var.getAxis(0).getBounds(). + id: + The variable name in the file. Default is var.id. + extend: + * 1 causes the first dimension to be `extensible` iteratively writeable. The default is None, in which case the first dimension is extensible if it is time. + * 0 to turn off this behaviour. + fill_value: is the missing value flag. + index: + The extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. + dtype: + The numpy dtype. + typecode: + Deprecated, for backward compatibility only + Returns + ------- + File variable """ if _showCompressWarnings: if (Cdunif.CdunifGetNCFLAGS("shuffle")!=0) or (Cdunif.CdunifGetNCFLAGS("deflate")!=0) or (Cdunif.CdunifGetNCFLAGS("deflate_level")!=0): @@ -1927,10 +2104,21 @@ def write(self, var, attributes=None, axes=None, extbounds=None, id=None, \ def write_it_yourself( self, obj ): """Tell obj to write itself to self (already open for writing), using its - writeg method (AbstractCurveGrid has such a method, for example). If no - such method be available, writeToFile will be used. If that is not - available, then self.write(obj) will be called to try to write obj as - a variable.""" + writeg method (AbstractCurveGrid has such a method, for example). + + Note + ---- + If `writeg` is not available, writeToFile will be used. + If `writeToFile` is also not available, then `self.write(obj)` will be called to try to write obj as + a variable. + + Parameters + ---------- + obj: + object containing `writeg`, `writeToFile` or `write` method. + Returns + ------- + Nothig is returned. """ # This method was formerly called writeg and just wrote an AbstractCurveGrid. if ( hasattr(obj,'writeg') and callable(getattr(obj,'writeg')) ): obj.writeg( self ) @@ -1942,26 +2130,30 @@ def write_it_yourself( self, obj ): def getVariable(self, id): """ Get the variable object with the given id. Returns None if not found. - ::: - Input::: - id :: (str) (0) id of the variable to get - ::: - Output::: - variable :: (cdms2.fvariable.FileVariable/None) (0) file variable - ::: + + Parameters + ---------- + id: str + id of the variable to get + + Returns + ------- + variable (cdms2.fvariable.FileVariable/None) + file variable + """ return self.variables.get(id) def getVariables(self, spatial=0): - """Get a list of variable objects. If spatial=1, only return those - axes defined on latitude or longitude, excluding weights and bounds. - ::: - Options::: - spatial :: (int/True/False) (0) If spatial=1, only return those axes defined on latitude or longitude, excluding weights and bounds - ::: - Output::: - variables :: ([cdms2.fvariable.FileVariable]) (0) file variables - ::: + """Get a list of variable objects. + Parameters + ---------- + spatial: + If spatial=1 or True, only return those axes defined on latitude or longitude, excluding weights and bounds + + Returns + ------- + file variable. """ retval = self.variables.values() if spatial: @@ -1970,38 +2162,43 @@ def getVariables(self, spatial=0): def getAxis(self, id): """Get the axis object with the given id. Returns None if not found. - ::: - Input::: - id :: (str) (0) id of the axis to get - ::: - Output::: - axis :: (cdms2.axis.FileAxis/None) (0) file axis - ::: + + Parameters + ---------- + id: + id of the axis to get + Returns + -------- + file axis """ return self.axes.get(id) def getGrid(self, id): """ Get the grid object with the given id. Returns None if not found. - ::: - Input::: - id :: (str) (0) id of the grid to get - ::: - Output::: - grid :: (cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid/cdms2.grid.FileRectGrid/None) (0) file axis - ::: + + Parameters + ---------- + id: + id of the grid to get + + Returns + ------- + file axis """ return self.grids.get(id) def getBoundsAxis(self, n,boundid=None): """Get a bounds axis of length n. Create the bounds axis if necessary. - ::: - Input::: - n :: (int) (0) ? - ::: - Output::: - axis :: (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) (0) bound axis - ::: + + Parameters + ---------- + n: + bound id (bound_%d) + + Returns + ------- + bounds axis """ if boundid is None: if n==2: diff --git a/docs/source/AbstractAxis.rst b/docs/source/AbstractAxis.rst new file mode 100644 index 00000000..3d6314d6 --- /dev/null +++ b/docs/source/AbstractAxis.rst @@ -0,0 +1,8 @@ +AbstractAxis +============ + +.. py:currentmodule:: cdms2.axis + +.. autoclass:: AbstractAxis + :members: + diff --git a/docs/source/cdmsfile.rst b/docs/source/cdmsfile.rst new file mode 100644 index 00000000..b4882112 --- /dev/null +++ b/docs/source/cdmsfile.rst @@ -0,0 +1,8 @@ +CdmsFile +======== + +.. py:currentmodule:: cdms2.dataset + +.. autoclass:: CdmsFile + :members: + diff --git a/docs/source/conf.py b/docs/source/conf.py index f91bc093..3cfd1c36 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -134,13 +134,13 @@ #html_theme = 'agogo' #html_theme = 'pyramid' #html_theme = 'epub' -#html_theme = 'haiku' -html_theme = 'classic' +html_theme = 'haiku' +#html_theme = 'classic' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { "stickysidebar" : "true" } +#html_theme_options = { "stickysidebar" : "true" } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] diff --git a/docs/source/index.rst b/docs/source/index.rst index a0cd1856..1cd8c5dc 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -15,6 +15,7 @@ Contents: axis bindex cache + cdmsfile cdmsobj database dataset From f8ab8f0048a966f5f68a5063a934d2ef77b48368 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 31 Oct 2016 10:33:56 -0700 Subject: [PATCH 007/239] update documentation --- Lib/fvariable.py | 6 +- docs/Makefile | 2 +- docs/source/conf.py | 20 +- docs/source/index.rst | 1 + docs/source/manual/cdms.rst | 283 + docs/source/manual/cdms_1.rst | 676 ++ docs/source/manual/cdms_2.rst | 8734 ++++++++++++++++++++++++++ docs/source/manual/cdms_3.rst | 659 ++ docs/source/manual/cdms_4.rst | 1282 ++++ docs/source/manual/cdms_5.rst | 486 ++ docs/source/manual/cdms_6.rst | 3128 +++++++++ docs/source/manual/cdms_7.rst | 423 ++ docs/source/manual/cdms_appendix.rst | 1411 +++++ 13 files changed, 17105 insertions(+), 6 deletions(-) create mode 100644 docs/source/manual/cdms.rst create mode 100644 docs/source/manual/cdms_1.rst create mode 100644 docs/source/manual/cdms_2.rst create mode 100644 docs/source/manual/cdms_3.rst create mode 100644 docs/source/manual/cdms_4.rst create mode 100644 docs/source/manual/cdms_5.rst create mode 100644 docs/source/manual/cdms_6.rst create mode 100644 docs/source/manual/cdms_7.rst create mode 100644 docs/source/manual/cdms_appendix.rst diff --git a/Lib/fvariable.py b/Lib/fvariable.py index 4271e12c..2f5813cc 100644 --- a/Lib/fvariable.py +++ b/Lib/fvariable.py @@ -32,7 +32,7 @@ def __init__(self,parent,varname,cdunifobj=None): # Initialize the domain def initDomain(self, axisdict): - "Called by whoever made me." + "Initialized the domain" self.domain = [] for dimname in self._obj_.dimensions: axis = axisdict.get(dimname) @@ -42,7 +42,7 @@ def initDomain(self, axisdict): self.domain.append((axis,start,length,truelen)) def typecode(self): - # Compatibility: convert to new typecode + """convert to new typecode.""" tc = self._obj_.typecode() tc = typeconv.convtypecode2(tc).char return tc @@ -171,7 +171,7 @@ def getValue(self, squeeze=1): return self._obj_.getValue() def __len__(self): - " Length of first dimension. " + "Length of first dimension. " if self.parent is None: raise CDMSError, FileClosed+self.id return len(self._obj_) diff --git a/docs/Makefile b/docs/Makefile index 2aa9c4d2..61c88bb2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -15,7 +15,7 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source diff --git a/docs/source/conf.py b/docs/source/conf.py index 3cfd1c36..4b5150d1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,6 +15,9 @@ import sys import os import shlex +import easydev + +html_theme_path = [easydev.get_path_sphinx_themes()] # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -33,10 +36,23 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. +#extensions = [ +# 'easydev.copybutton', +# 'sphinx.ext.viewcode', +# 'sphinx.ext.imgmath', +# 'sphinx.ext.ifconfig', +# 'sphinx.ext.coverage', +# 'sphinx.ext.doctest', +# 'sphinx.ext.intersphinx', +# 'matplotlib.sphinxext.only_directives', +# 'matplotlib.sphinxext.plot_directive', +# 'sphinx.ext.napoleon' +#] extensions = [ - 'sphinx.ext.autodoc', + 'easydev.copybutton', 'sphinx.ext.todo', - 'sphinx.ext.viewcode', + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', 'sphinx.ext.napoleon' ] diff --git a/docs/source/index.rst b/docs/source/index.rst index 1cd8c5dc..9def6d66 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,6 +9,7 @@ Welcome to cdms2's documentation! Contents: .. toctree:: + manual/cdms_1 AbstractAxis AbstractVariable avariable diff --git a/docs/source/manual/cdms.rst b/docs/source/manual/cdms.rst new file mode 100644 index 00000000..969e1d6e --- /dev/null +++ b/docs/source/manual/cdms.rst @@ -0,0 +1,283 @@ +CDMS Manual Table of Contents +============================= + +`CHAPTER 1 Introduction `__ +'''''''''''''''''''''''''''''''''''''''' + +- `1.1 Overview `__ +- `1.2 Variables `__ +- `1.3 File I/O `__ +- `1.4 Coordinate Axes `__ +- `1.5 Attributes `__ +- `1.6 Masked values `__ +- `1.7 File Variables `__ +- `1.8 Dataset Variables `__ +- `1.9 Grids `__ + + - `1.9.1 Example: a curvilinear grid `__ + - `1.9.2 Example: a generic grid `__ + +- `1.10 Regridding `__ + + - `1.10.1 CDMS Regridder `__ + - `1.10.2 SCRIP Regridder `__ + +- `1.11 Time types `__ +- `1.12 Plotting data `__ +- `1.13 Databases `__ + +`CHAPTER 2 CDMS Python Application Programming Interface `__ +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +- `2.1 Overview `__ + + - `Table 2.1 Python types used in CDMS `__ + +- `2.2 A first example `__ +- `2.3 cdms module `__ + + - `Table 2.2 cdms module functions `__ + - `Table 2.3 Class Tags `__ + +- `2.4 CdmsObj `__ + + - `Table 2.4 Attributes common to all CDMS + objects `__ + - `Table 2.5 Getting and setting + attributes `__ + +- `2.5 CoordinateAxis `__ + + - `Table 2.6 CoordinateAxis types `__ + - `Table 2.7 CoordinateAxis Internal + Attributes `__ + - `Table 2.8 Axis Constructors `__ + - `Table 2.9 CoordinateAxis Methods `__ + - `Table 2.10 Axis Methods, additional to CoordinateAxis + methods `__ + - `Table 2.11 Axis Slice Operators `__ + +- `2.6 CdmsFile `__ + + - `Table 2.12 CdmsFile Internal + Attributes `__ + - `Table 2.13 CdmsFile Constructors `__ + - `Table 2.14 CdmsFile Methods `__ + - `Table 2.15 CDMS Datatypes `__ + +- `2.7 Database `__ + + - `2.7.1 Overview `__ + + - `Table 2.16 Database Internal + Attributes `__ + - `Table 2.17 Database Constructors `__ + - `Table 2.18 Database Methods `__ + + - `2.7.2 Searching a database `__ + + - `Table 2.19 SearchResult Methods `__ + - `Table 2.20 ResultEntry Attributes `__ + - `Table 2.21 ResultEntry Methods `__ + + - `2.7.3 Accessing data `__ + - `2.7.4 Examples of database searches `__ + +- `2.8 Dataset `__ + + - `Table 2.22 Dataset Internal + Attributes `__ + - `Table 2.23 Dataset Constructors `__ + - `Table 2.24 Open Modes `__ + - `Table 2.25 Dataset Methods `__ + +- `2.9 MV module `__ + + - `Table 2.26 Variable Constructors in module + MV `__ + - `Table 2.27 MV functions `__ + +- `2.10 HorizontalGrid `__ + + - `Table 2.28 `__ + - `Table 2.29 HorizontalGrid Internal + Attributes `__ + - `Table 2.30 RectGrid Constructors `__ + - `Table 2.31 HorizontalGrid Methods `__ + - `Table 2.32 RectGrid Methods, additional to HorizontalGrid + Methods `__ + +- `2.11 Variable `__ + + - `Table 2.33 Variable Internal + Attributes `__ + - `Table 2.34 Variable Constructors `__ + - `Table 2.35 Variable Methods `__ + - `Table 2.36 Variable Slice Operators `__ + - `Table 2.37 Index and Coordinate + Intervals `__ + - `2.11.1 Selectors `__ + + - `Table 2.38 Selector keywords `__ + + - `2.11.2 Selector examples `__ + +- `2.12 Examples `__ + +`CHAPTER 3 cdtime Module `__ +''''''''''''''''''''''''''''''''''''''''' + +- `3.1 Time types `__ +- `3.2 Calendars `__ +- `3.3 Time Constructors `__ + + - `Table 3.1 Time Constructors `__ + +- `3.4 Relative Time `__ + + - `Table 3.2 Relative Time Members `__ + +- `3.5 Component Time `__ + + - `Table 3.3 Component Time Members `__ + +- `3.6 Time Methods `__ + + - `Table 3.4 Time Methods `__ + +`CHAPTER 4 Regridding Data `__ +''''''''''''''''''''''''''''''''''''''''''' + +- `4.1 Overview `__ + + - `4.1.1 CDMS horizontal regridder `__ + - `4.1.2 SCRIP horizontal regridder `__ + - `4.1.3 Pressure-level regridder `__ + - `4.1.4 Cross-section regridder `__ + +- `4.2 regrid module `__ + + - `4.2.1 CDMS horizontal regridder `__ + + - `Table 4.1 CDMS Regridder + Constructor `__ + + - `4.2.2 SCRIP Regridder `__ + + - `Table 4.2 SCRIP Regridder + Constructor `__ + +- `4.3 regridder functions `__ + + - `4.3.1 CDMS regridder functions `__ + + - `Table 4.3 CDMS Regridder function `__ + + - `4.3.2 SCRIP Regridder functions `__ + + - `Table 4.4 SCRIP Regridder functions `__ + +- `4.4 Examples `__ + + - `4.4.1 CDMS regridder `__ + - `4.4.2 SCRIP regridder `__ + +`CHAPTER 5 Plotting CDMS data in Python `__ +'''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +- `5.1 Overview `__ +- `5.2 Examples `__ + + - `5.2.1 Example: plotting a gridded variable `__ + - `5.2.2 Example: using plot keywords. `__ + - `5.2.3 Example: plotting a time-latitude + slice `__ + - `5.2.4 Example: plotting subsetted data `__ + +- `5.3 plot method `__ + + - `Table 5.1 plot keywords `__ + +`CHAPTER 6 Climate Data Markup Language (CDML) `__ +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +- `6.1 Introduction `__ +- `6.2 Elements `__ + + - `Table 6.1 CDML Tags `__ + +- `6.3 Special Characters `__ + + - `Table 6.2 Special Character Encodings `__ + +- `6.4 Identifiers `__ +- `6.5 CF Metadata Standard `__ +- `6.6 CDML Syntax `__ + + - `6.6.1 Dataset Element `__ + + - `Table 6.3 Dataset Attributes `__ + + - `6.6.2 Axis Element `__ + + - `Table 6.4 Axis Attributes `__ + + - `6.6.3 partition attribute `__ + - `6.6.4 Grid Element `__ + + - `Table 6.5 RectGrid Attributes `__ + + - `6.6.5 Variable Element `__ + + - `Table 6.6 Variable Attributes `__ + + - `6.6.6 Attribute Element `__ + +- `6.7 A Sample CDML Document `__ + +`CHAPTER 7 CDMS Utilities `__ +'''''''''''''''''''''''''''''''''''''''''' + +- `7.1 cdscan: Importing datasets into CDMS `__ + + - `7.1.1 Overview `__ + - `7.1.2 cdscan Syntax `__ + + - `Table 7.1 cdscan command options `__ + + - `7.1.3 Examples `__ + - `7.1.4 File Formats `__ + - `7.1.5 Name Aliasing `__ + +`APPENDIX A CDMS Classes `__ +'''''''''''''''''''''''''''''''''''''''''''''''''' + +`APPENDIX B Version Notes `__ +''''''''''''''''''''''''''''''''''''''''''''''''''' + +- `B.1 Version 4.0 `__ +- `B.2 Version 3.0 Overview `__ +- `B.3 V3.0 Details `__ + + - `B.3.1 AbstractVariable `__ + - `B.3.2 AbstractAxis `__ + - `B.3.3 AbstractDatabase `__ + - `B.3.4 Dataset `__ + - `B.3.5 cdms module `__ + - `B.3.6 CdmsFile `__ + - `B.3.7 CDMSError `__ + - `B.3.8 AbstractRectGrid `__ + - `B.3.9 InternalAttributes `__ + - `B.3.10 TransientVariable `__ + - `B.3.11 MV `__ + +`APPENDIX C cu Module `__ +''''''''''''''''''''''''''''''''''''''''''''''' + +- `C.1 Slab `__ + + - `Table C.1 Slab Methods `__ + +- `C.2 cuDataset `__ + + - `Table C.2 cuDataset Methods `__ diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst new file mode 100644 index 00000000..96bfa16c --- /dev/null +++ b/docs/source/manual/cdms_1.rst @@ -0,0 +1,676 @@ +CHAPTER 1 +--------- + +CHAPTER 1 Introduction +~~~~~~~~~~~~~~~~~~~~~~ + +1.1 Overview +^^^^^^^^^^^^ + +The Climate Data Management System is an object-oriented data management +system, specialized for organizing multidimensional, gridded data used +in climate analysis and simulation. + +CDMS is implemented as part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT), which uses the Python language. The examples in +this chapter assume some familiarity with the language and the Python +Numeric module (http://www.numpy.org). A number of excellent tutorials +on Python are available in books or on the Internet. For example, see +the `Python Foundation's homepage `__. + +1.2 Variables +^^^^^^^^^^^^^ + +The basic unit of computation in CDMS is the variable. A variable is +essentially a multidimensional data array, augmented with a domain, a +set of attributes, and optionally a spatial and/or temporal coordinate +system (see `Coordinate Axes <#1.4>`__). As a data array, a variable can +be sliced to obtain a portion of the data, and can be used in arithmetic +computations. For example, if ``u`` and ``v`` are variables representing +the eastward and northward components of wind speed, respectively, and +both variables are functions of time, latitude, and longitude, then the +velocity for time 0 (first index) can be calculated as + +>>> from cdms import MV vel = MV.sqrt(u[0]**2 + v[0]2) + +This illustrates several points: + +- Square brackets represent the slice operator. Indexing starts at 0, + so ``u[0]`` selects from variable ``u`` for the first timepoint. The + result of this slice operation is another variable. The slice + operator can be multidimensional, and follows the syntax of Numeric + Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data + for the first ten timepoints, at all latitudes, for the second + longitude. +- Variables can be used in computation. ``**`` is the Python + exponentiation operator. +- Arithmetic functions are defined in the ``cdms.MV`` module. +- Operations on variables carry along the corresponding metadata where + applicable. In the above example, ``vel`` has the same latitude and + longitude coordinates as ``u`` and ``v``, and the time coordinate is + the first time of ``u`` and ``v``. + +1.3 File I/O +^^^^^^^^^^^^ + +A variable can be obtained from a file or collection of files, or can be +generated as the result of a computation. Files can be in any of the +self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS +control file), or PCMDI DRS. (HDF and DRS support is optional, and is +configured at the time UV-CDAT is installed.) For instance, to read data +from file sample.nc into variable u: + + >>> import cdms + >>> f = cdms.open('sample.nc') + >>> u = f('u') + +Data can be read by index or by world coordinate values. The following +reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k +such that i <= k < j): + + >>> u0 = f('u',time=slice(n,n+1)) + +To read ``u`` at time 366.0: + + >>> u1 = f('u',time=366.) + +A variable can be written to a file with the write function: + + >>> g = cdms.open('sample2.nc','w') + >>> g.write(u) + + >>> g.close() + +1.4 Coordinate Axes +^^^^^^^^^^^^^^^^^^^ + +A coordinate axis is a variable that represents coordinate information. +Typically an axis is associated with one or more variables in a file or +dataset, to represent the indexing and/or spatiotemporal coordinate +system(s) of the variable(s). + +Often in climate applications an axis is a one-dimensional variable +whose values are floating-point and strictly monotonic. In some cases an +axis can be multidimensional (see `Grids <#1.9>`__). If an axis is +associated with one of the canonical types latitude, longitude, level, +or time, then the axis is called tep emporal . + +The shape and physical ordering of a variable is represented by the +variables domain , an ordered tuple of one-dimensional axes. In the +previous example, the domain of the variable u is the tuple (time, +latitude, longitude). This indicates the order of the dimensions, with +the slowest- varying dimension listed first (time). The domain may be +accessed with the ``getAxisList()`` method: + + >>> s.getAxisList() + [ id: lat Designated a latitude axis. + units: degrees_north + Length: 64 + First: -87.8637970305 + Last: 87.8637970305 + Other axis attributes: + long_name: latitude + axis: Y + Python id: 833efa4, + id: lon Designated a longitude axis. + units: degrees_east Length: 128 + First: 0.0 + Last: 357.1875 + Other axis attributes: + modulo: 360.0 + topology: circular + long_name: longitude + axis: X + Python id: 833f174 + ] + +In the above example, the domain elements are axes that are also +spatiotemporal. In general it is not always the case that an element of +a domain is spatiotemporal: + +- An axis in the domain of a variable need not be spatiotemporal. For + example, it may represent a range of indices, an index coordinate + system. +- The latitude and/or longitude coordinate axes associated with a + variable need not be elements of the domain. In particular this will + be true if the variable is defined on a non-rectangular grid (see `Grids <#1.9>`__). + +As previously noted, a spatial and/or temporal coordinate system may be +associated with a variable. The methods getLatitude, getLongitude, +getLevel, and getTime return the associated coordinate axes. For +example: + + >>> t = u.getTime() >>> print t[:][ 0., 366., 731.,] + >>> print t.units 'days since 2000-1-1' + +1.5 Attributes +^^^^^^^^^^^^^^ + +As mentioned above, variables can have associated attributes , +name-value pairs. In fact, nearly all CDMS objects can have associated +attributes, which are accessed using the Python dot notation: + + >>> u.units='m/s' >>> print u.units m/s + +Attribute values can be strings, scalars, or 1-D Numeric arrays. + +When a variable is written to a file, not all the attributes are +written. Some attributes, called internal attributes, are used for +bookkeeping, and are not intended to be part of the external file +representation of the variable. In contrast, external attributes are +written to an output file along with the variable. By default, when an +attribute is set, it is treated as external. Every variable has a field +attributes, a Python dictionary that defines the external attributes: + + >>> print u.attributes.keys() ['datatype', 'name', 'missing_value', 'units'] + +The Python dir command lists the internal attribute names: + + >>> dir(u) ['_MaskedArray__data', '_MaskedArray__fill_value,' ..., 'id', 'parent'] + +In general internal attributes should not be modified directly. One +exception is the id attribute, the name of the variable. It is used in +plotting and I/O, and can be set directly. + +1.6 Masked values +^^^^^^^^^^^^^^^^^ + +Optionally, variables have a mask that represents where data are +missing. If present, the mask is an array of ones and zeros having the +shape of the data array. A mask value of one indicates that the +corresponding data array element is missing or invalid. + +Arithmetic operations in CDMS take missing data into account. The same +is true of the functions defined in the cdms.MV module. For example: + + >>> a = MV.array([1,2,3]) # Create array a, with no mask + >>> b = MV.array([4,5,6]) # Same for b + >>> a+b variable_13 array([5,7,9,]) + + a[1]=MV.masked # Mask the second value of a a.mask() # View the mask [0,1,0,] + + a+b # The sum is masked also variable_14 array( data = [5,0,9,], mask = [0,1,0,], fill_value=[0,] ) + +When data is read from a file, the result variable is masked if the file +variable has a missing_value attribute. The mask is set to one for +those elements equal to the missing value, zero elsewhere. If no such +attribute is present in the file, the result variable is not masked. + +When a variable with masked values is written to a file, data values +with a corresponding mask value of one are set to the value of the +variables ``missing_value`` attribute. The data and ``missing_value`` +attribute are then written to the file. + +Masking is covered in `Section 2.9 `__. See also the +documentation of the Python Numeric and MA modules, on which ``cdms.MV`` +is based, at + +[http://numpy.sourceforge.net](http://numpy.sourceforge.net/). + +1.7 File Variables +^^^^^^^^^^^^^^^^^^ + +A variable can be obtained either from a file, a collection of files, or +as the result of computation. Correspondingly there are three types of +variables in CDMS: + +- *file variable* is a variable associated with a single data file. + Setting or referencing a file variable generates I/O operations. +- A *dataset variable* is a variable associated with a collection of + files. Reference to a dataset variable reads data, possibly from + multiple files. Dataset variables are read-only. +- *transient variable* is an in-memory object not associated with a + file or dataset. Transient variables result from a computation or I/O + operation. + +Typical use of a file variables is to inquire information about the +variable in a file without actually reading the data for the variables. +A file variable is obtained by applying the slice operator [] to a file, +passing the name of the variable, or by calling the getVariable +function. Note that obtaining a file variable does not actually read the +data array: + + >>> f = cdms.open('sample.nc','r+') + >>> u = f.getVariable('u') # or u=f['u'] + >>> u.shape (3, 16, 32) + +File variables are also useful for fine-grained I/O. They behave like +transient variables, but operations on them also affect the associated +file. Specifically: + +- slicing a file variable reads data, +- setting a slice writes data, +- referencing an attribute reads the attribute, +- setting an attribute writes the attribute, +- and calling a file variable like a function reads data associated + with the variable: + + >>> f = cdms.open('sample.nc','r+') # Open read/write + >>> uvar = f['u'] # Note square brackets + >>> uvar.shape (3, 16, 32) + + u0 = uvar[0] # Reads data from sample.nc u0.shape (16, 32) + + uvar[1]=u0 # Writes data to sample.nc uvar.units # Reads the + attribute 'm/s' + + uvar.units='meters/second' # Writes the attribute # Calling + a variable like a function reads data u24 = uvar(time=24.0) + f.close() # Save changes to sample.nc (I/O may be buffered) + + +In an interactive application, the type of variable can be determined +simply by printing the variable: + + >>> rlsf # Transient variable rls array( array (4,48,96) , type = f, has 18432 elements) + >>> rlsg # Dataset variable + >>> prc # File variable + +Note that the data values themselves are not printed. For transient +variables, the data is printed only if the size of the array is less +than the print limit . This value can be set with the function +MV.set_print_limit to force the data to be printed: + + >>> smallvar.size() # Number of elements 20 + >>> MV.get_print_limit() # Current limit 300 + >>> smallvar small variable array( [[ 0., 1., 2., 3.,][ 4., 5., 6., 7.,] [ 8., 9., 10., 11.,][ 12., 13., 14., 15.,] [ 16., 17., 18., 19.,] ]) + >>> largevar.size() 400 + >>> largevar large variable array( array (20,20) , type = d, has 400 elements) + >>> MV.set_print_limit(500) # Reset the print limit + >>> largevar large variable array( [[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19.,] ... ]) + +The datatype of the variable is determined with the typecode function: + + >>> x.typecode() 'd' + +1.8 Dataset Variables +^^^^^^^^^^^^^^^^^^^^^ + +The third type of variable, a *dataset variable*, is associated with a +*dataset*, a collection of files that is treated as a single file. A +dataset is created with the ``cdscan`` utility. This generates an XML +metafile that describes how the files are organized and what metadata +are contained in the files. In a climate simulation application, a +dataset typically represents the data generated by one run of a general +circulation or coupled ocean-atmosphere model. + +For example, suppose data for variables u and v are stored in six files: +u_2000.nc, u_2001.nc, u_2002.nc, v_2000.nc, v_2001.nc , and +v_2002.nc. A metafile can be generated with the command: + +{% highlight text %} $ cdscan -x cdsample.xml [uv]\*.nc {% endhighlight +%} + +The metafile **cdsample.xml** is then used like an ordinary data file: + + >>> f = cdms.open('cdsample.xml') + >>> u = f('u') + >>> u.shape (3, 16, 32) + +1.9 Grids +^^^^^^^^^ + +A latitude-longitude grid represents the coordinate information +associated with a variable. A grid encapsulates: + +- latitude, longitude coordinates +- grid cell boundaries +- area weights + +CDMS defines a rich set of grid types to represent the variety of +coordinate systems used in climate model applications. Grids can be +categorized as rectangular or nonrectangular. + +A rectangular grid has latitude and longitude axes that are +one-dimensional, with strictly monotonic values. The grid is essentially +the Cartesian product of the axes. If either criterion is not met, the +grid is nonrectangular . + +CDMS supports two types of nonrectangular grid: + +- A curvilinear grid consists of a latitude and longitude axis, each of + which is a two-dimensional coordinate axis. Curvilinear grids are + often used in ocean model applications. +- A generic grid consists of a latitude and longitude axis, each of + which is an auxiliary one-dimensional coordinate axis. An auxiliary + axis has values that are not necessarily monotonic. As the name + suggests, generic grids can represent virtually any type of grid. + However, it is more difficult to determine adjacency relationships + between grid points. + +1.9.1 Example: a curvilinear grid +''''''''''''''''''''''''''''''''' + +In this example, variable sample is defined on a 128x192 curvilinear +grid. Note that: + +- The domain of variable sample is ( y , x ) where y and x are index + coordinate axes. +- The curvilinear grid associated with sample consists of axes ( lat , + lon ), each a two-dimensional coordinate axis. +- lat and lon each have domain ( y , x ) + + >>> f = cdms.open('sampleCurveGrid.nc') + +lat and lon are coordinate axes, but are grouped +================================================ + +with data variables +=================== + + f.variables.keys() ['lat', 'sample', 'bounds_lon', 'lon', + 'bounds_lat'] + +y and x are index coordinate axes +================================= + + f.axes.keys() ['y', 'x', 'nvert'] # Read data for variable + sample sample = f('sample') + +The associated grid g is curvilinear +==================================== + + g = sample.getGrid() g + +The domain of the variable consists of index axes +================================================= + + sample.getAxisIds() ['y', 'x'] + +Get the coordinate axes associated with the grid +================================================ + + lat = g.getLatitude() # or sample.getLatitude() lon = + g.getLongitude() # or sample.getLongitude() + +lat and lon have the same domain, a subset of +============================================= + +the domain of 'sample' +====================== + + lat.getAxisIds() ['y', 'x'] + +lat and lon are variables ... +============================= + + lat.shape (128, 192) lat lat array( array (128,192) , type = d, has 24576 elements) # ... so can be used in computation + + >>> lat_in_radians = lat\*Numeric.pi/180.0 + +.. figure:: /images/curvilinear_grid.jpg + :alt: curvilinear grid + + curvilinear grid + +1.9.2 Example: a generic grid +''''''''''''''''''''''''''''' + +In this example variable zs is defined on a generic grid. Figure 2 +illustrates the grid, in this case a geodesic grid. + + >>> f.variables.keys() ['lat', 'bounds_lon', 'lon', 'zs', 'bounds_lat'] + >>> f.axes.keys() ['cell', 'nvert'] + >>> zs = f('zs') + >>> g = zs.getGrid() + >>> g + >>> lat = g.getLatitude() + >>> lon = g.getLongitude() + >>> lat.shape (2562,) + >>> lon.shape (2562,) # variable zs is defined in terms of a single index coordinate + +axis, 'cell' +============ + + zs.shape (2562,) zs.getAxisIds() ['cell'] + +lat and lon are also defined in terms of the cell axis +====================================================== + + lat.getAxisIds() ['cell'] + +lat and lon are one-dimensional, 'auxiliary' coordinate +======================================================= + +axes: values are not monotonic +============================== + + lat. **class** + +.. figure:: /images/generic_grid.jpg + :alt: generic grid + + generic grid + +FIGURE 2. Generic grid + +Generic grids can be used to represent any of the grid types. The method +toGenericGrid can be applied to any grid to convert it to a generic +representation. Similarly, a rectangular grid can be represented as +curvilinear. The method toCurveGrid is used to convert a non-generic +grid to curvilinear representation: + + >>> import cdms + >>> f = cdms.open('clt.nc') + >>> clt = f('clt') + >>> rectgrid = clt.getGrid() + >>> rectgrid.shape (46, 72) + >>> curvegrid = rectgrid.toCurveGrid() + >>> curvegrid + >>> genericgrid = curvegrid.toGenericGrid() + >>> genericgrid + >>> + +1.10 Regridding +^^^^^^^^^^^^^^^ + +Regridding is the process of mapping variables from one grid to another. +CDMS supports two forms of regridding. Which one you use depends on the +class of grids being transformed: + +- To interpolate from one rectangular grid to another, use the built-in + CDMS regridder. CDMS also has built-in regridders to interpolate from + one set of pressure levels to another, or from one vertical + cross-section to another. +- To interpolate from any lat-lon grid, rectangular or non-rectangular, + use the SCRIP regridder. + +1.10.1 CDMS Regridder +''''''''''''''''''''' + +The built-in CDMS regridder is used to transform data from one +rectangular grid to another. For example, to regrid variable ``u`` (from +a rectangular grid) to a 96x192 rectangular Gaussian grid: + + >>> u = f('u') + >>> u.shape (3, 16, 32) + >>> t63_grid = cdms.createGaussianGrid(96) + >>> u63 = u.regrid(t63_grid) + >>> u63.shape (3, 96, 192) + +To regrid a variable ``uold`` to the same grid as variable ``vnew``: + + >>> uold.shape (3, 16, 32) + >>> vnew.shape (3, 96, 192) + >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew + >>> u63 = u.regrid(t63_grid) + >>> u63.shape (3, 96, 192) + +1.10.2 SCRIP Regridder +'''''''''''''''''''''' + +To interpolate between any lat-lon grid types, the SCRIP regridder may +be used. The SCRIP package was developed at [Los Alamos National +Laboratory](http://oceans11.lanl.gov/drupal/Models/OtherSoftware). +SCRIP is written in Fortran 90, and must be built and installed +separately from the UV-CDAT/CDMS installation. + +The steps to regrid a variable are: + +(external to CDMS) + +1. Obtain or generate the grids, in SCRIP netCDF format. +2. Run SCRIP to generate a *remapping* file. + +(in CDMS) + +1. Read the regridder from the SCRIP remapping file. +2. Call the regridder with the source data, returning data on the target + grid. + +Steps 1 and 2 need only be done once. The regridder can be used as often +as necessary. + +For example, suppose the source data on a T42 grid is to be mapped to a +POP curvilinear grid. Assume that SCRIP generated a remapping file named +rmp_T42_to_POP43_conserv.nc: + + >>> # Import regrid package for regridder functions + +import regrid, cdms + +Get the source variable +======================= + +f = cdms.open('sampleT42Grid.nc') dat = f('src_array') f.close() + +Read the regridder from the remapper file +========================================= + +remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') regridf = +regrid.readRegridder(remapf) remapf.close() + +Regrid the source variable +========================== + +popdat = regridf(dat) + +Regridding is discussed in `Chapter 4 `__. + +1.11 Time types +^^^^^^^^^^^^^^^ + +CDMS provides extensive support for time values in the cdtime module. +cdtime also defines a set of calendars , specifying the number of days +in a given month. + +Two time types are available: relative time and component time . +Relative time is time relative to a fixed base time. It consists of: + +- a ``units`` string, of the form ``"units since basetime"`` , and +- a floating-point ``value`` + +For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and +units=" days since 1996-1-1". To create a relative time type: + + >>> import cdtime + >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") + >>> rt 28.00 days since 1996-1-1 + >>> rt.value 28.0 + >>> rt.units 'days since 1996-1-1' + +A component time consists of the integer fields year, month, day, hour, +minute , and the floating-point field second . For example: + +:: + + >>> ct = cdtime.comptime(1996,2,28,12,10,30) + >>> ct + -2-28 12:10:30.0 + ct.year + ct.month + + +The conversion functions tocomp and torel convert between the two +representations. For instance, suppose that the time axis of a variable +is represented in units " days since 1979" . To find the coordinate +value corresponding to January 1, 1990: + +:: + + >>> ct = cdtime.comptime(1990,1) + >>> rt = ct.torel("days since 1979") + >>> rt.value + .0 + +Time values can be used to specify intervals of time to read. The syntax +time=(c1,c2) specifies that data should be read for times t such that +c1<=t<=c2: + +:: + + >>> c1 = cdtime.comptime(1990,1) + >>> c2 = cdtime.comptime(1991,1) + >>> ua = f[' ua'] + >>> ua.shape + 480, 17, 73, 144) + >>> x = ua.subRegion(time=(c1,c2)) + >>> x.shape + 12, 17, 73, 144) + +or string representations can be used: + +:: + + >>> x = ua.subRegion(time=('1990-1','1991-1')) + +Time types are described in Chapter 3. + +1.12 Plotting data +^^^^^^^^^^^^^^^^^^ + +Data read via the CDMS Python interface can be plotted using the vcs +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the VCS reference manual. The +vcs module provides access to the functionality of the VCS visualization +program. + +To generate a plot: + +- Initialize a canvas with the ``vcs init`` routine. +- Plot the data using the canvas ``plot`` routine. + +For example: + + >>> import cdms, vcs + >>> f = cdms.open('sample.nc') + >>> f['time'][:] # Print the time coordinates [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] + >>> precip = f('prc', time=24.0) # Read precip data + >>> precip.shape (1, 32, 64) + >>> w = vcs.init() # Initialize a canvas 'Template' is currently set to P_default. Graphics method 'Boxfill' is currently set to Gfb_default. + >>> w.plot(precip) # Generate a plot (generates a boxfill plot) + +By default for rectangular grids, a boxfill plot of the lat-lon slice is +produced. Since variable precip includes information on time, latitude, +and longitude, the continental outlines and time information are also +plotted. If the variable were on a non-rectangular grid, the plot would +be a meshfill plot. + +The plot routine has a number of options for producing different types +of plots, such as isofill and x-y plots. See `Chapter 5 `__ +for details. + +1.13 Databases +^^^^^^^^^^^^^^ + +Datasets can be aggregated together into hierarchical collections, +called databases . In typical usage, a program: + +- connects to a database +- searches for data opens a dataset +- accesses data + +Databases add the ability to search for data and metadata in a +distributed computing environment. At present CDMS supports one +particular type of database, based on the Lightweight Directory Access +Protocol (LDAP). + +Here is an example of accessing data via a database: + + >>> db = cdms.connect() # Connect to the default database. + >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. + >>> f.variables.keys() # List the variables in the dataset. +['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] + + +Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst new file mode 100644 index 00000000..1c1aa20f --- /dev/null +++ b/docs/source/manual/cdms_2.rst @@ -0,0 +1,8734 @@ +CHAPTER 2 CDMS Python Application Programming Interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +2.1 Overview +^^^^^^^^^^^^ + +This chapter describes the CDMS Python application programming interface +(API). Python is a popular public-domain, object-oriented language. Its +features include support for object-oriented development, a rich set of +programming constructs, and an extensible architecture. CDMS itself is +implemented in a mixture of C and Python. In this chapter the assumption +is made that the reader is familiar with the basic features of the +Python language. + +Python supports the notion of a module, which groups together associated +classes and methods. The import command makes the module accessible to +an application. This chapter documents the cdms, cdtime, and regrid +modules. + +The chapter sections correspond to the CDMS classes. Each section +contains tables base. If no parent, the datapath is absolute.describing +the class internal (non-persistent) attributes, constructors (functions +for creating an object), and class methods (functions). A method can +return an instance of a CDMS class, or one of the Python types: + +Table 2.1 Python types used in CDMS + + ++-------+--------------+ +| Type | Description | ++=======+==============+ +| Array | Numeric or | +| | masked | +| | multidimensi | +| | onal | +| | data array. | +| | All elements | +| | of the array | +| | are of the | +| | same type. | +| | Defined in | +| | the Numeric | +| | and MA | +| | modules. | ++-------+--------------+ +| Compt | Absolute | +| ime | time value, | +| | a time with | +| | representati | +| | on | +| | (year, | +| | month, day, | +| | hour, | +| | minute, | +| | second). | +| | Defined in | +| | the cdtime | +| | module. cf. | +| | reltime | ++-------+--------------+ +| Dicti | An unordered | +| onary | 2,3collectio | +| | n | +| | of objects, | +| | indexed by | +| | key. All | +| | dictionaries | +| | in CDMS are | +| | indexed by | +| | strings, | +| | e.g.: | +| | ``axes['time | +| | ']`` | ++-------+--------------+ +| Float | Floating-poi | +| | nt | +| | value. | ++-------+--------------+ +| Integ | Integer | +| er | value. | ++-------+--------------+ +| List | An ordered | +| | sequence of | +| | objects, | +| | which need | +| | not be of | +| | the same | +| | type. New | +| | members can | +| | be inserted | +| | or appended. | +| | Lists are | +| | denoted with | +| | square | +| | brackets, | +| | e.g., | +| | ``[1, 2.0, ' | +| | x', 'y']`` | ++-------+--------------+ +| None | No value | +| | returned. | ++-------+--------------+ +| Relti | Relative | +| me | time value, | +| | a time with | +| | representati | +| | on | +| | (value, | +| | units since | +| | basetime). | +| | Defined in | +| | the cdtime | +| | module. cf. | +| | comptime | ++-------+--------------+ +| Tuple | An ordered | +| | sequence of | +| | objects, | +| | which need | +| | not be of | +| | the same | +| | type. Unlike | +| | lists, | +| | tuples | +| | elements | +| | cannot be | +| | inserted or | +| | appended. | +| | Tuples are | +| | denoted with | +| | parentheses, | +| | e.g., | +| | ``(1, 2.0, ' | +| | x', 'y')`` | ++-------+--------------+ + +2.2 A first example +^^^^^^^^^^^^^^^^^^^ + +The following Python script reads January and July monthly temperature +data from an input dataset, averages over time, and writes the results +to an output file. The input temperature data is ordered (time, +latitude, longitude). + +{% highlight python %} 1 #!/usr/bin/env python 2 import cdms 3 from cdms +import MV 4 jones = cdms.open('/pcmdi/cdms/obs/jones\_mo.nc') 5 tasvar = +jones['tas'] 6 jans = tasvar[0::12] 7 julys = tasvar[6::12] 8 janavg = +MV.average(jans) 9 janavg.id = "tas\_jan" 10 janavg.long\_name = "mean +January surface temperature" 11 julyavg = MV.average(julys) 12 +julyavg.id = "tas\_jul" 13 julyavg.long\_name = "mean July surface +temperature" 14 out = cdms.open('janjuly.nc','w') 15 out.write(janavg) +16 out.write(julyavg) 17 out.comment = "Average January/July from Jones +dataset" 18 jones.close() 19 out.close() {% endhighlight %} + ++-------+--------+ +| Line | Notes | ++=======+========+ +| 2,3 | Makes | +| | the | +| | CDMS | +| | and MV | +| | module | +| | s | +| | availa | +| | ble. | +| | MV | +| | define | +| | s | +| | arithm | +| | etic | +| | functi | +| | ons. | ++-------+--------+ +| 4 | Opens | +| | a | +| | netCDF | +| | file | +| | read-o | +| | nly. | +| | The | +| | result | +| | jones | +| | is a | +| | datase | +| | t | +| | object | +| | . | ++-------+--------+ +| 5 | Gets | +| | the | +| | surfac | +| | e | +| | air | +| | temper | +| | ature | +| | variab | +| | le. | +| | 'tas' | +| | is the | +| | name | +| | of the | +| | variab | +| | le | +| | in the | +| | input | +| | datase | +| | t. | +| | This | +| | does | +| | not | +| | actual | +| | ly | +| | read | +| | the | +| | data. | ++-------+--------+ +| 6 | Read | +| | all | +| | Januar | +| | y | +| | monthl | +| | y | +| | mean | +| | data | +| | into a | +| | variab | +| | le | +| | jans. | +| | Variab | +| | les | +| | can be | +| | sliced | +| | like | +| | arrays | +| | . | +| | The | +| | slice | +| | operat | +| | or | +| | [0::12 | +| | ] | +| | means | +| | take | +| | every | +| | 12th | +| | slice | +| | from | +| | dimens | +| | ion | +| | 0, | +| | starti | +| | ng | +| | at | +| | index | +| | 0 and | +| | ending | +| | at the | +| | last | +| | index. | +| | If the | +| | stride | +| | 12 | +| | were | +| | omitte | +| | d, | +| | it | +| | would | +| | defaul | +| | t | +| | to 1. | +| | Note | +| | that | +| | the | +| | variab | +| | le | +| | is | +| | actual | +| | ly | +| | 3-dime | +| | nsiona | +| | l. | +| | Since | +| | no | +| | slice | +| | is | +| | specif | +| | ied | +| | for | +| | the | +| | second | +| | or | +| | third | +| | dimens | +| | ions, | +| | all | +| | values | +| | of | +| | those | +| | 2,3 | +| | dimens | +| | ions | +| | are | +| | retrie | +| | ved. | +| | The | +| | slice | +| | operat | +| | ion | +| | could | +| | also | +| | have | +| | been | +| | writte | +| | n | +| | [0::12 | +| | , | +| | : , | +| | :]. | +| | Also | +| | note | +| | that | +| | the | +| | same | +| | script | +| | works | +| | for | +| | multi- | +| | file | +| | datase | +| | ts. | +| | CDMS | +| | opens | +| | the | +| | needed | +| | data | +| | files, | +| | extrac | +| | ts | +| | the | +| | approp | +| | riate | +| | slices | +| | , | +| | and | +| | concat | +| | enates | +| | them | +| | into | +| | the | +| | result | +| | array. | ++-------+--------+ +| 7 | Reads | +| | all | +| | July | +| | data | +| | into a | +| | masked | +| | array | +| | julys. | ++-------+--------+ +| 8 | Calcul | +| | ate | +| | the | +| | averag | +| | e | +| | Januar | +| | y | +| | value | +| | for | +| | each | +| | grid | +| | zone. | +| | Any | +| | missin | +| | g | +| | data | +| | is | +| | handle | +| | d | +| | automa | +| | ticall | +| | y. | ++-------+--------+ +| 9,10 | Set | +| | the | +| | variab | +| | le | +| | id and | +| | long\_ | +| | name | +| | attrib | +| | utes. | +| | The id | +| | is | +| | used | +| | as the | +| | name | +| | of the | +| | variab | +| | le | +| | when | +| | plotte | +| | d | +| | or | +| | writte | +| | n | +| | to a | +| | file. | ++-------+--------+ +| 14 | Create | +| | a new | +| | netCDF | +| | output | +| | file | +| | named | +| | 'janju | +| | ly.nc' | +| | to | +| | hold | +| | the | +| | result | +| | s. | ++-------+--------+ +| 15 | Write | +| | the | +| | Januar | +| | y | +| | averag | +| | e | +| | values | +| | to the | +| | output | +| | file. | +| | The | +| | variab | +| | le | +| | will | +| | have | +| | id | +| | "tas\_ | +| | jan" | +| | in the | +| | file. | +| | ``writ | +| | e`` | +| | is a | +| | utilit | +| | y | +| | functi | +| | on | +| | which | +| | create | +| | s | +| | the | +| | variab | +| | le | +| | in the | +| | file, | +| | then | +| | writes | +| | data | +| | to the | +| | variab | +| | le. | +| | A more | +| | genera | +| | l | +| | method | +| | of | +| | data | +| | output | +| | is | +| | first | +| | to | +| | create | +| | a | +| | variab | +| | le, | +| | then | +| | set a | +| | slice | +| | of the | +| | variab | +| | le. | +| | Note | +| | that | +| | janavg | +| | and | +| | julavg | +| | have | +| | the | +| | same | +| | latitu | +| | de | +| | and | +| | longit | +| | ude | +| | inform | +| | ation | +| | as | +| | tasvar | +| | . | +| | It is | +| | carrie | +| | d | +| | along | +| | with | +| | the | +| | comput | +| | ations | +| | . | ++-------+--------+ +| 17 | Set | +| | the | +| | global | +| | attrib | +| | ute | +| | 'comme | +| | nt'. | ++-------+--------+ +| 18 | Close | +| | the | +| | output | +| | file. | ++-------+--------+ + +2.3 cdms module +^^^^^^^^^^^^^^^ + +The cdms module is the Python interface to CDMS. The objects and methods +in this chapter are made accessible with the command: + +{% highlight python %} import cdms {% endhighlight %} + +The functions described in this section are not associated with a class. +Rather, they are called as module functions, e.g., + +{% highlight python %} file = cdms.open('sample.nc') {% endhighlight %} + +Table 2.2 cdms module functions + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
TypeDefinition
+ +Variable + +.. raw:: html + + + +asVariable(s): Transform s into a transient variable. s is a masked +array, Numeric array, or Variable. If s is already a transient variable, +s is returned. See also: isVariable. + +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +createAxis(data, bounds=None): Create a one-dimensional coordinate Axis, +which is not associated with a file or dataset. This is useful for +creating a grid which is not contained in a file or dataset. data is a +one-dimensional, monotonic Numeric array. bounds is an array of shape +(len(data),2), such that for all i, data[i] is in the range +[bounds[i,0],bounds[i,1] ]. If bounds is not specified, the default +boundaries are generated at the midpoints between the consecutive data +values, provided that the autobounds mode is 'on' (the default). See +setAutoBounds. Also see: CdmsFile.createAxis + +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +createEqualAreaAxis(nlat): Create an equal-area latitude axis. The +latitude values range from north to south, and for all axis values x[i], +sin(x[i])sin(x[i+1]) is constant. nlat is the axis length. The axis is +not associated with a file or dataset. + +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +createGaussianAxis(nlat): Create a Gaussian latitude axis. Axis values +range from north to south. nlat is the axis length. The axis is not +associated with a file or dataset. + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createGaussianGrid(nlats, xorigin=0.0, order="yx"): Create a Gaussian +grid, with shape (nlats, 2\*nlats). nlats is the number of latitudes. +xorigin is the origin of the longitude axis. order is either "yx" +(lat-lon, default) or "xy" (lon-lat) + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, +order="yx", mask=None): Create a generic grid, that is, a grid which is +not typed as Gaussian, uniform, or equal-area. The grid is not +associated with a file or dataset. latArray is a NumPy array of latitude +values. lonArray is a NumPy array of longitude values. latBounds is a +NumPy array having shape (len(latArray),2), of latitude boundaries. +lonBounds is a NumPy array having shape (len(lonArray),2), of longitude +boundaries. order is a string specifying the order of the axes, either +"yx" for (latitude, longitude), or "xy" for the reverse. mask (optional) +is an integer-valued NumPy mask array, having the same shape and +ordering as the grid. + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createGlobalMeanGrid(grid): Generate a grid for calculating the global +mean via a regridding operation. The return grid is a single zone +covering the range of the input grid. grid is a RectGrid. + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createRectGrid(lat, lon, order, type="generic", mask=None): Create a +rectilinear grid, not associated with a file or dataset. This might be +used as the target grid for a regridding operation. lat is a latitude +axis, created by cdms.createAxis. lon is a longitude axis, created by +cdms.createAxis. order is a string with value "yx" (the first grid +dimension is latitude) or "xy" (the first grid dimension is longitude). +type is one of 'gaussian','uniform','equalarea',or 'generic'. If +specified, mask is a two-dimensional, logical Numeric array (all values +are zero or one) with the same shape as the grid. + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, +order="yx", mask=None): Create a uniform rectilinear grid. The grid is +not associated with a file or dataset. The grid boundaries are at the +midpoints of the axis values. startLat is the starting latitude value. +nlat is the number of latitudes. If nlat is 1, the grid latitude +boundaries will be startLat +/- deltaLat/2. deltaLat is the increment +between latitudes. startLon is the starting longitude value. nlon is the +number of longitudes. If nlon is 1, the grid longitude boundaries will +be startLon +/- deltaLon/2. deltaLon is the increment between +longitudes. order is a string with value "yx" (the first grid dimension +is latitude) or "xy" (the first grid dimension is longitude). If +specified, mask is a two-dimensional, logical Numeric array (all values +are zero or one) with the same shape as the grid. + +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +createUniformLatitudeAxis(startLat, nlat, deltaLat): Create a uniform +latitude axis. The axis boundaries are at the midpoints of the axis +values. The axis is designated as a circular latitude axis. startLat is +the starting latitude value. nlat is the number of latitudes. deltaLat +is the increment between latitudes. + +.. raw:: html + +
+ +RectGrid + +.. raw:: html + + + +createZonalGrid(grid): Create a zonal grid. The output grid has the same +latitude as the input grid, and a single longitude. This may be used to +calculate zonal averages via a regridding operation. grid is a RectGrid. + +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +createUniformLongitudeAxis(startLon, nlon, delta-Lon): Create a uniform +longitude axis. The axis boundaries are at the midpoints of the axis +values. The axis is designated as a circular longitude axis. startLon is +the starting longitude value. nlon is the number of longitudes. deltaLon +is the increment between longitudes. + +.. raw:: html + +
+ +Variable + +.. raw:: html + + + +createVariable(array, typecode=None, copy=0, savespace=0, mask=None, +fill\_value=None, grid=None, axes=None, attributes=None, id=None): This +function is documented in Table 2.34 on page 90. + +.. raw:: html + +
+ +Integer + +.. raw:: html + + + +getAutoBounds(): Get the current autobounds mode. Returns 0, 1, or 2. +See setAutoBounds. + +.. raw:: html + +
+ +Integer + +.. raw:: html + + + +isVariable(s): Return 1 if s is a variable, 0 otherwise. See also: +asVariable. + +.. raw:: html + +
+ +Dataset or CdmsFile + +.. raw:: html + + + +open(url,mode='r'): Open or create a Dataset or CdmsFile. url is a +Uniform Resource Locator, referring to a cdunif or XML file. If the URL +has the extension '.xml' or '.cdml', a Dataset is returned, otherwise a +CdmsFile is returned. If the URL protocol is 'http', the file must be a +'.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is +'file' or is omitted, a local file or dataset is opened. mode is the +open mode. See Table 2.24 on page 70. + +.. raw:: html + +

+ +Example: Open an existing dataset: + +f = cdms.open("sampleset.xml") + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: Create a netCDF file: + +f = cdms.open("newfile.nc",'w') + +.. raw:: html + +

+ +.. raw:: html + +
+ +List + +.. raw:: html + + + +order2index (axes, orderstring): Find the index permutation of axes to +match order. Return a list of indices. axes is a list of axis objects. +orderstring is defined as in orderparse. + +.. raw:: html + +
+ +List + +.. raw:: html + + + +orderparse(orderstring): Parse an order string. Returns a list of axes +specifiers. orderstring consists of: + +.. raw:: html + +
    + +:: + +
  • Letters t, x, y, z meaning time, longitude, latitude, level
  • + +
  • Numbers 0-9 representing position in axes
  • + +
  • Dash (-) meaning insert the next available axis here.
  • + +
  • The ellipsis ... meaning fill these positions with any remaining axes.
  • + +
  • (name) meaning an axis whose id is name
  • + +.. raw:: html + +
+ +.. raw:: html + +
+ +None + +.. raw:: html + + + +setAutoBounds(mode): Set autobounds mode. In some circumstances CDMS can +generate boundaries for 1-D axes and rectilinear grids, when the bounds +are not explicitly defined. The autobounds mode determines how this is +done: If mode is 'grid' or 2 (the default), the getBounds method will +automatically generate boundary information for an axis or grid if the +axis is designated as a latitude or longitude axis, and the boundaries +are not explicitly defined. If mode is 'on' or 1, the getBounds method +will automatically generate boundary information for an axis or grid, if +the boundaries are not explicitly defined. If mode is 'off' or 0, and no +boundary data is explicitly defined, the bounds will NOT be generated; +the getBounds method will return None for the boundaries. Note: In +versions of CDMS prior to V4.0, the default mode was 'on'. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +setClassifyGrids(mode): Set the grid classification mode. This affects +how grid type is determined, for the purpose of generating grid +boundaries. If mode is 'on' (the default), grid type is determined by a +grid classification method, regardless of the value of grid.get-Type(). +If mode is 'off', the value of grid.getType() determines the grid type + +.. raw:: html + +
+ +None + +.. raw:: html + + + +writeScripGrid(path, grid, gridTitle=None): Write a grid to a SCRIP grid +file. path is a string, the path of the SCRIP file to be created. grid +is a CDMS grid object. It may be rectangular. gridTitle is a string ID +for the grid. + +.. raw:: html + +
+ +Table 2.3 Class Tags + + ++--------------+---------------------+ +| Tag | Class | ++==============+=====================+ +| 'axis' | Axis | ++--------------+---------------------+ +| 'database' | Database | ++--------------+---------------------+ +| 'dataset' | Dataset, CdmsFile | ++--------------+---------------------+ +| 'grid' | RectGrid | ++--------------+---------------------+ +| 'variable' | Variable | ++--------------+---------------------+ +| 'xlink' | Xlink | ++--------------+---------------------+ + +2.4 CdmsObj +^^^^^^^^^^^ + +A CdmsObj is the base class for all CDMS database objects. At the +application level, CdmsObj objects are never created and used directly. +Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the +basis of user application programming. + +All objects derived from CdmsObj have a special attribute .attributes. +This is a Python dictionary, which contains all the external +(persistent) attributes associated with the object. This is in contrast +to the internal, non-persistent attributes of an object, which are +built-in and predefined. When a CDMS object is written to a file, the +external attributes are written, but not the internal attributes. + +**Example**: get a list of all external attributes of obj. + +{% highlight python %} extatts = obj.attributes.keys() {% endhighlight +%} + +Table 2.4 Attributes common to all CDMS objects + + ++--------------+--------------+--------------------------------------------------+ +| Type | Name | Definition | ++==============+==============+==================================================+ +| Dictionary | attributes | External attribute dictionary for this object. | ++--------------+--------------+--------------------------------------------------+ + +Table 2.5 Getting and setting attributes + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
TypeDefinition
+ +various + +.. raw:: html + + + +value = obj.attname + +.. raw:: html + +

+ +Get an internal or external attribute value. If the attribute is +external, it is read from the database. If the attribute is not already +in the database, it is created as an external attribute. Internal +attributes cannot be created, only referenced. + +.. raw:: html + +

+ +.. raw:: html + +
+ +various + +.. raw:: html + + + +obj.attname = value + +.. raw:: html + +

+ +Set an internal or external attribute value. If the attribute is +external, it is written to the database. + +.. raw:: html + +

+ +.. raw:: html + +
+ +2.5 CoordinateAxis +^^^^^^^^^^^^^^^^^^ + +A CoordinateAxis is a variable that represents coordinate information. +It may be contained in a file or dataset, or may be transient +(memoryresident). Setting a slice of a file CoordinateAxis writes to the +file, and referencing a file CoordinateAxis slice reads data from the +file. Axis objects are also used to define the domain of a Variable. + +CDMS defines several different types of CoordinateAxis objects. Table +2.9 on page 45 documents methods that are common to all CoordinateAxis +types. Table 2.10 on page 48 specifies methods that are unique to 1D +Axis objects. + +Table 2.6 CoordinateAxis types + + ++----------+-------------+ +| Type | Definition | ++==========+=============+ +| ``Coordi | A variable | +| nateAxis | that | +| `` | represents | +| | coordinate | +| | information | +| | . | +| | Has | +| | subtypes | +| | ``Axis2D`` | +| | and | +| | ``AuxAxis1D | +| | ``. | ++----------+-------------+ +| ``Axis`` | A | +| | one-dimensi | +| | onal | +| | coordinate | +| | axis whose | +| | values are | +| | strictly | +| | monotonic. | +| | Has | +| | subtypes | +| | ``DatasetAx | +| | is``, | +| | ``FileAxis` | +| | `, | +| | and | +| | ``Transient | +| | Axis``. | +| | May be an | +| | index axis, | +| | mapping a | +| | range of | +| | integers to | +| | the | +| | equivalent | +| | floating | +| | point | +| | value. If a | +| | latitude or | +| | longitude | +| | axis, may | +| | be | +| | associated | +| | with a | +| | ``RectGrid` | +| | `. | ++----------+-------------+ +| ``Axis2D | A | +| `` | two-dimensi | +| | onal | +| | coordinate | +| | axis, | +| | typically a | +| | latitude or | +| | longitude | +| | axis | +| | related to | +| | a | +| | ``Curviline | +| | arGrid``. | +| | Has | +| | subtypes | +| | ``DatasetAx | +| | is2D``, | +| | ``FileAxis2 | +| | D``, | +| | and | +| | ``Transient | +| | Axis2D``. | ++----------+-------------+ +| ``AuxAxi | A | +| s1D`` | one-dimensi | +| | onal | +| | coordinate | +| | axis whose | +| | values need | +| | not be | +| | monotonic. | +| | Typically a | +| | latitude or | +| | longitude | +| | axis | +| | associated | +| | with a | +| | ``GenericGr | +| | id``. | +| | Has | +| | subtypes | +| | ``DatasetAu | +| | xAxis1D``, | +| | ``FileAuxAx | +| | is1D``, | +| | and | +| | ``Transient | +| | AuxAxis1D`` | +| | . | +| | An axis in | +| | a | +| | ``CdmsFile` | +| | ` | +| | may be | +| | designated | +| | the | +| | unlimited | +| | axis, | +| | meaning | +| | that it can | +| | be extended | +| | in length | +| | after the | +| | initial | +| | definition. | +| | There can | +| | be at most | +| | one | +| | unlimited | +| | axis | +| | associated | +| | with a | +| | ``CdmsFile` | +| | `. | ++----------+-------------+ + +Table 2.7 CoordinateAxis Internal Attributes + + ++------------------+------------------+--------------------------------------------+ +| Type | Name | Definition | ++==================+==================+============================================+ +| ``Dictionary`` | ``attributes`` | External attribute dictionary. | ++------------------+------------------+--------------------------------------------+ +| ``String`` | ``id`` | CoordinateAxis identifer. | ++------------------+------------------+--------------------------------------------+ +| ``Dataset`` | ``parent`` | The dataset which contains the variable. | ++------------------+------------------+--------------------------------------------+ +| ``Tuple`` | ``shape`` | The length of each axis. | ++------------------+------------------+--------------------------------------------+ + +Table 2.8 Axis Constructors + + ++---------------+---------------+ +| Constructor | Description | ++===============+===============+ +| ``cdms.create | Create an | +| Axis(data, bo | axis which is | +| unds=None)`` | not | +| | associated | +| | with a | +| | dataset or | +| | file. See | +| | Table 2.2 on | +| | page 33. | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``Dataset.cre | Create an | +| ateAxis(name, | ``Axis`` in a | +| ar)`` | ``Dataset``. | +| | (This | +| | function is | +| | not yet | +| | implemented. | +| | ) | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``CdmsFile.cr | Create an | +| eateAxis(name | Axis in a | +| ,ar,unlimited | ``CdmsFile``. | +| =0)`` | ``name`` is | +| | the string | +| | ``name`` of | +| | the ``Axis``. | +| | ``ar`` is a | +| | 1-D data | +| | array which | +| | defines the | +| | ``Axis`` | +| | values. It | +| | may have the | +| | value | +| | ``None`` if | +| | an unlimited | +| | axis is being | +| | defined. At | +| | most one | +| | ``Axis`` in a | +| | ``CdmsFile`` | +| | may be | +| | designated as | +| | being | +| | unlimited, | +| | meaning that | +| | it may be | +| | extended in | +| | length. To | +| | define an | +| | axis as | +| | unlimited, | +| | either: | ++---------------+---------------+ +| | A) set ``ar`` | +| | to ``None``, | +| | and leave | +| | ``unlimited`` | +| | undefined, or | ++---------------+---------------+ +| | B) set ``ar`` | +| | to the | +| | initial 1-D | +| | array, and | +| | set | +| | ``unlimited`` | +| | to | +| | ``cdms.Unlimi | +| | ted`` | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``cdms.create | See Table 2.2 | +| EqualAreaAxis | on page 33. | +| (nlat)`` | | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``cdms.create | See Table 2.2 | +| GaussianAxis( | on page 18. | +| nlat)`` | | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``cdms.create | See Table 2.2 | +| UniformLatitu | on page 18. | +| deAxis(startl | | +| at, nlat, del | | +| talat)`` | | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ +| ``cdms.create | See Table 2.2 | +| UniformLongit | on page 18. | +| udeAxis(start | | +| lon, nlon, de | | +| ltalon)`` | | ++---------------+---------------+ +| ----------- | ------------ | ++---------------+---------------+ + +Table 2.9 CoordinateAxis Methods + + ++-------+-------+-------+ +| Type | Metho | Defin | +| | d | ition | ++=======+=======+=======+ +| ``Arr | ``arr | Read | +| ay`` | ay = | a | +| | axis[ | slice | +| | i:j]` | of | +| | ` | data | +| | | from | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et. | +| | | Data | +| | | is | +| | | retur | +| | | ned | +| | | in | +| | | the | +| | | physi | +| | | cal | +| | | order | +| | | ing | +| | | defin | +| | | ed | +| | | in | +| | | the | +| | | datas | +| | | et. | +| | | See | +| | | Table | +| | | 2.11 | +| | | on | +| | | page | +| | | 51 | +| | | for a | +| | | descr | +| | | iptio | +| | | n | +| | | of | +| | | slice | +| | | opera | +| | | tors. | ++-------+-------+-------+ +| ``Non | ``axi | Write | +| e`` | s[i:j | a | +| | ] = a | slice | +| | rray` | of | +| | ` | data | +| | | to | +| | | the | +| | | exter | +| | | nal | +| | | file. | +| | | Datas | +| | | et | +| | | axes | +| | | are | +| | | read- | +| | | only. | ++-------+-------+-------+ +| ``Non | ``ass | Set | +| e`` | ignVa | the | +| | lue(a | entir | +| | rray) | e | +| | `` | value | +| | | of | +| | | the | +| | | axis. | +| | | ``arr | +| | | ay`` | +| | | is a | +| | | Numer | +| | | ic | +| | | array | +| | | , | +| | | of | +| | | the | +| | | same | +| | | dimen | +| | | siona | +| | | lity | +| | | as | +| | | the | +| | | axis. | ++-------+-------+-------+ +| ``Axi | ``clo | Retur | +| s`` | ne(co | n | +| | pyDat | a | +| | a=1)` | copy | +| | ` | of | +| | | the | +| | | axis, | +| | | as a | +| | | trans | +| | | ient | +| | | axis. | +| | | If | +| | | copyD | +| | | ata | +| | | is 1 | +| | | (the | +| | | defau | +| | | lt) | +| | | the | +| | | data | +| | | itsel | +| | | f | +| | | is | +| | | copie | +| | | d. | ++-------+-------+-------+ +| ``Non | ``des | Desig | +| e`` | ignat | nate | +| | eLati | the | +| | tude( | axis | +| | persi | to be | +| | stent | a | +| | =0)`` | latit | +| | | ude | +| | | axis. | +| | | If | +| | | persi | +| | | stent | +| | | is | +| | | true, | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et | +| | | (if | +| | | any) | +| | | is | +| | | modif | +| | | ied. | +| | | By | +| | | defau | +| | | lt, | +| | | the | +| | | desig | +| | | natio | +| | | n | +| | | is | +| | | tempo | +| | | rary. | ++-------+-------+-------+ +| ``Non | ``des | Desig | +| e`` | ignat | nate | +| | eLeve | the | +| | l(per | axis | +| | siste | to be | +| | nt=0) | a | +| | `` | verti | +| | | cal | +| | | level | +| | | axis. | +| | | If | +| | | persi | +| | | stent | +| | | is | +| | | true, | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et | +| | | (if | +| | | any) | +| | | is | +| | | modif | +| | | ied. | +| | | By | +| | | defau | +| | | lt, | +| | | the | +| | | desig | +| | | natio | +| | | n | +| | | is | +| | | tempo | +| | | rary. | ++-------+-------+-------+ +| ``Non | ``des | Desig | +| e`` | ignat | nate | +| | eLong | the | +| | itude | axis | +| | (pers | to be | +| | isten | a | +| | t=0, | longi | +| | modul | tude | +| | o=360 | axis. | +| | .0)`` | ``mod | +| | | ulo`` | +| | | is | +| | | the | +| | | modul | +| | | us | +| | | value | +| | | . | +| | | Any | +| | | given | +| | | axis | +| | | value | +| | | ``x`` | +| | | is | +| | | treat | +| | | ed | +| | | as | +| | | equiv | +| | | alent | +| | | to | +| | | ``x + | +| | | modu | +| | | lus`` | +| | | . | +| | | If | +| | | ``per | +| | | siste | +| | | nt`` | +| | | is | +| | | true, | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et | +| | | (if | +| | | any) | +| | | is | +| | | modif | +| | | ied. | +| | | By | +| | | defau | +| | | lt, | +| | | the | +| | | desig | +| | | natio | +| | | n | +| | | is | +| | | tempo | +| | | rary. | ++-------+-------+-------+ +| ``Non | ``des | Desig | +| e`` | ignat | nate | +| | eTime | the | +| | (pers | axis | +| | isten | to be | +| | t=0, | a | +| | calen | time | +| | dar = | axis. | +| | cdti | If | +| | me.Mi | ``per | +| | xedCa | siste | +| | lenda | nt`` | +| | r)`` | is | +| | | true, | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et | +| | | (if | +| | | any) | +| | | is | +| | | modif | +| | | ied. | +| | | By | +| | | defau | +| | | lt, | +| | | the | +| | | desig | +| | | natio | +| | | n | +| | | is | +| | | tempo | +| | | rary. | +| | | ``cal | +| | | endar | +| | | `` | +| | | is | +| | | defin | +| | | ed | +| | | as in | +| | | ``get | +| | | Calen | +| | | dar() | +| | | ``. | ++-------+-------+-------+ +| ``Arr | ``get | Get | +| ay`` | Bound | the | +| | s()`` | assoc | +| | | iated | +| | | bound | +| | | ary | +| | | array | +| | | . | +| | | The | +| | | shape | +| | | of | +| | | the | +| | | retur | +| | | n | +| | | array | +| | | depen | +| | | ds | +| | | on | +| | | the | +| | | type | +| | | of | +| | | axis: | ++-------+-------+-------+ +| | ``Axi | +| | s``: | +| | ``(n, | +| | 2)`` | ++-------+-------+-------+ +| | ``Axi | +| | s2D`` | +| | : | +| | ``(i, | +| | j,4)` | +| | ` | ++-------+-------+-------+ +| | ``Aux | +| | Axis1 | +| | D``: | +| | ``(nc | +| | ell, | +| | nvert | +| | )`` | +| | where | +| | nvert | +| | is | +| | the | +| | maxim | +| | um | +| | numbe | +| | r | +| | of | +| | verti | +| | ces | +| | of a | +| | cell. | ++-------+-------+-------+ +| | If | +| | the | +| | bound | +| | ary | +| | array | +| | of a | +| | latit | +| | ude | +| | or | +| | longi | +| | tude | +| | ``Axi | +| | s`` | +| | is | +| | not | +| | expli | +| | citly | +| | defin | +| | ed, | +| | and | +| | ``aut | +| | oBoun | +| | ds`` | +| | mode | +| | is | +| | on, a | +| | defau | +| | lt | +| | array | +| | is | +| | gener | +| | ated | +| | by | +| | calli | +| | ng | +| | ``gen | +| | Gener | +| | icBou | +| | nds`` | +| | . | +| | Other | +| | wise | +| | if | +| | auto- | +| | Bound | +| | s | +| | mode | +| | is | +| | off, | +| | the | +| | retur | +| | n | +| | value | +| | is | +| | ``Non | +| | e``. | +| | See | +| | ``set | +| | AutoB | +| | ounds | +| | ``. | ++-------+-------+-------+ +| ``Int | ``get | Retur | +| eger` | Calen | ns | +| ` | dar() | the | +| | `` | calen | +| | | dar | +| | | assoc | +| | | iated | +| | | with | +| | | the | +| | | ``(ti | +| | | me)`` | +| | | \ axi | +| | | s. | +| | | Possi | +| | | ble | +| | | retur | +| | | n | +| | | value | +| | | s, | +| | | as | +| | | defin | +| | | ed | +| | | in | +| | | the | +| | | ``cdt | +| | | ime`` | +| | | modul | +| | | e, | +| | | are: | ++-------+-------+-------+ +| | ``cdt | +| | ime.G | +| | regor | +| | ianCa | +| | lenda | +| | r``: | +| | the | +| | stand | +| | ard | +| | Grego | +| | rian | +| | calen | +| | dar | ++-------+-------+-------+ +| | ``cdt | +| | ime.M | +| | ixedC | +| | alend | +| | ar``: | +| | mixed | +| | Julia | +| | n/Gre | +| | goria | +| | n | +| | calen | +| | dar | ++-------+-------+-------+ +| | ``cdt | +| | ime.J | +| | ulian | +| | Calen | +| | dar`` | +| | : | +| | years | +| | divis | +| | ible | +| | by 4 | +| | are | +| | leap | +| | years | ++-------+-------+-------+ +| | ``cdt | +| | ime.N | +| | oLeap | +| | Calen | +| | dar`` | +| | : | +| | a | +| | year | +| | is | +| | 365 | +| | days | ++-------+-------+-------+ +| | ``cdt | +| | ime.C | +| | alend | +| | ar360 | +| | ``: | +| | a | +| | year | +| | is | +| | 360 | +| | days | ++-------+-------+-------+ +| | ``Non | +| | e``: | +| | no | +| | calen | +| | dar | +| | can | +| | be | +| | ident | +| | ified | ++-------+-------+-------+ +| | Note: | +| | If | +| | the | +| | axis | +| | is | +| | not a | +| | time | +| | axis, | +| | the | +| | globa | +| | l, | +| | file- | +| | relat | +| | ed | +| | calen | +| | dar | +| | is | +| | retur | +| | ned. | ++-------+-------+-------+ +| ``Arr | ``get | Get | +| ay`` | Value | the | +| | ()`` | entir | +| | | e | +| | | axis | +| | | vecto | +| | | r. | ++-------+-------+-------+ +| ``Int | ``isL | Retur | +| eger` | atitu | ns | +| ` | de()` | true | +| | ` | iff | +| | | the | +| | | axis | +| | | is a | +| | | latit | +| | | ude | +| | | axis. | ++-------+-------+-------+ +| ``Int | ``isL | Retur | +| eger` | evel( | ns | +| ` | )`` | true | +| | | iff | +| | | the | +| | | axis | +| | | is a | +| | | level | +| | | axis. | ++-------+-------+-------+ +| ``Int | ``isL | Retur | +| eger` | ongit | ns | +| ` | ude() | true | +| | `` | iff | +| | | the | +| | | axis | +| | | is a | +| | | longi | +| | | tude | +| | | axis. | ++-------+-------+-------+ +| ``Int | ``isT | Retur | +| eger` | ime() | ns | +| ` | `` | true | +| | | iff | +| | | the | +| | | axis | +| | | is a | +| | | time | +| | | axis. | ++-------+-------+-------+ +| ``Int | ``len | The | +| eger` | (axis | lengt | +| ` | )`` | h | +| | | of | +| | | the | +| | | axis | +| | | if | +| | | one-d | +| | | imens | +| | | ional | +| | | . | +| | | If | +| | | multi | +| | | dimen | +| | | siona | +| | | l, | +| | | the | +| | | lengt | +| | | h | +| | | of | +| | | the | +| | | first | +| | | dimen | +| | | sion. | ++-------+-------+-------+ +| ``Int | ``siz | The | +| eger` | e()`` | numbe | +| ` | | r | +| | | of | +| | | eleme | +| | | nts | +| | | in | +| | | the | +| | | axis. | ++-------+-------+-------+ +| ``Str | ``typ | The | +| ing`` | ecode | ``Num | +| | ()`` | eric` | +| | | ` | +| | | datat | +| | | ype | +| | | ident | +| | | ifier | +| | | . | ++-------+-------+-------+ + +Table 2.10 Axis Methods, additional to CoordinateAxis methods + + ++-------+-------+-------+ +| Type | Metho | Defin | +| | d | ition | ++=======+=======+=======+ +| ``Lis | ``asC | ``Arr | +| t`` | ompon | ay`` | +| of | entTi | versi | +| compo | me(ca | on | +| nent | lenda | of | +| times | r=Non | ``cdt | +| | e)`` | ime t | +| | | ocomp | +| | | ``. | +| | | Retur | +| | | ns | +| | | a | +| | | ``Lis | +| | | t`` | +| | | of | +| | | compo | +| | | nent | +| | | times | +| | | . | ++-------+-------+-------+ +| ``Lis | ``asR | ``Arr | +| t`` | elati | ay`` | +| of | veTim | versi | +| relat | e()`` | on | +| ive | | of | +| times | | ``cdt | +| | | ime t | +| | | orel` | +| | | `. | +| | | Retur | +| | | ns | +| | | a | +| | | ``Lis | +| | | t`` | +| | | of | +| | | relat | +| | | ive | +| | | times | +| | | . | ++-------+-------+-------+ +| ``Non | ``des | Desig | +| e`` | ignat | nate | +| | eCirc | the | +| | ular( | axis | +| | modul | to be | +| | o, pe | circu | +| | rsist | lar. | +| | ent=0 | ``mod | +| | )`` | ulo`` | +| | | is | +| | | the | +| | | modul | +| | | us | +| | | value | +| | | . | +| | | Any | +| | | given | +| | | axis | +| | | value | +| | | ``x`` | +| | | is | +| | | treat | +| | | ed | +| | | as | +| | | equiv | +| | | alent | +| | | to | +| | | ``x + | +| | | modu | +| | | lus`` | +| | | . | +| | | If | +| | | ``per | +| | | siste | +| | | nt`` | +| | | is | +| | | ``Tru | +| | | e``, | +| | | the | +| | | exter | +| | | nal | +| | | file | +| | | or | +| | | datas | +| | | et | +| | | (if | +| | | any) | +| | | is | +| | | modif | +| | | ied. | +| | | By | +| | | defau | +| | | lt, | +| | | the | +| | | desig | +| | | natio | +| | | n | +| | | is | +| | | tempo | +| | | rary. | ++-------+-------+-------+ +| ``Int | ``isC | Retur | +| eger` | ircul | ns | +| ` | ar()` | ``Tru | +| | ` | e`` | +| | | if | +| | | the | +| | | axis | +| | | has | +| | | circu | +| | | lar | +| | | topol | +| | | ogy. | +| | | An | +| | | axis | +| | | is | +| | | defin | +| | | ed | +| | | as | +| | | circu | +| | | lar | +| | | if: | ++-------+-------+-------+ +| | ``axi | +| | s.top | +| | ology | +| | == ' | +| | circu | +| | lar'` | +| | `, | +| | or | ++-------+-------+-------+ +| | ``axi | +| | s.top | +| | ology | +| | `` | +| | is | +| | undef | +| | ined, | +| | and | +| | the | +| | axis | +| | is a | +| | longi | +| | tude. | +| | The | +| | defau | +| | lt | +| | cycle | +| | for | +| | circu | +| | lar | +| | axes | +| | is | +| | 360.0 | ++-------+-------+-------+ +| ``Int | ``isL | Retur | +| eger` | inear | ns | +| ` | ()`` | ``Tru | +| | | e`` | +| | | if | +| | | the | +| | | axis | +| | | has a | +| | | linea | +| | | r | +| | | repre | +| | | senta | +| | | tion. | ++-------+-------+-------+ +| ``Tup | ``map | Same | +| le`` | Inter | as | +| | val(i | ``map | +| | nterv | Inter | +| | al)`` | valEx | +| | | t``, | +| | | but | +| | | retur | +| | | ns | +| | | only | +| | | the | +| | | tuple | +| | | ``(i, | +| | | j)``, | +| | | and | +| | | ``wra | +| | | parou | +| | | nd`` | +| | | is | +| | | restr | +| | | icted | +| | | to | +| | | one | +| | | cycle | +| | | . | ++-------+-------+-------+ +| ``(i, | ``map | Map a | +| j,k)` | Inter | coord | +| ` | valEx | inate | +| | t(int | inter | +| | erval | val | +| | )`` | to an | +| | | index | +| | | ``int | +| | | erval | +| | | ``. | +| | | ``int | +| | | erval | +| | | `` | +| | | is a | +| | | tuple | +| | | havin | +| | | g | +| | | one | +| | | of | +| | | the | +| | | forms | +| | | : | ++-------+-------+-------+ +| | ``(x, | +| | y)`` | ++-------+-------+-------+ +| | ``(x, | +| | y,ind | +| | icato | +| | r)`` | ++-------+-------+-------+ +| | ``(x, | +| | y,ind | +| | icato | +| | r,cyc | +| | le)`` | ++-------+-------+-------+ +| | ``Non | +| | e or | +| | ':'`` | ++-------+-------+-------+ +| | where | +| | ``x`` | +| | and | +| | ``y`` | +| | are | +| | coord | +| | inate | +| | s | +| | indic | +| | ating | +| | the | +| | inter | +| | val | +| | ``[x, | +| | y)``, | +| | and: | ++-------+-------+-------+ +| | ``ind | +| | icato | +| | r`` | +| | is a | +| | two | +| | or | +| | three | +| | -char | +| | acter | +| | strin | +| | g, | +| | where | +| | the | +| | first | +| | chara | +| | cter | +| | is | +| | ``'c' | +| | `` | +| | if | +| | the | +| | inter | +| | val | +| | is | +| | close | +| | d | +| | on | +| | the | +| | left, | +| | ``'o' | +| | `` | +| | if | +| | open, | +| | and | +| | the | +| | secon | +| | d | +| | chara | +| | cter | +| | has | +| | the | +| | same | +| | meani | +| | ng | +| | for | +| | the | +| | right | +| | -hand | +| | point | +| | . | +| | If | +| | prese | +| | nt, | +| | the | +| | third | +| | chara | +| | cter | +| | speci | +| | fies | +| | how | +| | the | +| | inter | +| | val | +| | shoul | +| | d | +| | be | +| | inter | +| | secte | +| | d | +| | with | +| | the | +| | axis: | ++-------+-------+-------+ +| | ``'n' | +| | `` | +| | - | +| | selec | +| | t | +| | node | +| | value | +| | s | +| | which | +| | are | +| | conta | +| | ined | +| | in | +| | the | +| | inter | +| | val | ++-------+-------+-------+ +| | ``'b' | +| | `` | +| | -sele | +| | ct | +| | axis | +| | eleme | +| | nts | +| | for | +| | which | +| | the | +| | corre | +| | spond | +| | ing | +| | cell | +| | bound | +| | ary | +| | inter | +| | sects | +| | the | +| | inter | +| | val | ++-------+-------+-------+ +| | ``'e' | +| | `` | +| | - | +| | same | +| | as n, | +| | but | +| | inclu | +| | de | +| | an | +| | extra | +| | node | +| | on | +| | eithe | +| | r | +| | side | ++-------+-------+-------+ +| | ``'s' | +| | `` | +| | - | +| | selec | +| | t | +| | axis | +| | eleme | +| | nts | +| | for | +| | which | +| | the | +| | cell | +| | bound | +| | ary | +| | is a | +| | subse | +| | t | +| | of | +| | the | +| | inter | +| | val | ++-------+-------+-------+ +| | The | +| | defau | +| | lt | +| | indic | +| | ator | +| | is | +| | 'ccn' | +| | , | +| | that | +| | is, | +| | the | +| | inter | +| | val | +| | is | +| | close | +| | d, | +| | and | +| | nodes | +| | in | +| | the | +| | inter | +| | val | +| | are | +| | selec | +| | ted. | ++-------+-------+-------+ +| | If | +| | ``cyc | +| | le`` | +| | is | +| | speci | +| | fied, | +| | the | +| | axis | +| | is | +| | treat | +| | ed | +| | as | +| | circu | +| | lar | +| | with | +| | the | +| | given | +| | cycle | +| | value | +| | . | +| | By | +| | defau | +| | lt, | +| | if | +| | ``axi | +| | s.isC | +| | ircul | +| | ar()` | +| | ` | +| | is | +| | true, | +| | the | +| | axis | +| | is | +| | treat | +| | ed | +| | as | +| | circu | +| | lar | +| | with | +| | a | +| | defau | +| | lt | +| | modul | +| | us | +| | of | +| | ``360 | +| | .0``. | ++-------+-------+-------+ +| | An | +| | inter | +| | val | +| | of | +| | ``Non | +| | e`` | +| | or | +| | ``':' | +| | `` | +| | retur | +| | ns | +| | the | +| | full | +| | index | +| | inter | +| | val | +| | of | +| | the | +| | axis. | ++-------+-------+-------+ +| | The | +| | metho | +| | d | +| | retur | +| | ns | +| | the | +| | corre | +| | spond | +| | ing | +| | index | +| | inter | +| | val | +| | as a | +| | 3tupl | +| | e | +| | ``(i, | +| | j,k)` | +| | `, | +| | where | +| | ``k`` | +| | is | +| | the | +| | integ | +| | er | +| | strid | +| | e, | +| | and | +| | ``[i. | +| | j)`` | +| | is | +| | the | +| | half- | +| | open | +| | index | +| | inter | +| | val | +| | ``i < | +| | = k < | +| | j`` | +| | ``(i | +| | >= k | +| | > j i | +| | f k < | +| | 0)`` | +| | , | +| | or | +| | ``non | +| | e`` | +| | if | +| | the | +| | inter | +| | secti | +| | on | +| | is | +| | empty | +| | . | ++-------+-------+-------+ +| | for | +| | an | +| | axis | +| | which | +| | is | +| | circu | +| | lar | +| | (``ax | +| | is.to | +| | polog | +| | y == | +| | 'circ | +| | ular' | +| | ``), | +| | ``[i, | +| | j)`` | +| | is | +| | inter | +| | prete | +| | d | +| | as | +| | follo | +| | ws, | +| | where | +| | ``n = | +| | len( | +| | axis) | +| | `` | ++-------+-------+-------+ +| | if | +| | ``0 < | +| | = i < | +| | n`` | +| | and | +| | ``0 < | +| | = j < | +| | = n`` | +| | , | +| | the | +| | inter | +| | val | +| | does | +| | not | +| | wrap | +| | aroun | +| | d | +| | the | +| | axis | +| | endpo | +| | int. | ++-------+-------+-------+ +| | other | +| | wise | +| | the | +| | inter | +| | val | +| | wraps | +| | aroun | +| | d | +| | the | +| | axis | +| | endpo | +| | int. | ++-------+-------+-------+ +| | see | +| | also: | +| | ``map | +| | inter | +| | val`` | +| | , | +| | ``var | +| | iable | +| | .subr | +| | egion | +| | ()`` | ++-------+-------+-------+ +| ``tra | ``sub | creat | +| nsien | axis( | e | +| taxis | i,j,k | an | +| `` | =1)`` | axis | +| | | assoc | +| | | iated | +| | | with | +| | | the | +| | | integ | +| | | er | +| | | range | +| | | ``[i: | +| | | j:k]` | +| | | `. | +| | | the | +| | | strid | +| | | e | +| | | ``k`` | +| | | can | +| | | be | +| | | posit | +| | | ive | +| | | or | +| | | negat | +| | | ive. | +| | | wrapa | +| | | round | +| | | is | +| | | suppo | +| | | rted | +| | | for | +| | | longi | +| | | tude | +| | | dimen | +| | | sions | +| | | or | +| | | those | +| | | with | +| | | a | +| | | modul | +| | | us | +| | | attri | +| | | bute. | ++-------+-------+-------+ + +table 2.11 axis slice operators + + ++---------------+-----------------------------------------------------------------------------+ +| slice | definition | ++===============+=============================================================================+ +| ``[i]`` | the ``ith`` element, starting with index ``0`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:]`` | the ``ith`` element through and including the end | ++---------------+-----------------------------------------------------------------------------+ +| ``[:j]`` | the beginning element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[:]`` | the entire array | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | ++---------------+-----------------------------------------------------------------------------+ + +**example:** + +a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length +``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index +interval(s), with wraparound. the result index interval ``-2 <= n < 3`` +wraps around, since ``-2 < 0``, and has a stride of ``1``. this is +equivalent to the two contiguous index intervals ``2 <= n < 0`` and +``0 <= n < 3`` + +{% highlight python %} >>> axis.isCircular() 1 >>> +axis.mapIntervalExt((-5.0,5.0,'co')) (-2,3,1) {% endhighlight %} + +2.6 CdmsFile +^^^^^^^^^^^^ + +A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` +interface. netCDF files are accessible in read-write mode. All other +formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. + +As of CDMS V3, the legacy cuDataset interface is also supported by +Cdms-Files. See "cu Module" on page 180. + +Table 2.12 CdmsFile Internal Attributes + + ++------------------+------------------+---------------------------------------+ +| Type | Name | Definition | ++==================+==================+=======================================+ +| ``Dictionary`` | ``attributes`` | Global, external file attributes | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``grids`` | Grids contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``String`` | ``id`` | File pathname. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``variables`` | Variables contained in the file. | ++------------------+------------------+---------------------------------------+ + +Table 2.13 CdmsFile Constructors + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| ``fi | Open | +| leob | the | +| j = | file | +| cdms | spec | +| .ope | ifie | +| n(pa | d | +| th, | by | +| mode | path | +| )`` | retu | +| | rnin | +| | g | +| | a | +| | Cdms | +| | File | +| | obje | +| | ct. | +| | ``pa | +| | th`` | +| | is | +| | the | +| | file | +| | path | +| | name | +| | , | +| | a | +| | stri | +| | ng. | +| | ``mo | +| | de`` | +| | is | +| | the | +| | open | +| | mode | +| | indi | +| | cato | +| | r, | +| | as | +| | list | +| | ed | +| | in | +| | Tabl | +| | e | +| | 2.24 | +| | on | +| | page | +| | 70. | ++------+------+ +| ``fi | Crea | +| leob | te | +| j = | the | +| cdms | file | +| .cre | spec | +| ateD | ifie | +| atas | d | +| et(p | by | +| ath) | path | +| `` | , | +| | a | +| | stri | +| | ng. | ++------+------+ + +Table 2.14 CdmsFile Methods + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeMethodDefinition
Transient-Variablefileobj(varname, selector)

Calling a CdmsFile object as a function reads the region of data specified by the selector. The result is a transient variable, unless raw = 1 is specified. See "Selectors" on page 103.

Example: The following reads data for variable 'prc', year 1980:

f = cdms.open('test.nc')
+
+x = f('prc', time=('1980-1','1981-1'))
+
+.. raw:: html
+
+   
+ +.. raw:: html + +

Variable, Axis, or Grid

fileobj['id']

Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable.

Example: The following gets the persistent variable v, equivalent to v = f.variables['prc'].

+
f = cdms.open('sample.nc')
+
+v = f['prc']
+
+.. raw:: html
+
+   
+ +.. raw:: html + +

+ +Example: The following gets the axis named time, equivalent to t = +f.axes['time']. + +.. raw:: html + +

+ +:: + +

t = f['time']

Noneclose()Close the file.
AxiscopyAxis(axis, newname=None)Copy axis values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. axis is the axis object to be copied. newname, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used.
GridcopyGrid(grid, newname=None)Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. grid is the grid object to be copied. newname, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used.
AxiscreateAxis(id, ar, unlimited=0)Create a new Axis. This is a persistent object which can be used to read or write axis data to the file. id is an alphanumeric string identifier, containing no blanks. ar is the one-dimensional axis array. Set unlimited to cdms.Unlimited to indicate that the axis is extensible.
RectGridcreateRectGrid(id, lat, lon, order, type="generic", mask=None)Create a RectGrid in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. lat is a latitude axis in the file. lon is a longitude axis in the file. order is a string with value "yx" (the first grid dimension is latitude) or "xy" (the first grid dimension is longitude). type is one of 'gaussian','uniform','equalarea', or 'generic'. If specified, mask is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid.
VariablecreateVariable(String id, String datatype,List axes, fill_value=None)Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. id is a String name which is unique with respect to all other objects in the file. datatype is an MA typecode, e.g., MA.Float, MA.Int. axes is a list of Axis and/or Grid objects. fill_value is the missing value (optional).
VariablecreateVariableCopy(var, newname=None)

Create a new Variable, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. var is the Variable to be copied. newname, if specified is the name of the new variable. If unspecified, the returned variable has the same name as var.

Note: Unlike copyAxis, the actual data is not copied to the new variable.

CurveGrid or Generic-GridreadScripGrid(self, whichGrid='destination', check-Grid=1)Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, whichGrid chooses the grid to read, either "source" or "destination". If checkGrid is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.
Nonesync()Writes any pending changes to the file.
Variable
write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)

Write a variable or array to the file. The return value is the associated file variable.

If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords extend and index, and the unlimited dimension values associated with var.

var is a Variable, masked array, or Numeric array. attributes is the attribute dictionary for the variable. The default is var.attributes. axes is the list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). extbounds is the unlimited dimension bounds. Defaults to var.getAxis(0).getBounds(). id is the variable name in the file. Default is var.id. extend = 1 causes the first dimension to be unlimited: iteratively writeable. The default is None, in which case the first dimension is extensible if it is time.Set to 0 to turn off this behaviour. fill_value is the missing value flag. index is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension.

+

Note: data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable.

+
+ +Table 2.15 CDMS Datatypes + + ++-----------------+-----------------------------------+ +| CDMS Datatype | Definition | ++=================+===================================+ +| ``CdChar`` | character | ++-----------------+-----------------------------------+ +| ``CdDouble`` | double-precision floating-point | ++-----------------+-----------------------------------+ +| ``CdFloat`` | floating-point | ++-----------------+-----------------------------------+ +| ``CdInt`` | integer | ++-----------------+-----------------------------------+ +| ``CdLong`` | long integer | ++-----------------+-----------------------------------+ +| ``CdShort`` | short integer | ++-----------------+-----------------------------------+ + +2.7 Database +^^^^^^^^^^^^ + +A Database is a collection of datasets and other CDMS objects. It +consists of a hierarchical collection of objects, with the database +being at the root, or top of the hierarchy. A database is used to: + +- search for metadata +- access data +- provide authentication and access control for data and metadata + +The figure below illustrates several important points: + +- Each object in the database has a relative name of the form tag=id. + The id of an object is unique with respect to all objects contained + in the parent. + +- The name of the object consists of its relative name followed by the + relative name(s) of its antecedent objects, up to and including the + database name. In the figure below, one of the variables has name + ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. + +- Subordinate objects are thought of as being contained in the parent. + In this example, the database 'CDMS' contains two datasets, each of + which contain several variables. + +.. figure:: /images/diagram1.jpg + :alt: Diagram 1 + + Diagram 1 + +Figure 1 + + +2.7.1 Overview +'''''''''''''' + +To access a database: + +.. raw:: html + +
    + +.. raw:: html + +
  1. + +Open a connection. The connect method opens a database connection. +connect takes a database URI and returns a database object: db = +cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US") + +.. raw:: html + +
  2. + +.. raw:: html + +
  3. + +.. raw:: html + +

    + +Search the database, locating one or more datasets, variables, and/or +other objects. + +.. raw:: html + +

    + +.. raw:: html + +

    + +The database searchFilter method searches the database. A single +database connection may be used for an arbitrary number of searches. + +.. raw:: html + +

    + +.. raw:: html + +

    + +Example: Find all observed datasets + +.. raw:: html + +

    + +.. raw:: html + +

    + +result = db.searchFilter(category="observed",tag="dataset") + +.. raw:: html + +

    + +.. raw:: html + +

    + +Searches can be restricted to a subhierarchy of the database. + +.. raw:: html + +

    + +.. raw:: html + +

    + +Example: Search just the dataset 'ncep\_reanalysis\_mo': + +.. raw:: html + +

    + +.. raw:: html + +

    + +result = db.searchFilter(relbase="dataset=ncep\_reanalysis") + +.. raw:: html + +

    + +.. raw:: html + +
  4. + +.. raw:: html + +
  5. + +Refine the search results if necessary. The result of a search can be +narrowed with the searchPredicate method. + +.. raw:: html + +
  6. + +.. raw:: html + +
  7. + +.. raw:: html + +

    + +Process the results. A search result consists of a sequence of entries. +Each entry has a name, the name of the CDMS object, and an attribute +dictionary, consisting of the attributes located by the search: + +.. raw:: html + +

    + +.. raw:: html + +

    + + for entry in result: print entry.name, entry.attributes + +.. raw:: html + +

    + +.. raw:: html + +
  8. + +.. raw:: html + +
  9. + +.. raw:: html + +

    + +Access the data. The CDMS object associated with an entry is obtained +from the getObject method: + +.. raw:: html + +

    + +.. raw:: html + +

    + +obj = entry.getObject() + +.. raw:: html + +

    + +.. raw:: html + +

    + +If the id of a dataset is known, the dataset can be opened directly with +the open method: + +.. raw:: html + +

    + +.. raw:: html + +

    + +dset = db.open("ncep\_reanalysis\_mo") + +.. raw:: html + +

    + +.. raw:: html + +
  10. + +.. raw:: html + +
  11. + +.. raw:: html + +

    + +Close the database connection: + +.. raw:: html + +

    + +.. raw:: html + +

    + +db.close() + +.. raw:: html + +

    + +.. raw:: html + +
  12. + +.. raw:: html + +
+ +Table 2.16 Database Internal Attributes + + ++------------------+------------------+----------------------------------------+ +| Type | Name | Summary | ++==================+==================+========================================+ +| ``Dictionary`` | ``attributes`` | Database attribute dictionary | ++------------------+------------------+----------------------------------------+ +| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``netloc`` | Hostname, for server-based databases | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``path`` | path name | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``uri`` | Uniform Resource Identifier | ++------------------+------------------+----------------------------------------+ + +Table 2.17 Database Constructors + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| ``db | Conn | +| = c | ect | +| dms. | to | +| conn | the | +| ect( | data | +| uri= | base | +| None | . | +| , us | ``ur | +| er=" | i`` | +| ", p | is | +| assw | the | +| ord= | Univ | +| "")` | ersa | +| ` | l | +| | Reso | +| | urce | +| | Inde | +| | ntif | +| | ier | +| | of | +| | the | +| | data | +| | base | +| | . | +| | The | +| | form | +| | of | +| | the | +| | URI | +| | depe | +| | nds | +| | on | +| | the | +| | impl | +| | emen | +| | tati | +| | on | +| | of | +| | the | +| | data | +| | base | +| | . | +| | For | +| | a | +| | Ligh | +| | twei | +| | ght | +| | Dire | +| | ctor | +| | y | +| | Acce | +| | ss | +| | Prot | +| | ocol | +| | (LDA | +| | P) | +| | data | +| | base | +| | , | +| | the | +| | form | +| | is: | +| | ``ld | +| | ap:/ | +| | /hos | +| | t[:p | +| | ort] | +| | /dbn | +| | ame` | +| | `. | +| | For | +| | exam | +| | ple, | +| | if | +| | the | +| | data | +| | base | +| | is | +| | loca | +| | ted | +| | on | +| | host | +| | dbho | +| | st.l | +| | lnl. | +| | gov, | +| | and | +| | is | +| | name | +| | d | +| | ``'d | +| | atab | +| | ase= | +| | CDMS | +| | ,ou= | +| | PCMD | +| | I,o= | +| | LLNL | +| | ,c=U | +| | S'`` | +| | , | +| | the | +| | URI | +| | is: | +| | ``ld | +| | ap:/ | +| | /dbh | +| | ost. | +| | llnl | +| | .gov | +| | /dat | +| | abas | +| | e=CD | +| | MS,o | +| | u=PC | +| | MDI, | +| | o=LL | +| | NL,c | +| | =US` | +| | `. | +| | If | +| | unsp | +| | ecif | +| | ied, | +| | the | +| | URI | +| | defa | +| | ults | +| | to | +| | the | +| | valu | +| | e | +| | of | +| | envi | +| | ronm | +| | ent | +| | vari | +| | able | +| | CDMS | +| | ROOT | +| | . | +| | ``us | +| | er`` | +| | is | +| | the | +| | user | +| | ID. | +| | If | +| | unsp | +| | ecif | +| | ied, | +| | an | +| | anon | +| | ymou | +| | s | +| | conn | +| | ecti | +| | on | +| | is | +| | made | +| | . | +| | ``pa | +| | sswo | +| | rd`` | +| | is | +| | the | +| | user | +| | pass | +| | word | +| | . | +| | A | +| | pass | +| | word | +| | is | +| | not | +| | requ | +| | ired | +| | for | +| | an | +| | anon | +| | ymou | +| | s | +| | conn | +| | ecti | +| | on | ++------+------+ + +Table 2.18 Database Methods + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Type + +.. raw:: html + + + +Method + +.. raw:: html + + + +Definition + +.. raw:: html + +
+ +None + +.. raw:: html + + + +close() + +.. raw:: html + + + +Close a database connection. + +.. raw:: html + +
+ +List + +.. raw:: html + + + +listDatasets() + +.. raw:: html + + + +Return a list of the dataset IDs in this database. A dataset ID can be +passed to the open command. + +.. raw:: html + +
+ +Dataset + +.. raw:: html + + + +open(dsetid, mode='r') + +.. raw:: html + + + +.. raw:: html + +

+ +Open a dataset. + +.. raw:: html + +

+ +.. raw:: html + +

+ +dsetid is the string dataset identifier + +.. raw:: html + +

+ +.. raw:: html + +

+ +mode is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + +.. raw:: html + +

+ +.. raw:: html + +

+ +openDataset is a synonym for open. + +.. raw:: html + +

+ +.. raw:: html + +
+ +SearchResult + +.. raw:: html + + + +.. raw:: html + +
+   searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)
+     
+ +.. raw:: html + +
+ +.. raw:: html + +

+ +Search a CDMS database. + +.. raw:: html + +

+ +.. raw:: html + +

+ +filter is the string search filter. Simple filters have the form "tag = +value". Simple filters can be combined using logical operators '&', +'\|', '!' in prefix notation. + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: + +.. raw:: html + +

+ +.. raw:: html + +

+ +The filter '(&(objec)(id=cli))' finds all variables named "cli". + +.. raw:: html + +

+ +.. raw:: html + +

+ +A formal definition of search filters is provided in the following +section. + +.. raw:: html + +

+ +.. raw:: html + +

+ +tag restricts the search to objects with that tag ("dataset" \| +"variable" \| "database" \| "axis" \| "grid"). + +.. raw:: html + +

+ +.. raw:: html + +

+ +relbase is the relative name of the base object of the search. The +search is restricted to the base object and all objects below it in the +hierarchy. + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: + +.. raw:: html + +

+ +.. raw:: html + +

+ +To search only dataset 'ncep\_reanalysis\_mo', specify: + +.. raw:: html + +

+ +.. raw:: html + +

+ +relbase="dataset=ncep\_reanalysis\_mo" + +.. raw:: html + +

+ +.. raw:: html + +

+ +To search only variable 'ua' in 'ncep\_reanalysis\_mo', use: + +.. raw:: html + +

+ +.. raw:: html + +

+ +relbase="variable=ua,dataset=ncep\_reanalysis\_mo" + +.. raw:: html + +

+ +.. raw:: html + +

+ +If no base is specified, the entire database is searched. See the scope +argument also. + +.. raw:: html + +

+ +.. raw:: html + +

+ +scope is the search scope (Subtree \| Onelevel \| Base). + +.. raw:: html + +

+ +.. raw:: html + +
    + +:: + +
  • Subtree searches the base object and its descendants.
  • +
  • Onelevel searches the base object and its immediate descendants.
  • +
  • Basesearches the base object alone.
  • + +.. raw:: html + +
+ +.. raw:: html + +

+ +The default is Subtree. + +.. raw:: html + +

+ +.. raw:: html + +

+ +attnames: list of attribute names. Restricts the attributes returned. If +None, all attributes are returned. Attributes 'id' and 'objectclass' are +always included in the list. + +.. raw:: html + +

+ +.. raw:: html + +

+ +timeout: integer number of seconds before timeout. The default is no +timeout. + +.. raw:: html + +

+ +.. raw:: html + +
+ +2.7.2 Searching a database +'''''''''''''''''''''''''' + +The ``searchFilter`` method is used to search a database. The result is +called a search result, and consists of a sequence of result entries. + +In its simplest form, ``searchFilter`` takes an argument consisting of a +string filter. The search returns a sequence of entries, corresponding +to those objects having an attribute which matches the filter. Simple +filters have the form (tag = value), where value can contain wildcards. +For example: + +{% highlight text %} (id = ncep\*) (project = AMIP2) {% endhighlight %} + +Simple filters can be combined with the logical operators '&', '\|', +'!'. For example, + +{% highlight text %} (&(id = bmrc\*)(project = AMIP2)) {% endhighlight +%} + +matches all objects with id starting with bmrc, and a project attribute +with value 'AMIP2'. + +Formally, search filters are strings defined as follows: + +{% highlight text %} filter ::= "(" filtercomp ")" + +filtercomp ::= "&" filterlist \| # and "\|" filterlist \| # or "!" +filterlist \| # not simple + +filterlist ::= filter \| filter filterlist simple ::= tag op value op +::= "=" \| # equality + +"~=" \| # approximate equality "<=" \| # lexicographically less than or +equal to ">=" # lexicographically greater than or equal to + +tag ::= string attribute name value ::= string attribute value, may +include '\*' as a wild card {% endhighlight %} + +Attribute names are defined in the chapter on "Climate Data Markup +Language (CDML)" on page 149. In addition, some special attributes are +defined for convenience: + +- ``category`` is either "experimental" or "observed" +- ``parentid`` is the ID of the parent dataset +- ``project`` is a project identifier, e.g., "AMIP2" +- ``objectclass`` is the list of tags associated with the object. + +The set of objects searched is called the search scope. The top object +in the hierarchy is the base object. By default, all objects in the +database are searched, that is, the database is the base object. If the +database is very large, this may result in an unnecessarily slow or +inefficient search. To remedy this the search scope can be limited in +several ways: + +- The base object can be changed. +- The scope can be limited to the base object and one level below, or + to just the base object. +- The search can be restricted to objects of a given class (dataset, + variable, etc.) +- The search can be restricted to return only a subset of the object + attributes +- The search can be restricted to the result of a previous search. +- A search result is accessed sequentially within a for loop: + +{% highlight python %} result = +db.searchFilter('(&(category=obs\ *)(id=ncep*))') for entry in result: +print entry.name {% endhighlight %} + +Search results can be narrowed using ``searchPredicate``. In the +following example, the result of one search is itself searched for all +variables defined on a 94x192 grid: + +{% highlight python %} >>> result = +db.searchFilter('parentid=ncep\*',tag="variable") >>> len(result) 65 >>> +result2 = result.searchPredicate(lambda x: + +x.getGrid().shape==(94,192)) >>> len(result2) 3 >>> for entry in +result2: print entry.name +variable=rluscs,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, + +:: + + o=LLNL, c=US + +variable=rlds,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, + +:: + + o=LLNL, c=US + +variable=rlus,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, + +:: + + o=LLNL, c=US + +{% endhighlight %} + +Table 2.19 SearchResult Methods + + ++------+------+------+ +| Type | Meth | Defi | +| | od | niti | +| | | on | ++======+======+======+ +| Resu | ``[i | Retu | +| ltEn | ]`` | rn | +| try | | the | +| | | i-th | +| | | sear | +| | | ch | +| | | resu | +| | | lt. | +| | | Resu | +| | | lts | +| | | can | +| | | also | +| | | be | +| | | retu | +| | | rned | +| | | in a | +| | | for | +| | | loop | +| | | : | +| | | ``fo | +| | | r en | +| | | try | +| | | in d | +| | | b.se | +| | | arch | +| | | Resu | +| | | lt(t | +| | | ag=" | +| | | data | +| | | set" | +| | | ):`` | ++------+------+------+ +| Inte | ``le | Numb | +| ger | n()` | er | +| | ` | of | +| | | entr | +| | | ies | +| | | in | +| | | the | +| | | resu | +| | | lt. | ++------+------+------+ +| Sear | ``se | Refi | +| chRe | arch | ne | +| sult | Pred | a | +| | icat | sear | +| | e(pr | ch | +| | edic | resu | +| | ate, | lt, | +| | tag | with | +| | =Non | a | +| | e)`` | pred | +| | | icat | +| | | e | +| | | sear | +| | | ch. | +| | | ``pr | +| | | edic | +| | | ate` | +| | | ` | +| | | is a | +| | | func | +| | | tion | +| | | whic | +| | | h | +| | | take | +| | | s | +| | | a | +| | | sing | +| | | le | +| | | CDMS | +| | | obje | +| | | ct | +| | | and | +| | | retu | +| | | rns | +| | | true | +| | | (1) | +| | | if | +| | | the | +| | | obje | +| | | ct | +| | | sati | +| | | sfie | +| | | s | +| | | the | +| | | pred | +| | | icat | +| | | e, | +| | | 0 if | +| | | not. | +| | | ``ta | +| | | g`` | +| | | rest | +| | | rict | +| | | s | +| | | the | +| | | sear | +| | | ch | +| | | to | +| | | obje | +| | | cts | +| | | of | +| | | the | +| | | clas | +| | | s | +| | | deno | +| | | ted | +| | | by | +| | | the | +| | | tag. | +| | | **No | +| | | te** | +| | | : | +| | | In | +| | | the | +| | | curr | +| | | ent | +| | | impl | +| | | emen | +| | | tati | +| | | on, | +| | | ``se | +| | | arch | +| | | Pred | +| | | icat | +| | | e``\ | +| | | is | +| | | much | +| | | less | +| | | effi | +| | | cien | +| | | t | +| | | than | +| | | ``se | +| | | arch | +| | | Filt | +| | | er`` | +| | | . | +| | | For | +| | | best | +| | | perf | +| | | orma | +| | | nce, | +| | | use | +| | | ``se | +| | | arch | +| | | Filt | +| | | er`` | +| | | to | +| | | narr | +| | | ow | +| | | the | +| | | scop | +| | | e | +| | | of | +| | | the | +| | | sear | +| | | ch, | +| | | then | +| | | use | +| | | ``se | +| | | arch | +| | | Pred | +| | | icat | +| | | e`` | +| | | for | +| | | more | +| | | gene | +| | | ral | +| | | sear | +| | | ches | +| | | . | ++------+------+------+ + +A search result is a sequence of result entries. Each entry has a string +name, the name of the object in the database hierarchy, and an attribute +dictionary. An entry corresponds to an object found by the search, but +differs from the object, in that only the attributes requested are +associated with the entry. In general, there will be much more +information defined for the associated CDMS object, which is retrieved +with the ``getObject`` method. + +Table 2.20 ResultEntry Attributes + + ++------+------+------+ +| Type | Name | Desc | +| | | ript | +| | | ion | ++======+======+======+ +| Stri | ``na | The | +| ng | me`` | name | +| | | of | +| | | this | +| | | entr | +| | | y | +| | | in | +| | | the | +| | | data | +| | | base | +| | | . | ++------+------+------+ +| Dict | ``at | The | +| iona | trib | attr | +| ry | utes | ibut | +| | `` | es | +| | | retu | +| | | rned | +| | | from | +| | | the | +| | | sear | +| | | ch. | +| | | ``at | +| | | trib | +| | | utes | +| | | [key | +| | | ]`` | +| | | is a | +| | | list | +| | | of | +| | | all | +| | | stri | +| | | ng | +| | | valu | +| | | es | +| | | asso | +| | | ciat | +| | | ed | +| | | with | +| | | the | +| | | key | ++------+------+------+ + +Table 2.21 ResultEntry Methods + + ++------+------+------+ +| Type | Meth | Defi | +| | od | niti | +| | | on | ++======+======+======+ +| ``Cd | ``ge | Retu | +| msOb | tObj | rn | +| j`` | ect( | the | +| | )`` | CDMS | +| | | obje | +| | | ct | +| | | asso | +| | | ciat | +| | | ed | +| | | with | +| | | this | +| | | entr | +| | | y. | +| | | **No | +| | | te:* | +| | | * | +| | | For | +| | | many | +| | | sear | +| | | ch | +| | | appl | +| | | icat | +| | | ions | +| | | it | +| | | is | +| | | unne | +| | | cess | +| | | ary | +| | | to | +| | | acce | +| | | ss | +| | | the | +| | | asso | +| | | ciat | +| | | ed | +| | | CDMS | +| | | obje | +| | | ct. | +| | | For | +| | | best | +| | | perf | +| | | orma | +| | | nce | +| | | this | +| | | func | +| | | tion | +| | | shou | +| | | ld | +| | | be | +| | | used | +| | | only | +| | | when | +| | | nece | +| | | ssar | +| | | y, | +| | | for | +| | | exam | +| | | ple, | +| | | to | +| | | retr | +| | | ieve | +| | | data | +| | | asso | +| | | ciat | +| | | ed | +| | | with | +| | | a | +| | | vari | +| | | able | +| | | . | ++------+------+------+ + +2.7.3 Accessing data +'''''''''''''''''''' + +To access data via CDMS: + +1. Locate the dataset ID. This may involve searching the metadata. +2. Open the dataset, using the open method. +3. Reference the portion of the variable to be read. + +In the next example, a portion of variable 'ua' is read from dataset +'ncep\_reanalysis\_mo': + +{% highlight python %} dset = db.open('ncep\_reanalysis\_mo') ua = +dset.variables['ua'] data = ua[0,0] {% endhighlight %} + +2.7.4 Examples of database searches +''''''''''''''''''''''''''''''''''' + +In the following examples, db is the database opened with + +{% highlight python %} db = cdms.connect() {% endhighlight %} + +This defaults to the database defined in environment variable +``CDMSROOT``. + +**Example:** List all variables in dataset 'ncep\_reanalysis\_mo': + +{% highlight python %} for entry in db.searchFilter(filter = +"parentid=ncep\_reanalysis\_mo", tag = "variable"): print entry.name {% +endhighlight %} + +**Example:** Find all axes with bounds defined: + +{% highlight python %} for entry in +db.searchFilter(filter="bounds=\*",tag="axis"): print entry.name {% +endhighlight %} + +**Example:** Locate all GDT datasets: + +{% highlight python %} for entry in +db.searchFilter(filter="Conventions=GDT\*",tag="dataset"): print +entry.name {% endhighlight %} + +**Example:** Find all variables with missing time values, in observed +datasets: + +{% highlight python %} def missingTime(obj): time = obj.getTime() return +time.length != time.partition\_length + +result = db.searchFilter(filter="category=observed") for entry in +result.searchPredicate(missingTime): print entry.name {% endhighlight %} + +**Example:** Find all CMIP2 datasets having a variable with id "hfss": + +{% highlight python %} for entry in db.searchFilter(filter = +"(&(project=CMIP2)(id=hfss))", tag = "variable"): print +entry.getObject().parent.id {% endhighlight %} + +**Example:** Find all observed variables on 73x144 grids: + +{% highlight python %} result = db.searchFilter(category='obs\*') for +entry in result.searchPredicate(lambda x: +x.getGrid().shape==(73,144),tag="variable"): print entry.name {% +endhighlight %} + +**Example:** Find all observed variables with more than 1000 timepoints: + +{% highlight python %} result = db.searchFilter(category='obs\*') for +entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = +"variable"): print entry.name, len(entry.getObject().getTime()) {% +endhighlight %} + +**Example:** Find the total number of each type of object in the +database + +{% highlight python %} print +len(db.searchFilter(tag="database")),"database" print +len(db.searchFilter(tag="dataset")),"datasets" print +len(db.searchFilter(tag="variable")),"variables" print +len(db.searchFilter(tag="axis")),"axes" {% endhighlight %} + +2.8 Dataset +^^^^^^^^^^^ + +A Dataset is a virtual file. It consists of a metafile, in CDML/XML +representation, and one or more data files. + +As of CDMS V3, the legacy cuDataset interface is supported by Datasets. +See "cu Module" on page 180. + +Table 2.22 Dataset Internal Attributes + + ++------+------+------+ +| Type | Name | Desc | +| | | ript | +| | | ion | ++======+======+======+ +| Dict | ``at | Data | +| iona | trib | set | +| ry | utes | exte | +| | `` | rnal | +| | | attr | +| | | ibut | +| | | es. | ++------+------+------+ +| Dict | ``ax | Axes | +| iona | es`` | cont | +| ry | | aine | +| | | d | +| | | in | +| | | the | +| | | data | +| | | set. | ++------+------+------+ +| Stri | ``da | Path | +| ng | tapa | of | +| | th`` | data | +| | | file | +| | | s, | +| | | rela | +| | | tive | +| | | to | +| | | the | +| | | pare | +| | | nt | +| | | data | +| | | base | +| | | . | +| | | If | +| | | no | +| | | pare | +| | | nt, | +| | | the | +| | | data | +| | | path | +| | | is | +| | | abso | +| | | lute | +| | | . | ++------+------+------+ +| Dict | ``gr | Grid | +| iona | ids` | s | +| ry | ` | cont | +| | | aine | +| | | d | +| | | in | +| | | the | +| | | data | +| | | set. | ++------+------+------+ +| Stri | ``mo | Open | +| ng | de`` | mode | +| | | . | ++------+------+------+ +| Data | ``pa | Data | +| base | rent | base | +| | `` | whic | +| | | h | +| | | cont | +| | | ains | +| | | this | +| | | data | +| | | set. | +| | | If | +| | | the | +| | | data | +| | | set | +| | | is | +| | | not | +| | | part | +| | | of a | +| | | data | +| | | base | +| | | , | +| | | the | +| | | valu | +| | | e | +| | | is | +| | | ``No | +| | | ne`` | +| | | . | ++------+------+------+ +| Stri | ``ur | Unif | +| ng | i`` | orm | +| | | Reso | +| | | urce | +| | | Iden | +| | | tifi | +| | | er | +| | | of | +| | | this | +| | | data | +| | | set. | ++------+------+------+ +| Dict | ``va | Vari | +| iona | riab | able | +| ry | les` | s | +| | ` | cont | +| | | aine | +| | | d | +| | | in | +| | | the | +| | | data | +| | | set. | ++------+------+------+ +| Dict | ``xl | Exte | +| iona | inks | rnal | +| ry | `` | link | +| | | s | +| | | cont | +| | | aine | +| | | d | +| | | in | +| | | the | +| | | data | +| | | set. | ++------+------+------+ + +Table 2.23 Dataset Constructors + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| ``da | Open | +| tase | the | +| tobj | data | +| = c | set | +| dms. | spec | +| open | ifie | +| (Str | d | +| ing | by | +| uri, | the | +| Str | Univ | +| ing | ersa | +| mode | l | +| ='r' | Reso | +| )`` | urce | +| | Indi | +| | cato | +| | r, | +| | a | +| | CDML | +| | file | +| | . | +| | Retu | +| | rns | +| | a | +| | Data | +| | set | +| | obje | +| | ct. | +| | mode | +| | is | +| | one | +| | of | +| | the | +| | indi | +| | cato | +| | rs | +| | list | +| | ed | +| | in | +| | Tabl | +| | e | +| | 2.24 | +| | on | +| | page | +| | 70. | +| | ``op | +| | enDa | +| | tase | +| | t`` | +| | is a | +| | syno | +| | nym | +| | for | +| | ``op | +| | en`` | ++------+------+ + +Table 2.24 Open Modes + + ++--------+-----------------------------------------------------------------------+ +| Mode | Definition | ++========+=======================================================================+ +| 'r' | read-only | ++--------+-----------------------------------------------------------------------+ +| 'r+' | read-write | ++--------+-----------------------------------------------------------------------+ +| 'a' | read-write. Open the file if it exists, otherwise create a new file | ++--------+-----------------------------------------------------------------------+ +| 'w' | Create a new file, read-write | ++--------+-----------------------------------------------------------------------+ + +Table 2.25 Dataset Methods + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeMethodDefinition
Transient-Variabledatasetobj(varname, selector) + Calling a Dataset object as a function reads the region of data defined by the + selector. The result is a transient variable, unless raw = 1 is + specified. See "Selectors" on page 103. + +

Example: The following reads data for variable 'prc', year 1980:

+
+
+f = cdms.open('test.xml') x = f('prc', time=('1980-1','1981-1'))
+
+.. raw:: html
+
+   
+ +:: + +
Variable, Axis, or Griddatasetobj['id'] +

The square bracket operator applied to a dataset gets the persistent + variable, axis or grid object having the string identifier. This does not read + the data for a variable. Returns None if not found.

+ +

Example:

+
+
+f = cdms.open('sample.xml') v = f['prc']
+
+.. raw:: html
+
+   
+ +:: + +

gets the persistent variable v, equivalent to v = + f.variables['prc'].

+ +

Example:

+ +

t = f['time']
+ gets the axis named 'time', equivalent to t = f.axes['time']

+
None
+
close()Close the dataset.
+

RectGrid

+
+

createRectGrid(id, lat, lon, order, type="generic", + mask=None)

+
+

Create a RectGrid in the dataset. This is not a persistent object: the + order, type, and mask are not written to the dataset. However, the grid may be + used for regridding operations.

+ +

lat is a latitude axis in the dataset.

+ +

lon is a longitude axis in the dataset.

+ +

order is a string with value "yx" (the first grid dimension is + latitude) or "xy" (the first grid dimension is longitude).

+ +

type is one of 'gaussian','uniform','equalarea',or + 'generic'

+ +

If specified, mask is a two-dimensional, logical Numeric array + (all values are zero or one) with the same shape as the grid.

+
+

Axis

+
+

getAxis(id)

+
+

Get an axis object from the file or dataset.

+ +

id is the string axis identifier.

+
+

Grid

+
+

getGrid(id)

+
+

Get a grid object from a file or dataset.

+ +

id is the string grid identifier.

+
+

List

+
+

getPaths()

+
+

Get a sorted list of pathnames of datafiles which comprise the dataset. This + does not include the XML metafile path, which is stored in the .uri + attribute.

+
+

Variable

+
+

getVariable(id)

+
+

Get a variable object from a file or dataset.

+ +

id is the string variable identifier.

+
CurveGrid or GenericGridreadScripGrid(self, whichGrid='destination', check-or Generic-Grid=1) +

Read a curvilinear or generic grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remapping file.

+ +

If a mapping file, whichGrid chooses the grid to read, either "source" or "destination".

+ +

If checkGrid is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.

+
None

sync()Write any pending changes to the dataset.
+ +2.9 MV module +^^^^^^^^^^^^^ + +The fundamental CDMS data object is the variable. A variable is +comprised of: + +- a masked data array, as defined in the NumPy MA module. +- a domain: an ordered list of axes and/or grids. +- an attribute dictionary. + +The MV module is a work-alike replacement for the MA module, that +carries along the domain and attribute information where appropriate. MV +provides the same set of functions as MA. However, MV functions generate +transient variables as results. Often this simplifies scripts that +perform computation. MA is part of the Python Numeric package, +documented at http://www.numpy.org. + +MV can be imported with the command: + +{% highlight text %} import MV {% endhighlight %} + +The command + +{% highlight text %} from MV import \* {% endhighlight %} + +allows use of MV commands without any prefix. + +Table 2.26 on page 75 lists the constructors in MV. All functions return +a transient variable. In most cases the keywords axes, attributes, and +id are available. axes is a list of axis objects which specifies the +domain of the variable. attributes is a dictionary. id is a special +attribute string that serves as the identifier of the variable, and +should not contain blanks or non-printing characters. It is used when +the variable is plotted or written to a file. Since the id is just an +attribute, it can also be set like any attribute: + +{% highlight text %} var.id = 'temperature' {% endhighlight %} + +For completeness MV provides access to all the MA functions. The +functions not listed in the following tables are identical to the +corresponding MA function: ``allclose``, ``allequal``, +``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, +``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, +``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, +``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, +``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, +``putmask``, ``rank``, ``ravel``, ``set_fill_value``, +``set_print_limit``, ``shape``, ``size``. See the documentation at +http://numpy.sourceforge.net for a description of these functions. + +Table 2.26 Variable Constructors in module MV + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| ``ar | Just | +| rayr | like | +| ange | ``MA | +| (sta | .ara | +| rt, | nge( | +| stop | )`` | +| =Non | exce | +| e, s | pt | +| tep= | it | +| 1, t | retu | +| ypec | rns | +| ode= | a | +| None | vari | +| , ax | able | +| is=N | whos | +| one, | e | +| att | type | +| ribu | can | +| tes= | be | +| None | spec | +| , id | fied | +| =Non | by | +| e)`` | the | +| | keyw | +| | ord | +| | argu | +| | ment | +| | type | +| | code | +| | . | +| | The | +| | axis | +| | , | +| | attr | +| | ibut | +| | e | +| | dict | +| | iona | +| | ry, | +| | and | +| | stri | +| | ng | +| | iden | +| | tifi | +| | er | +| | of | +| | the | +| | resu | +| | lt | +| | vari | +| | able | +| | may | +| | be | +| | spec | +| | ifie | +| | d. | +| | *Syn | +| | onym | +| | :* | +| | ``ar | +| | ange | +| | `` | ++------+------+ +| ``ma | Same | +| sked | as | +| _arr | MA.m | +| ay(a | aske | +| , ma | d\_a | +| sk=N | rray | +| one, | but | +| fil | crea | +| l_va | tes | +| lue= | a | +| None | vari | +| , ax | able | +| es=N | inst | +| one, | ead. | +| att | If | +| ribu | no | +| tes= | axes | +| None | are | +| , id | spec | +| =Non | ifie | +| e)`` | d, | +| | the | +| | resu | +| | lt | +| | has | +| | defa | +| | ult | +| | axes | +| | , | +| | othe | +| | rwis | +| | e | +| | axes | +| | is a | +| | list | +| | of | +| | axis | +| | obje | +| | cts | +| | matc | +| | hing | +| | a.sh | +| | ape. | ++------+------+ +| ``ma | Crea | +| sked | te | +| _obj | vari | +| ect( | able | +| data | mask | +| , va | ed | +| lue, | wher | +| cop | e | +| y=1, | exac | +| sav | tly | +| espa | data | +| ce=0 | equa | +| , ax | l | +| es=N | to | +| one, | valu | +| att | e. | +| ribu | Crea | +| tes= | te | +| None | the | +| , id | vari | +| =Non | able | +| e)`` | with | +| | the | +| | give | +| | n | +| | list | +| | of | +| | axis | +| | obje | +| | cts, | +| | attr | +| | ibut | +| | e | +| | dict | +| | iona | +| | ry, | +| | and | +| | stri | +| | ng | +| | id. | ++------+------+ +| ``ma | Cons | +| sked | truc | +| _val | ts | +| ues( | a | +| data | vari | +| , va | able | +| lue, | with | +| rto | the | +| l=1e | give | +| -05, | n | +| ato | list | +| l=1e | of | +| -08, | axes | +| cop | and | +| y=1, | attr | +| sav | ibut | +| espa | e | +| ce=0 | dict | +| , ax | iona | +| es=N | ry, | +| one, | whos | +| att | e | +| ribu | mask | +| tes= | is | +| None | set | +| , id | at | +| =Non | thos | +| e)`` | e | +| | plac | +| | es | +| | wher | +| | e | +| | ``ab | +| | s(da | +| | ta - | +| | val | +| | ue) | +| | < | +| | ato | +| | l + | +| | rtol | +| | * a | +| | bs(d | +| | ata) | +| | ``. | +| | This | +| | is a | +| | care | +| | ful | +| | way | +| | of | +| | sayi | +| | ng | +| | that | +| | thos | +| | e | +| | elem | +| | ents | +| | of | +| | the | +| | data | +| | that | +| | have | +| | valu | +| | e | +| | = | +| | valu | +| | e | +| | (to | +| | with | +| | in | +| | a | +| | tole | +| | ranc | +| | e) | +| | are | +| | to | +| | be | +| | trea | +| | ted | +| | as | +| | inva | +| | lid. | +| | If | +| | data | +| | is | +| | not | +| | of a | +| | floa | +| | ting | +| | poin | +| | t | +| | type | +| | , | +| | call | +| | s | +| | mask | +| | ed\_ | +| | obje | +| | ct | +| | inst | +| | ead. | ++------+------+ +| ``on | retu | +| es(s | rn | +| hape | an | +| , ty | arra | +| peco | y | +| de=' | of | +| l', | all | +| save | ones | +| spac | of | +| e=0, | the | +| axe | give | +| s=no | n | +| ne, | leng | +| attr | th | +| ibut | or | +| es=n | shap | +| one, | e. | +| id= | | +| none | | +| )`` | | ++------+------+ +| ``re | copy | +| shap | of a | +| e(a, | with | +| new | a | +| shap | new | +| e, a | shap | +| xes= | e. | +| none | | +| , at | | +| trib | | +| utes | | +| =non | | +| e, i | | +| d=no | | +| ne)` | | +| ` | | ++------+------+ +| ``re | retu | +| size | rn | +| (a, | a | +| new_ | new | +| shap | arra | +| e, a | y | +| xes= | with | +| none | the | +| , at | spec | +| trib | ifie | +| utes | d | +| =non | shap | +| e, i | e. | +| d=no | the | +| ne)` | orig | +| ` | inal | +| | arra | +| | ys | +| | tota | +| | l | +| | size | +| | can | +| | be | +| | any | +| | size | +| | . | ++------+------+ +| ``ze | an | +| ros( | arra | +| shap | y | +| e, t | of | +| ypec | all | +| ode= | zero | +| 'l', | s | +| sav | of | +| espa | the | +| ce=0 | give | +| , ax | n | +| es=n | leng | +| one, | th | +| att | or | +| ribu | shap | +| tes= | e | +| none | | +| , id | | +| =non | | +| e)`` | | ++------+------+ + +The following table describes the MV non-constructor functions. with the +exception of argsort, all functions return a transient variable. + +Table 2.27 MV functions + + ++------+------+ +| Func | Desc | +| tion | ript | +| | ion | ++======+======+ +| ``ar | Retu | +| gsor | rn | +| t(x, | a | +| axi | Nume | +| s=-1 | ric | +| , fi | arra | +| ll_v | y | +| alue | of | +| =Non | indi | +| e)`` | ces | +| | for | +| | sort | +| | ing | +| | alon | +| | g | +| | a | +| | give | +| | n | +| | axis | +| | . | ++------+------+ +| ``as | Same | +| arra | as | +| y(da | ``cd | +| ta, | ms.c | +| type | reat | +| code | eVar | +| =Non | iabl | +| e)`` | e(da | +| | ta, | +| | type | +| | code | +| | , co | +| | py=0 | +| | )``. | +| | This | +| | is a | +| | shor | +| | t | +| | way | +| | of | +| | ensu | +| | ring | +| | that | +| | some | +| | thin | +| | g | +| | is | +| | an | +| | inst | +| | ance | +| | of a | +| | vari | +| | able | +| | of a | +| | give | +| | n | +| | type | +| | befo | +| | re | +| | proc | +| | eedi | +| | ng, | +| | as | +| | in | +| | ``da | +| | ta = | +| | asa | +| | rray | +| | (dat | +| | a)`` | +| | . | +| | Also | +| | see | +| | the | +| | vari | +| | able | +| | ``as | +| | type | +| | ()`` | +| | func | +| | tion | +| | . | ++------+------+ +| ``av | Comp | +| erag | utes | +| e(a, | the | +| axi | aver | +| s=0, | age | +| wei | valu | +| ghts | e | +| =Non | of | +| e)`` | the | +| | non- | +| | mask | +| | ed | +| | elem | +| | ents | +| | of x | +| | alon | +| | g | +| | the | +| | sele | +| | cted | +| | axis | +| | . | +| | If | +| | weig | +| | hts | +| | is | +| | give | +| | n, | +| | it | +| | must | +| | matc | +| | h | +| | the | +| | size | +| | and | +| | shap | +| | e | +| | of | +| | x, | +| | and | +| | the | +| | valu | +| | e | +| | retu | +| | rned | +| | is: | +| | ``su | +| | m(a* | +| | weig | +| | hts) | +| | /sum | +| | (wei | +| | ghts | +| | )`` | +| | In | +| | comp | +| | utin | +| | g | +| | thes | +| | e | +| | sums | +| | , | +| | elem | +| | ents | +| | that | +| | corr | +| | espo | +| | nd | +| | to | +| | thos | +| | e | +| | that | +| | are | +| | mask | +| | ed | +| | in x | +| | or | +| | weig | +| | hts | +| | are | +| | igno | +| | red. | ++------+------+ +| ``ch | Has | +| oose | a | +| (con | resu | +| diti | lt | +| on, | shap | +| t)`` | ed | +| | like | +| | arra | +| | y | +| | cond | +| | itio | +| | n. | +| | ``t` | +| | ` | +| | must | +| | be a | +| | tupl | +| | e | +| | of | +| | two | +| | arra | +| | ys | +| | ``t1 | +| | `` | +| | and | +| | ``t2 | +| | ``. | +| | Each | +| | elem | +| | ent | +| | of | +| | the | +| | resu | +| | lt | +| | is | +| | the | +| | corr | +| | espo | +| | ndin | +| | g | +| | elem | +| | ent | +| | of | +| | ``t1 | +| | ``\ | +| | wher | +| | e | +| | ``co | +| | ndit | +| | ion` | +| | ` | +| | is | +| | true | +| | , | +| | and | +| | the | +| | corr | +| | espo | +| | ndin | +| | g | +| | elem | +| | ent | +| | of | +| | ``t2 | +| | `` | +| | wher | +| | e | +| | ``co | +| | ndit | +| | ion` | +| | ` | +| | is | +| | fals | +| | e. | +| | The | +| | resu | +| | lt | +| | is | +| | mask | +| | ed | +| | wher | +| | e | +| | ``co | +| | ndit | +| | ion` | +| | ` | +| | is | +| | mask | +| | ed | +| | or | +| | wher | +| | e | +| | the | +| | sele | +| | cted | +| | elem | +| | ent | +| | is | +| | mask | +| | ed. | ++------+------+ +| ``co | Conc | +| ncat | aten | +| enat | ate | +| e(ar | the | +| rays | arra | +| , ax | ys | +| is=0 | alon | +| , ax | g | +| isid | the | +| =Non | give | +| e, a | n | +| xisa | axis | +| ttri | . | +| bute | Give | +| s=No | the | +| ne)` | exte | +| ` | nded | +| | axis | +| | the | +| | id | +| | and | +| | attr | +| | ibut | +| | es | +| | prov | +| | ided | +| | - by | +| | defa | +| | ult, | +| | thos | +| | e | +| | of | +| | the | +| | firs | +| | t | +| | arra | +| | y. | ++------+------+ +| ``co | Coun | +| unt( | t | +| a, a | of | +| xis= | the | +| None | non- | +| )`` | mask | +| | ed | +| | elem | +| | ents | +| | in | +| | ``a` | +| | `, | +| | or | +| | alon | +| | g | +| | a | +| | cert | +| | ain | +| | axis | +| | . | ++------+------+ +| ``is | Retu | +| Mask | rn | +| edVa | true | +| riab | if | +| le(x | ``x` | +| )`` | ` | +| | is | +| | an | +| | inst | +| | ance | +| | of a | +| | vari | +| | able | +| | . | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _equ | mask | +| al(x | ed | +| , va | wher | +| lue) | e | +| `` | ``x` | +| | ` | +| | equa | +| | ls | +| | the | +| | scal | +| | ar | +| | valu | +| | e. | +| | For | +| | floa | +| | ting | +| | poin | +| | t | +| | valu | +| | es | +| | cons | +| | ider | +| | ``ma | +| | sked | +| | _val | +| | ues( | +| | x, v | +| | alue | +| | )`` | +| | inst | +| | ead. | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _gre | mask | +| ater | ed | +| (x, | wher | +| valu | e | +| e)`` | ``x | +| | > va | +| | lue` | +| | ` | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _gre | mask | +| ater | ed | +| _equ | wher | +| al(x | e | +| , va | ``x | +| lue) | >= v | +| `` | alue | +| | `` | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _les | mask | +| s(x, | ed | +| val | wher | +| ue)` | e | +| ` | ``x | +| | < | +| | val | +| | ue`` | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _les | mask | +| s_eq | ed | +| ual( | wher | +| x, v | e | +| alue | ``x | +| )`` | ≤ | +| | val | +| | ue`` | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _not | mask | +| _equ | ed | +| al(x | wher | +| , va | e | +| lue) | ``x | +| `` | != v | +| | alue | +| | `` | ++------+------+ +| ``ma | ``x` | +| sked | ` | +| _out | with | +| side | mask | +| (x, | of | +| v1, | all | +| v2)` | valu | +| ` | es | +| | of | +| | ``x` | +| | ` | +| | that | +| | are | +| | outs | +| | ide | +| | ``[v | +| | 1,v2 | +| | ]`` | ++------+------+ +| ``ma | Retu | +| sked | rn | +| _whe | ``x` | +| re(c | ` | +| ondi | as a | +| tion | vari | +| , x, | able | +| cop | mask | +| y=1) | ed | +| `` | wher | +| | e | +| | cond | +| | itio | +| | n | +| | is | +| | true | +| | . | +| | Also | +| | mask | +| | ed | +| | wher | +| | e | +| | ``x` | +| | ` | +| | or | +| | ``co | +| | ndit | +| | ion` | +| | ` | +| | mask | +| | ed. | +| | ``co | +| | ndit | +| | ion` | +| | ` | +| | is a | +| | mask | +| | ed | +| | arra | +| | y | +| | havi | +| | ng | +| | the | +| | same | +| | shap | +| | e | +| | as | +| | ``x` | +| | `. | ++------+------+ +| ``ma | Comp | +| ximu | ute | +| m(a, | the | +| b=N | maxi | +| one) | mum | +| `` | vali | +| | d | +| | valu | +| | es | +| | of | +| | ``x` | +| | ` | +| | if | +| | ``y` | +| | ` | +| | is | +| | ``No | +| | ne`` | +| | ; | +| | with | +| | two | +| | argu | +| | ment | +| | s, | +| | retu | +| | rn | +| | the | +| | elem | +| | ent- | +| | wise | +| | larg | +| | er | +| | of | +| | vali | +| | d | +| | valu | +| | es, | +| | and | +| | mask | +| | the | +| | resu | +| | lt | +| | wher | +| | e | +| | eith | +| | er | +| | ``x` | +| | ` | +| | or | +| | ``y` | +| | ` | +| | is | +| | mask | +| | ed. | ++------+------+ +| ``mi | Comp | +| nimu | ute | +| m(a, | the | +| b=N | mini | +| one) | mum | +| `` | vali | +| | d | +| | valu | +| | es | +| | of | +| | ``x` | +| | ` | +| | if | +| | ``y` | +| | ` | +| | is | +| | None | +| | ; | +| | with | +| | two | +| | argu | +| | ment | +| | s, | +| | retu | +| | rn | +| | the | +| | elem | +| | ent- | +| | wise | +| | smal | +| | ler | +| | of | +| | vali | +| | d | +| | valu | +| | es, | +| | and | +| | mask | +| | the | +| | resu | +| | lt | +| | wher | +| | e | +| | eith | +| | er | +| | ``x` | +| | ` | +| | or | +| | ``y` | +| | ` | +| | is | +| | mask | +| | ed. | ++------+------+ +| ``ou | Retu | +| terp | rn | +| rodu | a | +| ct(a | vari | +| , b) | able | +| `` | such | +| | that | +| | ``re | +| | sult | +| | [i, | +| | j] = | +| | a[i | +| | ] * | +| | b[j] | +| | ``. | +| | The | +| | resu | +| | lt | +| | will | +| | be | +| | mask | +| | ed | +| | wher | +| | e | +| | ``a[ | +| | i]`` | +| | or | +| | ``b[ | +| | j]`` | +| | is | +| | mask | +| | ed. | ++------+------+ +| ``po | ``a* | +| wer( | *b`` | +| a, b | | +| )`` | | ++------+------+ +| ``pr | Prod | +| oduc | uct | +| t(a, | of | +| axi | elem | +| s=0, | ents | +| fil | alon | +| l_va | g | +| lue= | axis | +| 1)`` | usin | +| | g | +| | ``fi | +| | ll_v | +| | alue | +| | `` | +| | for | +| | miss | +| | ing | +| | elem | +| | ents | +| | . | ++------+------+ +| ``re | Retu | +| peat | rn | +| (ar, | ``ar | +| rep | `` | +| eats | repe | +| , ax | ated | +| is=0 | ``re | +| )`` | peat | +| | s`` | +| | time | +| | s | +| | alon | +| | g | +| | ``ax | +| | is`` | +| | . | +| | ``re | +| | peat | +| | s`` | +| | is a | +| | sequ | +| | ence | +| | of | +| | leng | +| | th | +| | ``ar | +| | .sha | +| | pe[a | +| | xis] | +| | `` | +| | tell | +| | ing | +| | how | +| | many | +| | time | +| | s | +| | to | +| | repe | +| | at | +| | each | +| | elem | +| | ent. | ++------+------+ +| ``se | Set | +| t_de | the | +| faul | defa | +| t_fi | ult | +| ll_v | fill | +| alue | valu | +| (val | e | +| ue_t | for | +| ype, | ``va | +| val | lue_ | +| ue)` | type | +| ` | `` | +| | to | +| | ``va | +| | lue` | +| | `. | +| | ``va | +| | lue_ | +| | type | +| | `` | +| | is a | +| | stri | +| | ng: | +| | 'rea | +| | l',' | +| | comp | +| | lex' | +| | ,'ch | +| | arac | +| | ter' | +| | ,'in | +| | tege | +| | r',o | +| | r | +| | 'obj | +| | ect' | +| | . | +| | ``va | +| | lue` | +| | ` | +| | shou | +| | ld | +| | be a | +| | scal | +| | ar | +| | or | +| | sing | +| | le-e | +| | leme | +| | nt | +| | arra | +| | y. | ++------+------+ +| ``so | Sort | +| rt(a | arra | +| r, a | y | +| xis= | ``ar | +| -1)` | `` | +| ` | elem | +| | entw | +| | ise | +| | alon | +| | g | +| | the | +| | spec | +| | ifie | +| | d | +| | axis | +| | . | +| | The | +| | corr | +| | espo | +| | ndin | +| | g | +| | axis | +| | in | +| | the | +| | resu | +| | lt | +| | has | +| | dumm | +| | y | +| | valu | +| | es. | ++------+------+ +| ``su | Sum | +| m(a, | of | +| axi | elem | +| s=0, | ents | +| fil | alon | +| l_va | g | +| lue= | a | +| 0)`` | cert | +| | ain | +| | axis | +| | usin | +| | g | +| | ``fi | +| | ll_v | +| | alue | +| | `` | +| | for | +| | miss | +| | ing. | ++------+------+ +| ``ta | Retu | +| ke(a | rn | +| , in | a | +| dice | sele | +| s, a | ctio | +| xis= | n | +| 0)`` | of | +| | item | +| | s | +| | from | +| | ``a` | +| | `. | +| | See | +| | the | +| | docu | +| | ment | +| | atio | +| | n | +| | in | +| | the | +| | Nume | +| | ric | +| | manu | +| | al. | ++------+------+ +| ``tr | Perf | +| ansp | orm | +| ose( | a | +| ar, | reor | +| axes | deri | +| =Non | ng | +| e)`` | of | +| | the | +| | axes | +| | of | +| | arra | +| | y | +| | ar | +| | depe | +| | ndin | +| | g | +| | on | +| | the | +| | tupl | +| | e | +| | of | +| | indi | +| | ces | +| | axes | +| | ; | +| | the | +| | defa | +| | ult | +| | is | +| | to | +| | reve | +| | rse | +| | the | +| | orde | +| | r | +| | of | +| | the | +| | axes | +| | . | ++------+------+ +| ``wh | ``x` | +| ere( | ` | +| cond | wher | +| itio | e | +| n, x | ``co | +| , y) | ndit | +| `` | ion` | +| | ` | +| | is | +| | true | +| | , | +| | ``y` | +| | ` | +| | othe | +| | rwis | +| | e | ++------+------+ + +2.10 HorizontalGrid +^^^^^^^^^^^^^^^^^^^ + +A HorizontalGrid represents a latitude-longitude coordinate system. In +addition, it optionally describes how lat-lon space is partitioned into +cells. Specifically, a HorizontalGrid: + +- consists of a latitude and longitude coordinate axis. +- may have associated boundary arrays describing the grid cell + boundaries, +- may optionally have an associated logical mask. + +CDMS supports several types of HorizontalGrids: + +Table 2.28 + + ++------+------+ +| Grid | Defi | +| Type | niti | +| | on | ++======+======+ +| ``Re | Asso | +| ctGr | ciat | +| id`` | ed | +| | lati | +| | tude | +| | an | +| | long | +| | itud | +| | e | +| | are | +| | 1-D | +| | axes | +| | , | +| | with | +| | stri | +| | ctly | +| | mono | +| | toni | +| | c | +| | valu | +| | es. | ++------+------+ +| ``Cu | Lati | +| rveG | tude | +| rid` | and | +| ` | long | +| | itud | +| | e | +| | are | +| | 2-D | +| | coor | +| | dina | +| | te | +| | axes | +| | (Axi | +| | s2D) | +| | . | ++------+------+ +| ``Ge | Lati | +| neri | tude | +| cGri | and | +| d`` | long | +| | itud | +| | e | +| | are | +| | 1-D | +| | auxi | +| | liar | +| | y | +| | coor | +| | dina | +| | te | +| | axis | +| | (Aux | +| | Axis | +| | 1D) | ++------+------+ + +Table 2.29 HorizontalGrid Internal Attribute + + ++-----------------------+------------------+------------------------------------------------+ +| Type | Name | Definition | ++=======================+==================+================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+------------------+------------------------------------------------+ +| String | ``id`` | The grid identifier. | ++-----------------------+------------------+------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | ++-----------------------+------------------+------------------------------------------------+ +| Tuple | ``shape`` | The shape of the grid, a 2-tuple | ++-----------------------+------------------+------------------------------------------------+ + +Table 2.31 on page 82 describes the methods that apply to all types of +HorizontalGrids. Table 2.32 on page 86 describes the additional methods +that are unique to RectGrids. + +Table 2.30 RectGrid Constructors + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| ``cd | Crea | +| ms.c | te | +| reat | a | +| eRec | grid | +| tGri | not | +| d(la | asso | +| t, l | ciat | +| on, | ed | +| orde | with | +| r, t | a | +| ype= | file | +| "gen | or | +| eric | data | +| ", m | set. | +| ask= | See | +| None | Tabl | +| )`` | e | +| | 2.2 | +| | on | +| | page | +| | 33. | ++------+------+ +| ``Cd | Crea | +| msFi | te | +| le.c | a | +| reat | grid | +| eRec | asso | +| tGri | ciat | +| d(id | ed | +| , la | with | +| t, l | a | +| on, | file | +| orde | . | +| r, t | See | +| ype= | Tabl | +| "gen | e | +| eric | 2.14 | +| ", m | on | +| ask= | page | +| None | 53. | +| )`` | | ++------+------+ +| ``Da | Crea | +| tase | te | +| t.cr | a | +| eate | grid | +| Rect | asso | +| Grid | ciat | +| (id, | ed | +| lat | with | +| , lo | a | +| n, o | data | +| rder | set. | +| , ty | See | +| pe=" | Tabl | +| gene | e | +| ric" | 2.25 | +| , ma | on | +| sk=N | page | +| one) | 71. | +| `` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eGau | 2.2 | +| ssia | on | +| nGri | page | +| d(nl | 33. | +| ats, | | +| xor | | +| igin | | +| =0.0 | | +| , or | | +| der= | | +| "yx" | | +| )`` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eGen | 2.2 | +| eric | on | +| Grid | page | +| (lat | 18. | +| Arra | | +| y, l | | +| onAr | | +| ray, | | +| lat | | +| Boun | | +| ds=N | | +| one, | | +| lon | | +| Boun | | +| ds=N | | +| one, | | +| ord | | +| er=" | | +| yx", | | +| mas | | +| k=No | | +| ne)` | | +| ` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eGlo | 2.2 | +| balM | on | +| eanG | page | +| rid( | 18. | +| grid | | +| )`` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eRec | 2.2 | +| tGri | on | +| d(la | page | +| t, l | 18. | +| on, | | +| orde | | +| r, t | | +| ype= | | +| "gen | | +| eric | | +| ", m | | +| ask= | | +| None | | +| )`` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eUni | 2.2 | +| form | on | +| Grid | page | +| (sta | 18. | +| rtLa | | +| t, n | | +| lat, | | +| del | | +| taLa | | +| t, s | | +| tart | | +| Lon, | | +| nlo | | +| n, d | | +| elta | | +| Lon, | | +| ord | | +| er=" | | +| yx", | | +| mas | | +| k=No | | +| ne)` | | +| ` | | ++------+------+ +| ``cd | See | +| ms.c | Tabl | +| reat | e | +| eZon | 2.2 | +| alGr | on | +| id(g | page | +| rid) | 18 | +| `` | | ++------+------+ + +Table 2.31 HorizontalGrid Methods + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeMethodDescription
+

Horizontal-Grid

+
clone() +

Return a transient copy of the grid.

+
AxisgetAxis(Integer n) +

Get the n-th axis.n is either 0 or 1.

+
TuplegetBounds() +

Get the grid boundary arrays.

+ +

Returns a tuple (latitudeArray, longitudeArray), where + latitudeArray is a Numeric array of latitude bounds, and similarly for + longitudeArray.The shape of latitudeArray and longitudeArray depend on the type + of grid:

+ +
    +
  • for rectangular grids with shape (nlat, nlon), the boundary arrays have + shape (nlat,2) and (nlon,2).
  • + +
  • for curvilinear grids with shape (nx, ny), the boundary arrays each have + shape (nx, ny, 4).
  • + +
  • for generic grids with shape (ncell,), the boundary arrays each have + shape (ncell, nvert) where nvert is the maximum number of vertices per + cell.
  • +
+ +

For rectilinear grids: If no boundary arrays are explicitly defined (in the + file or dataset), the result depends on the auto- Bounds mode (see + cdms.setAutoBounds) and the grid classification mode (see + cdms.setClassifyGrids). By default, autoBounds mode is enabled, in + which case the boundary arrays are generated based on the type of grid. If + disabled, the return value is (None,None).For rectilinear grids: The grid + classification mode specifies how the grid type is to be determined. By + default, the grid type (Gaussian, uniform, etc.) is determined by calling + grid.classifyInFamily. If the mode is 'off' + grid.getType is used instead.

+
AxisgetLatitude() +

Get the latitude axis of this grid.

+
AxisgetLongitude() +

Get the latitude axis of this grid.

+
AxisgetMask() +

Get the mask array of this grid, if any.Returns a 2-D Numeric array, having + the same shape as the grid. If the mask is not explicitly defined, the return + value is None.

+
AxisgetMesh(self, transpose=None) +

Generate a mesh array for the meshfill graphics method.If transpose is + defined to a tuple, say (1,0), first transpose latbounds and lonbounds + according to the tuple, in this case (1,0,2).

+
NonesetBounds(latBounds, lonBounds, persistent=0) +

Set the grid boundaries.latBounds is a NumPy array of shape + (n,2), such that the boundaries of the kth axis value are + [latBounds[k,0],latBounds[k,1] ]. lonBounds is + defined similarly for the longitude array. Note: By default, the + boundaries are not written to the file or dataset containing the grid (if any). + This allows bounds to be set on read-only files, for regridding. If the + optional argument persistent is set to 1, the boundary array is + written to the file.

+
NonesetMask(mask, persistent=0) +

Set the grid mask. If persistent == 1, the mask values are + written to the associated file, if any. Otherwise, the mask is associated with + the grid, but no I/O is generated. mask is a two-dimensional, + Boolean-valued Numeric array, having the same shape as the grid.

+
Horizontal-GridsubGridRegion(latInterval, lonInterval) +

Create a new grid corresponding to the coordinate region defined by + latInterval, lonInterval.

+ +

latInterval and lonInterval are the coordinate + intervals for latitude and longitude, respectively.

+ +

Each interval is a tuple having one of the forms:

+ +
    +
  • (x,y)
  • + +
  • (x,y,indicator)
  • + +
  • (x,y,indicator,cycle)
  • + +
  • None
  • +
+ +

where x and y are coordinates indicating the + interval [x,y), and:

+ +

indicator is a two-character string, where the + first character is 'c' if the interval is closed on the left, 'o' if open, and + the second character has the same meaning for the right-hand point. (Default: + 'co').

+ +

If cycle is specified, the axis is treated as circular + with the given cycle value. By default, if grid.isCircular() is + true, the axis is treated as circular with a default value of 360.0.

+ +

An interval of None returns the full index interval of the + axis.

+ +

If a mask is defined, the subgrid also has a mask corresponding to the index + ranges.Note: The result grid is not associated with any file or dataset.

+
+

Transient-CurveGrid

+
toCurveGrid(gridid=None) +

Convert to a curvilinear grid. If the grid is already curvilinear, a copy of + the grid object is returned. gridid is the string identifier of + the resulting curvilinear grid object. If unspecified, the grid ID is copied. + Note: This method does not apply to generic grids.

+
+

Transient-GenericGrid

+
toGenericGrid(gridid=None) +

Convert to a generic grid. If the grid is already generic, a copy of the + grid is returned. gridid is the string identifier of the resulting + curvilinear grid object. If unspecified, the grid ID is copied.

+
+ +Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeMethodDescription
StringgetOrder()Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if + longitude is the first axis.
StringgetType()Get the grid type, either "gaussian", "uniform", "equalarea", or + "generic".
(Array,Array)getWeights() +

Get the normalized area weight arrays, as a tuple (latWeights, + lonWeights). It is assumed that the latitude and longitude axes are + defined in degrees.

+ +

The latitude weights are defined as:

+ +

latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - + sin(latBounds[i]))

+ +

The longitude weights are defined as:

+ +

lonWeights[i] = abs(lonBounds[i+1] - lonBounds[i])/360.0

+ +

For a global grid, the weight arrays are normalized such that the sum of the + weights is 1.0

+ +

Example:

+ +

Generate the 2-D weights array, such that weights[i.j] is the + fractional area of grid zone [i,j].

+
+
+from cdms import MV latwts, lonwts = grid.getWeights() weights =
+MV.outerproduct(latwts, lonwts)
+
+.. raw:: html
+
+   
+ +:: + +

Also see the function area_weights in module + pcmdi.weighting.

+
NonesetType(gridtype)Set the grid type. gridtype is one of "gaussian", "uniform", + "equalarea", or "generic".
RectGridsubGrid((latStart,latStop),(lonStart,lonStop)) +

Create a new grid, with latitude index range [latStart : latStop] and + longitude index range [lonStart : lonStop]. Either index range can also be + specified as None, indicating that the entire range of the latitude or longitude + is used.

+ +

Example:

+ +

This creates newgrid corresponding to all latitudes and index range + [lonStart:lonStop] of oldgrid.

+ +

newgrid = oldgrid.subGrid(None, (lonStart, lonStop))

+ +

If a mask is defined, the subgrid also has a mask corresponding to the index + ranges.

+ +

Note: The result grid is not associated with any file or dataset.

+
RectGridtranspose() +

Create a new grid, with axis order reversed. The grid mask is also + transposed.

+ +

Note: The result grid is not associated with any file or dataset.

+
+ +2.11 Variable +^^^^^^^^^^^^^ + +A Variable is a multidimensional data object, consisting of: + +- a multidimensional data array, possibly masked, +- a collection of attributes +- a domain, an ordered tuple of CoordinateAxis objects. + +A Variable which is contained in a Dataset or CdmsFile is called a +persistent variable. Setting a slice of a persistent Variable writes +data to the Dataset or file, and referencing a Variable slice reads data +from the Dataset. Variables may also be transient, not associated with a +Dataset or CdmsFile. + +Variables support arithmetic operations, including the basic Python +operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations +defined in the MV module. The result of an arithmetic operation is a +transient variable, that is, the axis information is transferred to the +result. + +The methods subRegion and subSlice return transient variables. In +addition, a transient variable may be created with the +cdms.createVariable method. The vcs and regrid module methods take +advantage of the attribute, domain, and mask information in a transient +variable. + +Table 2.33 Variable Internal Attributes + + ++------+------+------+ +| Type | Name | Defi | +| | | niti | +| | | on | ++======+======+======+ +| Dict | ``at | Exte | +| iona | trib | rnal | +| ry | utes | attr | +| | `` | ibut | +| | | e | +| | | dict | +| | | iona | +| | | ry. | ++------+------+------+ +| Stri | ``id | Vari | +| ng | `` | able | +| | | iden | +| | | tifi | +| | | er. | ++------+------+------+ +| Stri | ``na | The | +| ng | me\_ | name | +| | in\_ | of | +| | file | the | +| | `` | vari | +| | | able | +| | | in | +| | | the | +| | | file | +| | | or | +| | | file | +| | | s | +| | | whic | +| | | h | +| | | repr | +| | | esen | +| | | t | +| | | the | +| | | data | +| | | set. | +| | | If | +| | | diff | +| | | eren | +| | | t | +| | | from | +| | | id, | +| | | the | +| | | vari | +| | | able | +| | | is | +| | | alia | +| | | sed. | ++------+------+------+ +| Data | ``pa | The | +| set | rent | data | +| or | `` | set | +| Cdms | | or | +| File | | file | +| | | whic | +| | | h | +| | | cont | +| | | ains | +| | | the | +| | | vari | +| | | able | +| | | . | ++------+------+------+ +| Tupl | ``sh | The | +| e | ape` | leng | +| | ` | th | +| | | of | +| | | each | +| | | axis | +| | | of | +| | | the | +| | | vari | +| | | able | ++------+------+------+ + +Table 2.34 Variable Constructors + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + +
ConstructorDescription
Dataset.createVariable(String id, String datatype, List axes)Create a Variable in a Dataset. This function is not yet implemented.
CdmsFile.createVariable(String id, String datatype, List + axesOr-Grids)Create a Variable in a CdmsFile. id is the name of the variable. + datatype is the MA or Numeric typecode, for example, MA.Float. + axesOrGrids is a list of Axis and/or Grid objects, on which the + variable is defined. Specifying a rectilinear grid is equivalent to listing the + grid latitude and longitude axes, in the order defined for the grid. **Note:** this + argument can either be a list or a tuple. If the tuple form is used, and there is + only one element, it must have a following comma, e.g.: + (axisobj,).
cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)
Create a transient variable, not associated with a file or dataset. + array is the data values: a Variable, masked array, or Numeric array. + typecode is the MA typecode of the array. Defaults to the typecode of + array. copy is an integer flag: if 1, the variable is created with a + copy of the array, if 0 the variable data is shared with array. + savespace is an integer flag: if set to 1, internal Numeric operations + will attempt to avoid silent upcasting. mask is an array of integers + with value 0 or 1, having the same shape as array. array elements with a + corresponding mask value of 1 are considered invalid, and are not used for + subsequent Numeric operations. The default mask is obtained from array if present, + otherwise is None. fill_value is the missing value flag. The default + is obtained from array if possible, otherwise is set to 1.0e20 for floating point + variables, 0 for integer-valued variables. grid is a rectilinear grid + object. axes is a tuple of axis objects. By default the axes are + obtained from array if present. Otherwise for a dimension of length n, the default + axis has values [0., 1., ..., double(n)]. attributes is a dictionary + of attribute values. The dictionary keys must be strings. By default the dictionary + is obtained from array if present, otherwise is empty. id is the + string identifier of the variable. By default the id is obtained from array if + possible, otherwise is set to 'variable_n' for some integer n.
+ +Table 2.35 Variable Methods + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + +
TypeMethodDefinition
Variabletvar = var[ i:j, m:n]Read a slice of data from the file or dataset, resulting in a transient + variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical + ordering defined in the dataset. The forms of the slice operator are listed in + Table 2.36 on page 102.
Nonevar[ i:j, m:n] = arrayWrite a slice of data to the external dataset. The forms of the slice operator + are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)
Variabletvar = var(selector)Calling a variable as a function reads the region of data defined by the + selector. The result is a transient variable, unless raw=1 keyword is specified. + See "Selectors" on page 103.
NoneassignValue(Array ar)Write the entire data array. Equivalent to var[:] = ar. (Variables + in CdmsFiles only).
Variableastype(typecode)Cast the variable to a new datatype. Typecodes are as for MV, MA, and Numeric + modules.
Variableclone(copyData=1) +

Return a copy of a transient variable.

+ +

If copyData is 1 (the default) the variable data is copied as well. If + copyData is 0, the result transient variable shares the original transient + variables data array.

+
Transient Variable
crossSectionRegrid(newLevel, newLatitude, method="log", missing=None, order=None)
+

Return a lat/level vertical cross-section regridded to a new set of latitudes + newLatitude and levels newLevel. The variable should be a function of latitude, + level, and (optionally) time.

+ +

newLevel is an axis of the result pressure levels.

+ +

newLatitude is an axis of the result latitudes.

+ +

method is optional, either "log" to interpolate in the log of + pressure (default), or "linear" for linear interpolation.

+ +

missing is a missing data value. The default is + var.getMissing()

+ +

order is an order string such as "tzy" or "zy". The default is + var.getOrder().

+ +

See also: regrid, pressureRegrid.

+
AxisgetAxis(n) +

Get the n-th axis.

+ +

n is an integer.

+
ListgetAxisIds()Get a list of axis identifiers.
IntegergetAxisIndex(axis_spec) +

Return the index of the axis specificed by axis_spec. Return -1 if no + match.

+ +

axis_spec is a specification as defined for getAxisList

+
ListgetAxisList(axes=None, omit=None, order=None) +

Get an ordered list of axis objects in the domain of the variable.

+ +

If axes is not None, include only certain axes. + Otherwise axes is a list of specifications as described below. Axes are returned + in the order specified unless the order keyword is given.

+ +

If omit is not None, omit those specified by an + integer dimension number. Otherwise omit is a list of specifications as described + below.

+ +

order is an optional string determining the output order.

+ +

Specifications for the axes or omit keywords are a list, each element having + one of the following forms:

+ +
    +
  • an integer dimension index, starting at 0.
  • + +
  • a string representing an axis id or one of the strings 'time', 'latitude', + 'lat', 'longitude', 'lon', 'lev' or 'level'.
  • + +
  • a function that takes an axis as an argument and returns a value. If the + value returned is true, the axis matches.
  • + +
  • an axis object; will match if it is the same object as axis.
  • +
+ +

order can be a string containing the characters t,x,y,z, or -. If + a dash ('-') is given, any elements of the result not chosen otherwise are filled + in from left to right with remaining candidates.

+
ListgetAxisListIndex(axes=None, omit=None, order=None)Return a list of indices of axis objects. Arguments are as for + getAxisList.
ListgetDomain()Get the domain. Each element of the list is itself a tuple of the form + (axis,start,length,true_length) where axis is an axis object, start is + the start index of the domain relative to the axis object, length is the length of + the axis, and true_length is the actual number of (defined) points in the domain. + See also: getAxisList.
Horizontal-GridgetGrid()Return the associated grid, or None if the variable is not + gridded.
AxisgetLatitude()Get the latitude axis, or None if not found.
AxisgetLevel()Get the vertical level axis, or None if not found.
AxisgetLongitude()Get the longitude axis, or None if not found.
VariousgetMissing()Get the missing data value, or None if not found.
StringgetOrder() +

Get the order string of a spatio-temporal variable. The order string specifies + the physical ordering of the data. It is a string of characters with length equal + to the rank of the variable, indicating the order of the variable's time, level, + latitude, and/or longitude axes. Each character is one of:

+ +
    +
  • 't': time
  • + +
  • 'z': vertical level
  • + +
  • 'y': latitude
  • + +
  • 'x': longitude
  • + +
  • '-': the axis is not spatio-temporal.
  • +
+ +

Example:

+ +

A variable with ordering "tzyx" is 4-dimensional, where the ordering of axes + is (time, level, latitude, longitude).

+ +

Note: The order string is of the form required for the order argument + of a regridder function.

+
ListgetPaths(*intervals) +

Get the file paths associated with the index region specified by + intervals.

+ +

intervals is a list of scalars, 2-tuples representing [i,j), + slices, and/or Ellipses. If no argument(s) are present, all file + paths associated with the variable are returned.

+ +

Returns a list of tuples of the form (path,slicetuple), where path is the path + of a file, and slicetuple is itself a tuple of slices, of the same length as the + rank of the variable, representing the portion of the variable in the file + corresponding to intervals.

+ +

Note: This function is not defined for transient variables.

+
AxisgetTime()Get the time axis, or None if not found.
Integerlen(var) +

The length of the first dimension of the variable. If the variable is + zero-dimensional (scalar), a length of 0 is returned.

+ +

Note: size() returns the total number of elements.

+
Transient VariablepressureRegrid (newLevel, method="log", missing=None, + order=None) +

Return the variable regridded to a new set of pressure levels newLevel. The + variable must be a function of latitude, longitude, pressure level, and + (optionally) time.

+ +

newLevel is an axis of the result pressure levels.

+ +

method is optional, either "log" to interpolate in the log of + pressure (default), or "linear" for linear interpolation.

+ +

missing is a missing data value. The default is + var.getMissing()

+ +

order is an order string such as "tzyx" or "zyx". The default is + var.getOrder()

+ +

See also: regrid, crossSectionRegrid.

+
Integerrank()The number of dimensions of the variable.
Transient +
+
+regrid (togrid, missing=None, order=None, Variable mask=None)
+
+.. raw:: html
+
+   
+ +:: + +
+

Return the variable regridded to the horizontal grid togrid.

+ +

missing is a Float specifying the missing data value. The default + is 1.0e20.

+ +

order is a string indicating the order of dimensions of the + array. It has the form returned from variable.getOrder(). For + example, the string "tzyx" indicates that the dimension order of array is (time, + level, latitude, longitude). If unspecified, the function assumes that the last + two dimensions of array match the input grid.

+ +

mask is a Numeric array, of datatype Integer or Float, consisting + of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data + value is to be ignored for purposes of regridding. If mask is two-dimensional of + the same shape as the input grid, it overrides the mask of the input grid. If the + mask has more than two dimensions, it must have the same shape as array. In this + case, the missing data value is also ignored. Such an n-dimensional mask is + useful if the pattern of missing data varies with level (e.g., ocean data) or + time. Note: If neither missing or mask is set, the default mask is obtained from + the mask of the array if any.

+ +

See also: crossSectionRegrid, pressureRegrid.

+
NonesetAxis(n, axis)Set the n-th axis (0-origin index) of to a copy of axis.
NonesetAxisList(axislist)Set all axes of the variable. axislist is a list of axis objects.
NonesetMissing(value)Set the missing value.
Integersize()Number of elements of the variable.
Variable +
+
+subRegion(\*region, time=None, level=None, latitude=None,
+longitude=None, squeeze=0, raw=0)
+
+.. raw:: html
+
+   
+ +:: + +
+

Read a coordinate region of data, returning a transient variable. A region is + a hyperrectangle in coordinate space.

+ +

region is an argument list, each item of which specifies an + interval of a coordinate axis. The intervals are listed in the order of the + variable axes. If trailing dimensions are omitted, all values of those dimensions + are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is + specified (see below), then data will be read with wraparound in that dimension. + Only one axis may be read with wraparound. A coordinate interval has one of the + forms listed in Table 2.37 on page 102. Also see + axis.mapIntervalExt.

+ +

The optional keyword arguments time, level, + latitude, and longitude may also be used to specify the + dimension for which the interval applies. This is particularly useful if the + order of dimensions is not known in advance. An exception is raised if a keyword + argument conflicts with a positional region argument.

+ +

The optional keyword argument squeeze determines whether or not + the shape of the returned array contains dimensions whose length is 1; by default + this argument is 0, and such dimensions are not 'squeezed out'.

+ +

The optional keyword argument raw specifies whether the return + object is a variable or a masked array. By default, a transient variable is + returned, having the axes and attributes corresponding to2,3 the region read. If + raw=1, an MA masked array is returned, equivalent to the transient variable + without the axis and attribute information.

+
Variable +
+
+subSlice(\*specs, time=None, level=None, latitude=None, longitude=None,
+squeeze=0, raw=0)
+
+.. raw:: html
+
+   
+ +:: + +
+

Read a slice of data, returning a transient variable. This is a functional + form of the slice operator [] with the squeeze option turned off.

+ +

specs is an argument list, each element of which specifies a + slice of the corresponding dimension. There can be zero or more positional + arguments, each of the form:

+ +
    +
  • a single integer n, meaning slice(n, n+1)
  • + +
  • an instance of the slice class
  • + +
  • a tuple, which will be used as arguments to create a slice
  • + +
  • ':', which means a slice covering that entire dimension
  • + +
  • Ellipsis (...), which means to fill the slice list with ':' leaving only + enough room at the end for the remaining positional arguments
  • + +
  • a Python slice object, of the form slice(i,j,k)
  • +
+ +

If there are fewer slices than corresponding dimensions, all values of the + trailing dimensions are read.

+ +

The keyword arguments are defined as in subRegion.

+ +

There must be no conflict between the positional arguments and the + keywords.

+ +

In (a)-(c) and (f), negative numbers are treated as offsets from + the end of that dimension, as in normal Python indexing.

+
Stringtypecode()The Numeric datatype identifier.
+ +**Example:** Get a region of data. + +Variable ta is a function of (time, latitude, longitude). Read data +corresponding to all times, latitudes -45.0 up to but not +including+45.0, longitudes 0.0 through and including longitude 180.0: + +{% highlight python %} data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, +180.0)) {% endhighlight %} + +or equivalently: + +{% highlight python %} data = ta.subRegion(latitude=(-45.0,45.0,'co'), +longitude=(0.0, 180.0) {% endhighlight %} + +Read all data for March, 1980: + +{% highlight python %} data = +ta.subRegion(time=('1980-3','1980-4','co')) {% endhighlight %} + +Table 2.36 Variable Slice Operators + + ++-------------------+---------------------------------------------------------------+ +| Operator | Description | ++===================+===============================================================+ +| ``[i]`` | The ith element, zero-origin indexing. | ++-------------------+---------------------------------------------------------------+ +| ``[i:j]`` | The ith element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[i:]`` | The ith element through the end | ++-------------------+---------------------------------------------------------------+ +| ``[:j]`` | The beginning element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[:]`` | The entire array | ++-------------------+---------------------------------------------------------------+ +| ``[i:j:k]`` | Every kth element | ++-------------------+---------------------------------------------------------------+ +| ``[i:j, m:n]`` | Multidimensional slice | ++-------------------+---------------------------------------------------------------+ +| ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | ++-------------------+---------------------------------------------------------------+ +| ``[-1]`` | Negative indices 'wrap around'. -1 is the last element | ++-------------------+---------------------------------------------------------------+ + +Table 2.37 Index and Coordinate Intervals + + ++------+------+------+ +| Inte | Exam | Exam | +| rval | ple | ple | +| Defi | Inte | | +| niti | rval | | +| on | Defi | | +| | niti | | +| | on | | ++======+======+======+ +| ``x` | sing | ``18 | +| ` | le | 0.0` | +| | poin | `\ \ | +| | t, | ``c | +| | such | dtim | +| | that | e.re | +| | axis | ltim | +| | [i]= | e(48 | +| | =x | ,"ho | +| | In | ur s | +| | gene | sin | +| | ral | ce 1 | +| | x is | 980- | +| | a | 1")` | +| | scal | `\ \ | +| | ar. | ``' | +| | If | 1980 | +| | the | -1-3 | +| | axis | '`` | +| | is a | | +| | time | | +| | axis | | +| | , | | +| | x | | +| | may | | +| | also | | +| | be a | | +| | cdti | | +| | me | | +| | rela | | +| | tive | | +| | time | | +| | type | | +| | , | | +| | comp | | +| | onen | | +| | t | | +| | time | | +| | type | | +| | , | | +| | or | | +| | stri | | +| | ng | | +| | of | | +| | the | | +| | form | | +| | 'yyy | | +| | y-mm | | +| | -dd | | +| | hh:m | | +| | i:ss | | +| | ' | | +| | (whe | | +| | re | | +| | trai | | +| | ling | | +| | fiel | | +| | ds | | +| | of | | +| | the | | +| | stri | | +| | ng | | +| | may | | +| | be | | +| | omit | | +| | ted. | | ++------+------+------+ +| ``(x | indi | ``(- | +| ,y)` | ces | 180, | +| ` | i | 180) | +| | such | `` | +| | that | | +| | x ≤ | | +| | axis | | +| | [i] | | +| | ≤ y | | ++------+------+------+ +| ``(x | ``x | ``(- | +| ,y,' | ≤ ax | 90,9 | +| co') | is[i | 0,'c | +| `` | ] < | c')` | +| | y``. | ` | +| | The | | +| | thir | | +| | d | | +| | item | | +| | is | | +| | defi | | +| | ned | | +| | as | | +| | in | | +| | mapI | | +| | nter | | +| | val. | | ++------+------+------+ +| ``(x | ``x | ``( | +| ,y,' | ≤ ax | 180, | +| co', | is[i | 180 | +| cycl | ]< y | , 'c | +| e)`` | ``, | o', | +| | with | 360. | +| | wrap | 0)`` | +| | arou | | +| | nd | | +| | **No | | +| | te:* | | +| | * | | +| | It | | +| | is | | +| | not | | +| | nece | | +| | sary | | +| | to | | +| | spec | | +| | ify | | +| | the | | +| | cycl | | +| | e | | +| | of a | | +| | circ | | +| | ular | | +| | long | | +| | itud | | +| | e | | +| | axis | | +| | , | | +| | that | | +| | is, | | +| | for | | +| | whic | | +| | h | | +| | ``ax | | +| | is.i | | +| | sCir | | +| | cula | | +| | r()` | | +| | ` | | +| | is | | +| | true | | +| | . | | ++------+------+------+ +| ``sl | slic | ``sl | +| ice( | e | ice( | +| i,j, | obje | 1,10 | +| k)`` | ct, | )``\ | +| | equi | \ ` | +| | vale | `sli | +| | nt | ce(, | +| | to | ,-1) | +| | i:j: | `` | +| | k | reve | +| | in a | rses | +| | slic | the | +| | e | dire | +| | oper | ctio | +| | ator | n | +| | . | of | +| | Refe | the | +| | rs | axis | +| | to | . | +| | the | | +| | indi | | +| | ces | | +| | i, | | +| | i+k, | | +| | i+2k | | +| | , | | +| | ... | | +| | up | | +| | to | | +| | but | | +| | not | | +| | incl | | +| | udin | | +| | g | | +| | inde | | +| | x | | +| | j. | | +| | If i | | +| | is | | +| | not | | +| | spec | | +| | ifie | | +| | d | | +| | or | | +| | is | | +| | None | | +| | it | | +| | defa | | +| | ults | | +| | to | | +| | 0. | | +| | If j | | +| | is | | +| | not | | +| | spec | | +| | ifie | | +| | d | | +| | or | | +| | is | | +| | None | | +| | it | | +| | defa | | +| | ults | | +| | to | | +| | the | | +| | leng | | +| | th | | +| | of | | +| | the | | +| | axis | | +| | . | | +| | The | | +| | stri | | +| | de | | +| | k | | +| | defa | | +| | ults | | +| | to | | +| | 1. k | | +| | may | | +| | be | | +| | nega | | +| | tive | | +| | . | | ++------+------+------+ +| ``': | all | | +| '`` | axis | | +| | valu | | +| | es | | +| | of | | +| | one | | +| | dime | | +| | nsio | | +| | n | | ++------+------+------+ +| ``El | all | | +| lips | valu | | +| is`` | es | | +| | of | | +| | all | | +| | inte | | +| | rmed | | +| | iate | | +| | axes | | ++------+------+------+ + +2.11.1 Selectors +'''''''''''''''' + +A selector is a specification of a region of data to be selected from a +variable. For example, the statement + +{% highlight python %} x = v(time='1979-1-1', level=(1000.0,100.0)) {% +endhighlight %} + +means 'select the values of variable v for time '1979-1-1' and levels +1000.0 to 100.0 inclusive, setting x to the result.' Selectors are +generally used to represent regions of space and time. + +The form for using a selector is + +{% highlight python %} result = v(s) {% endhighlight %} + +where v is a variable and s is the selector. An equivalent form is + +{% highlight python %} result = f('varid', s) {% endhighlight %} + +where f is a file or dataset, and 'varid' is the string ID of a +variable. + +A selector consists of a list of selector components. For example, the +selector + +{% highlight python %} time='1979-1-1', level=(1000.0,100.0) {% +endhighlight %} + +has two components: time='1979-1-1', and level=(1000.0,100.0). This +illustrates that selector components can be defined with keywords, using +the form: + +{% highlight python %} keyword=value {% endhighlight %} + +Note that for the keywords time, level, latitude, and longitude, the +selector can be used with any variable. If the corresponding axis is not +found, the selector component is ignored. This is very useful for +writing general purpose scripts. The required keyword overrides this +behavior. These keywords take values that are coordinate ranges or index +ranges as defined in Table 2.37 on page 102. + +The following keywords are available: Another form of selector +components is the positional form, where the component order corresponds +to the axis order of a variable. For example: + +Table 2.38 Selector keywords + + ++------+------+------+ +| Keyw | Desc | Valu | +| ord | ript | e | +| | ion | | ++======+======+======+ +| ``ax | Rest | See | +| isid | rict | Tabl | +| `` | the | e | +| | axis | 2.37 | +| | with | on | +| | ID | page | +| | axis | 102 | +| | id | | +| | to a | | +| | valu | | +| | e | | +| | or | | +| | rang | | +| | e | | +| | of | | +| | valu | | +| | es. | | ++------+------+------+ +| ``gr | Regr | Grid | +| id`` | id | obje | +| | the | ct | +| | resu | | +| | lt | | +| | to | | +| | the | | +| | grid | | +| | . | | ++------+------+------+ +| ``la | Rest | See | +| titu | rict | Tabl | +| de`` | lati | e | +| | tude | 2.37 | +| | valu | on | +| | es | page | +| | to a | 102 | +| | valu | | +| | e | | +| | or | | +| | rang | | +| | e. | | +| | Shor | | +| | t | | +| | form | | +| | : | | +| | lat | | ++------+------+------+ +| ``le | Rest | See | +| vel` | rict | Tabl | +| ` | vert | e | +| | ical | 2.37 | +| | leve | on | +| | ls | page | +| | to a | 102 | +| | valu | | +| | e | | +| | or | | +| | rang | | +| | e. | | +| | Shor | | +| | t | | +| | form | | +| | : | | +| | lev | | ++------+------+------+ +| ``lo | Rest | See | +| ngit | rict | Tabl | +| ude` | long | e | +| ` | itud | 2.37 | +| | e | on | +| | valu | page | +| | es | 102 | +| | to a | | +| | valu | | +| | e | | +| | or | | +| | rang | | +| | e. | | +| | Shor | | +| | t | | +| | form | | +| | : | | +| | lon | | ++------+------+------+ +| ``or | Reor | Orde | +| der` | der | r | +| ` | the | stri | +| | resu | ng, | +| | lt. | e.g. | +| | | , | +| | | "tzy | +| | | x" | ++------+------+------+ +| ``ra | Retu | 0: | +| w`` | rn | retu | +| | a | rn | +| | mask | a | +| | ed | tran | +| | arra | sien | +| | y | t | +| | (MA. | vari | +| | arra | able | +| | y) | (def | +| | rath | ault | +| | er | ); | +| | than | =1: | +| | a | retu | +| | tran | rn | +| | sien | a | +| | t | mask | +| | vari | ed | +| | able | arra | +| | . | y. | ++------+------+------+ +| ``re | Requ | List | +| quir | ire | of | +| ed`` | that | axis | +| | the | iden | +| | axis | tifi | +| | IDs | ers. | +| | be | | +| | pres | | +| | ent. | | ++------+------+------+ +| ``sq | Remo | 0: | +| ueez | ve | leav | +| e`` | sing | e | +| | leto | sing | +| | n | leto | +| | dime | n | +| | nsio | dime | +| | ns | nsio | +| | from | ns | +| | the | (def | +| | resu | ault | +| | lt. | ); | +| | | 1: | +| | | remo | +| | | ve | +| | | sing | +| | | leto | +| | | n | +| | | dime | +| | | nsio | +| | | ns. | ++------+------+------+ +| ``ti | Rest | See | +| me`` | rict | Tabl | +| | time | e | +| | valu | 2.37 | +| | es | on | +| | to a | page | +| | valu | 10 | +| | e | | +| | or | | +| | rang | | +| | e. | | ++------+------+------+ + +Another form of selector components is the positional form, where the +component order corresponds to the axis order of a variable. For +example: + +{% highlight python %} x9 = hus(('1979-1-1','1979-2-1'),1000.0) {% +endhighlight %} + +reads data for the range ('1979-1-1','1979-2-1') of the first axis, and +coordinate value 1000.0 of the second axis. Non-keyword arguments of the +form(s) listed in Table 2.37 on page 102 are treated as positional. Such +selectors are more concise, but not as general or flexible as the other +types described in this section. + +Selectors are objects in their own right. This means that a selector can +be defined and reused, independent of a particular variable. Selectors +are constructed using the cdms.selectors.Selector class. The constructor +takes an argument list of selector components. For example: + +{% highlight python %} from cdms.selectors import Selector sel = +Selector(time=('1979-1-1','1979-2-1'), level=1000.) x1 = v1(sel) x2 = +v2(sel) {% endhighlight %} + +For convenience CDMS provides several predefined selectors, which can be +used directly or can be combined into more complex selectors. The +selectors time, level, latitude, longitude, and required are equivalent +to their keyword counterparts. For example: + +{% highlight python %} from cdms import time, level x = +hus(time('1979-1-1','1979-2-1'), level(1000.)) {% endhighlight %} + +and + +{% highlight python %} x = hus(time=('1979-1-1','1979-2-1'), +level=1000.) {% endhighlight %} + +are equivalent. Additionally, the predefined selectors +``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` +take arguments ``(startindex, stopindex[, stride])``: + +{% highlight python %} from cdms import timeslice, levelslice x = +v(timeslice(0,2), levelslice(16,17)) {% endhighlight %} + +Finally, a collection of selectors is defined in module cdutil.region: + +{% highlight python %} from cdutil.region import \* +NH=NorthernHemisphere=domain(latitude=(0.,90.) +SH=SouthernHemisphere=domain(latitude=(-90.,0.)) +Tropics=domain(latitude=(-23.4,23.4)) +NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) +SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) {% endhighlight %} + +Selectors can be combined using the & operator, or by refining them in +the call: + +{% highlight python %} from cdms.selectors import Selector from cdms +import level sel2 = Selector(time=('1979-1-1','1979-2-1')) sel3 = sel2 & +level(1000.0) x1 = hus(sel3) x2 = hus(sel2, level=1000.0) {% +endhighlight %} + +2.11.2 Selector examples +'''''''''''''''''''''''' + +CDMS provides a variety of ways to select or slice data. In the +following examples, variable hus is contained in file sample.nc, and is +a function of (time, level, latitude, longitude). Time values are +monthly starting at 1979-1-1. There are 17 levels, the last level being +1000.0. The name of the vertical level axis is 'plev'. All the examples +select the first two times and the last level. The last two examples +remove the singleton level dimension from the result array. + +{% highlight python %} import cdms f = cdms.open('sample.nc') hus = +f.variables['hus'] + +Keyword selection +================= + +x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + +Interval indicator (see mapIntervalExt) +======================================= + +x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) + +Axis ID (plev) as a keyword +=========================== + +x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + +Positional +========== + +x9 = hus(('1979-1-1','1979-2-1'),1000.0) + +Predefined selectors +==================== + +from cdms import time, level x = hus(time('1979-1-1','1979-2-1'), +level(1000.)) + +from cdms import timeslice, levelslice x = hus(timeslice(0,2), +levelslice(16,17)) + +Call file as a function +======================= + +x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + +Python slices +============= + +x = hus(time=slice(0,2), level=slice(16,17)) + +Selector objects +================ + +from cdms.selectors import Selector sel = +Selector(time=('1979-1-1','1979-2-1'), level=1000.) x = hus(sel) + +sel2 = Selector(time=('1979-1-1','1979-2-1')) sel3 = sel2 & +level(1000.0) x = hus(sel3) x = hus(sel2, level=1000.0) + +Squeeze singleton dimension (level) +=================================== + +x = hus[0:2,16] x = hus(time=('1979-1-1','1979-2-1'), level=1000., +squeeze=1) + +f.close() {% endhighlight %} + +2.12 Examples +^^^^^^^^^^^^^ + +2.12.1 Example 1 +'''''''''''''''' + +In this example, two datasets are opened, containing surface air +temperature ('tas') and upper-air temperature ('ta') respectively. +Surface air temperature is a function of (time, latitude, longitude). +Upper-air temperature is a function of (time, level, latitude, +longitude). Time is assumed to have a relative representation in the +datasets (e.g., with units 'months since basetime'). + +Data is extracted from both datasets for January of the first input year +through December of the second input year. For each time and level, +three quantities are calculated: slope, variance, and correlation. The +results are written to a netCDF file. For brevity, the functions +``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. + +{% highlight python %} 1. import cdms import MV + +:: + + # Calculate variance, slope, and correlation of + # surface air temperature with upper air temperature + # by level, and save to a netCDF file. 'pathTa' is the location of + # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + # Data is extracted from January of year1 through December of year2. + def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): + + # Open the files for ta and tas + fta = cdms.open(pathTa) + ftas = cdms.open(pathTas) + +2. :: + + #Get upper air temperature + taObj = fta['ta'] + levs = taObj.getLevel() + + #Get the surface temperature for the closed interval [time1,time2] + tas = ftas('tas', time=(month1,month2,'cc')) + + # Allocate result arrays + newaxes = taObj.getAxisList(omit='time') + newshape = tuple([len(a) for a in newaxes]) + cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + + # Remove seasonal cycle from surface air temperature + tas = removeSeasonalCycle(tas) + + # For each level of air temperature, remove seasonal cycle + # from upper air temperature, and calculate statistics + +3. :: + + for ilev in range(len(levs)): + + ta = taObj(time=(month1,month2,'cc'), \ + level=slice(ilev, ilev+1), squeeze=1) + ta = removeSeasonalCycle(ta) + cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + + # Write slope, correlation, and variance variables + +4. :: + + f = cdms.open('CC_B_V_ALL.nc','w') + f.title = filtered + f.write(b) + f.write(cc) + f.write(v) + f.close() + +5. if **name**\ =='**main**': pathTa = + '/pcmdi/cdms/sample/ccmSample\_ta.xml' pathTas = + '/pcmdi/cdms/sample/ccmSample\_tas.xml' + # Process Jan80 through Dec81 + ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') {% + endhighlight %} + +**Notes:** + +1. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements + arithmetic functions. +2. ``taObj`` is a file (persistent) variable. At this point, no data has + actually been read. This happens when the file variable is sliced, or + when the subRegion function is called. levs is an axis. +3. Calling the file like a function reads data for the given variable + and time range. Note that month1 and month2 are time strings. +4. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are + transient variables, not associated with a file. The assigned names + are used when the variables are written. +5. Another way to read data is to call the variable as a function. The + squeeze option removes singleton axes, in this case the level axis. +6. Write the data. Axis information is written automatically. +7. This is the main routine of the script. ``pathTa`` and ``pathTas`` + pathnames. Data is processed from January 1980 through December 1981. + +2.12.2 Example 2 +'''''''''''''''' + +In the next example, the pointwise variance of a variable over time is +calculated, for all times in a dataset. The name of the dataset and +variable are entered, then the variance is calculated and plotted via +the vcs module. + +{% highlight python %} #!/usr/bin/env python # # Calculates gridpoint +total variance # from an array of interest # + +:: + + import cdms + from MV import * + + # Wait for return in an interactive window + + def pause(): + print Hit return to continue: , + line = sys.stdin.readline() + +1. :: + + # Calculate pointwise variance of variable over time + # Returns the variance and the number of points + # for which the data is defined, for each grid point + def calcVar(x): + # Check that the first axis is a time axis + firstaxis = x.getAxis(0) + if not firstaxis.isTime(): + raise 'First axis is not time, variable:', x.id + + n = count(x,0) + sumxx = sum(x*x) + sumx = sum(x) + variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + + return variance, n + + if __name__=='__main__': + import vcs, sys + + print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + path = string.strip(sys.stdin.readline()) + if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + +2. :: + + # Open the dataset + dataset = cdms.open(path) + + # Select a variable from the dataset + print 'Variables in file:',path + varnames = dataset.variables.keys() + varnames.sort() + for varname in varnames: + + var = dataset.variables[varname] + if hasattr(var,'long_name'): + long_name = var.long_name + elif hasattr(var,'title'): + long_name = var.title + else: + long_name = '?' + + print '%-10s: %s'%(varname,long_name) + print 'Select a variable: ', + +3. :: + + varname = string.strip(sys.stdin.readline()) + var = dataset(varname) + dataset.close() + + # Calculate variance, count, and set attributes + variance,n = calcVar(var) + variance.id = 'variance_%s'%var.id + n.id = 'count_%s'%var.id + if hasattr(var,'units'): + variance.units = '(%s)^2'%var.units + + # Plot variance + w=vcs.init() + +4. :: + + w.plot(variance) + pause() + w.clear() + w.plot(n) + pause() + w.clear() + + {% endhighlight %} + +The result of running this script is as follows: + +{% highlight pycon %} % calcVar.py Enter dataset path +[/pcmdi/cdms/sample/obs/erbs\_mo.xml]: + +Variables in file: /pcmdi/cdms/sample/obs/erbs\_mo.xml albt : Albedo TOA +[%] albtcs : Albedo TOA clear sky [%] rlcrft : LW Cloud Radiation +Forcing TOA [W/m^2] rlut : LW radiation TOA (OLR) [W/m^2] rlutcs : LW +radiation upward TOA clear sky [W/m^2] rscrft : SW Cloud Radiation +Forcing TOA [W/m^2] rsdt : SW radiation downward TOA [W/m^2] rsut : SW +radiation upward TOA [W/m^2] rsutcs : SW radiation upward TOA clear sky +[W/m^2] Select a variable: albt + +Hit return to continue: + + {% endhighlight %} + +**Notes:** + +1. n = count(x, 0) returns the pointwise number of valid values, summing + across axis 0, the first axis. count is an MV function. +2. dataset is a Dataset or CdmsFile object, depending on whether a .xml + or .nc pathname is entered. dataset.variables is a dictionary mapping + variable name to file variable. +3. var is a transient variable. +4. Plot the variance and count variables. Spatial longitude and latitude + information are carried with the computations, so the continents are + plotted correctly. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst new file mode 100644 index 00000000..41a55a3b --- /dev/null +++ b/docs/source/manual/cdms_3.rst @@ -0,0 +1,659 @@ +CHAPTER 3 cdtime Module +----------------------- + +3.1 Time types +^^^^^^^^^^^^^^ + +The ``cdtime`` module implements the CDMS time types, methods, and +calendars. These are made available with the command + +{% highlight python %} import cdtime {% endhighlight %} + +Two time types are available: relative time and component time. Relative +time is time relative to a fixed base time. It consists of: + +- a units string, of the form 'units since basetime', and +- a floating-point value + +For example, the time "28.0 days since 1996-1-1" has value=28.0, and +units='days since 1996-1-1' + +Component time consists of the integer fields year, month, day, hour, +minute, and the floating-point field second. A sample component time is +``1996-2-28 12:10:30.0`` + +The ``cdtime`` module contains functions for converting between these +forms, based on the common calendars used in climate simulation. Basic +arithmetic and comparison operators are also available. + +3.2 Calendars +^^^^^^^^^^^^^ + +A calendar specifies the number of days in each month, for a given year. +cdtime supports these calendars: + +- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap + years, except century years not evenly divisible by 400. This is + sometimes called the proleptic Gregorian calendar, meaning that the + algorithm for leap years applies for all years. +- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates + before 158210-15 are encoded with the Julian calendar, otherwise are + encoded with the Gregorian calendar. The day immediately following + 1582-10-4 is 1582-10-15. This is the default calendar. +- ``cdtime.JulianCalendar``: years evenly divisible by four are leap + years, +- ``cdtime.NoLeapCalendar``: all years have 365 days, +- ``cdtime.Calendar360``: all months have 30 days. + +Several ``cdtime`` functions have an optional calendar argument. The +default calendar is the ``MixedCalendar``. The default calendar may be +changed with the command: + +{% highlight python %} cdtime.DefaultCalendar = newCalendar {% +endhighlight %} + +3.3 Time Constructors +^^^^^^^^^^^^^^^^^^^^^ + +The following table describes the methods for creating time types. + +Table 3.1 Time Constructors + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeConstructorDefinition
Reltimecdtime.reltime(value, relunits) +

Create a relative time type.

+ +

value is an integer or floating point value.

+ +

relunits is a string of the form "unit(s) [since + basetime]" where

+ +

unit = [second | minute | hour | day | week | month | season | + year]

+ +

basetime has the form yyyy-mm-dd hh:mi:ss. The + default basetime is 1979-1-1, if no since clause is specified.

+ +

Example:

+ +

r = cdtime.reltime(28, "days since 1996-1-1")

+
Comptimecdtime.comptime(year, month=1, day=1, hour=0, minute=0, + second=0.0) +

Create a component time type.

+ +

year is an integer.

+ +

month is an integer in the range 1 .. 12

+ +

day is an integer in the range 1 .. 31

+ +

hour is an integer in the range 0 .. 23

+ +

minute is an integer in the range 0 .. 59

+ +

second is a floating point number in the range 0.0 ,, 60.0

+ +

Example:

+ +

c = cdtime.comptime(1996, 2, 28)

+
Comptime +

[Deprecated] cdtime.abstime(absvalue, + absunits)

+
+

Create a component time from an absolute time representation.

+ +

absvalue is a floating-point encoding of an absolute time.

+ +

absunits is the units template, a string of the form "unit + as format", where unit is one of second, minute, hour, + day, calendar_month, or calendar_year. format is + a string ofthe form "%x[%x[...] ][.%f]", where 'x' is + one of the formatletters 'Y' (year, including century), + 'm' (two digit month,01=January), 'd' (two-digit day + within month), 'H' (hourssince midnight), 'M' + (minutes), or 'S' (seconds ). The optional '.%f' + denotes a floating-point fraction of the unit.

+ +

Example:

+ +

c = cdtime.abstime(19960228.0, "day as %Y%m%d.%f")

+
+ +3.4 Relative Time +^^^^^^^^^^^^^^^^^ + +A relative time type has two members, value and units. Both can be set. + +Table 3.2 Relative Time Members + + ++----------+---------+-------------------------------------------------------+ +| Type | Name | Summary | ++==========+=========+=======================================================+ +| Float | value | Number of units | ++----------+---------+-------------------------------------------------------+ +| String | units | Relative units, of the form "unit(s) since basetime | ++----------+---------+-------------------------------------------------------+ + +3.5 Component Time +^^^^^^^^^^^^^^^^^^ + +A component time type has six members, all of which are settable. + +Table 3.3 Component Time Membersch3\_cdms\_4.0.html/#Table\_3.1 + + ++-----------+----------+--------------------------------------+ +| Type | Name | Summary | ++===========+==========+======================================+ +| Integer | year | Year value | ++-----------+----------+--------------------------------------+ +| Integer | month | Month, in the range 1..12 | ++-----------+----------+--------------------------------------+ +| Integer | day | Day of month, in the range 1 .. 31 | ++-----------+----------+--------------------------------------+ +| Integer | hour | Hour, in the range 0 .. 23 | ++-----------+----------+--------------------------------------+ +| Integer | minute | Minute, in the range 0 .. 59 | ++-----------+----------+--------------------------------------+ +| Float | second | Seconds, in the range 0.0 .. 60.0 | ++-----------+----------+--------------------------------------+ + +3.6 Time Methods +^^^^^^^^^^^^^^^^ + +The following methods apply both to relative and component times. + +Table 3.4 Time Methods + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + + + + .. raw:: html + +
TypeMethodDefinitionExamples
Comptime or Reltimet.add(value, intervalUnits, calendar=cdtime.Default-Calendar) +

Add an interval of time to a time type t. Returns the same type of time.

+

value is the Float number of interval units.

+

intervalUnits is

cdtime.[Second(s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]
+

calendar is the calendar type.

+
+
+
+            from cdtime import \* c = comptime(1996,2,28) r =
+            reltime(28,"days since 1996-1-1") print r.add(1,Day) 29.00
+            days since 1996-1-1 print c.add(36,Hours) 1996-2-29 12:0:0.0
+
+            .. raw:: html
+
+               
+ + .. raw:: html + +

+ + Note: When adding or subtracting intervals of months or + years, only the month and year of the result are + significant. The reason is that intervals in months/years + are not commensurate with intervals in days or fractional + days. This leads to results that may be surprising. For + example: + + .. raw:: html + +

+ + .. raw:: html + +
+               c = comptime(1979,8,31)
+               c.add(1,Month)
+               1979-9-1 0:0:0.0
+ + .. raw:: html + +

+ + In other words, the day component of c was ignored in the + addition, and the day/hour/minute components of the results + are just the defaults. If the interval is in years, the + interval is converted internally to months: + + .. raw:: html + +

+ + .. raw:: html + +
+               c = comptime(1979,8,31)
+               c.add(2,Years)
+               1981-8-1 0:0:0.0
+ + .. raw:: html + +
+ + Integer + + .. raw:: html + + + + t.cmp(t2, calendar=cdtime.DefaultCalendar) + + .. raw:: html + + + + .. raw:: html + +

+ + Compare time values t and t2. Returns -1, 0, 1 as t is less than, + equal to, or greater than t2 respectively. + + .. raw:: html + +

+ + .. raw:: html + +

+ + t2 is the time to compare. + + .. raw:: html + +

+ + .. raw:: html + +

+ + calendar is the calendar type. + + .. raw:: html + +

+ + .. raw:: html + +
+ + .. raw:: html + +
>>> from cdtime import *
+       >> r = cdtime.reltime(28,"days since 1996-1-1")
+       >> c = comptime(1996,2,28)
+       >> print r.cmp(c)
+       -1
+       >> print c.cmp(r)
+       1
+       >> print r.cmp(r)
+       0
+ + .. raw:: html + +
+ + Comptime or Reltime + + .. raw:: html + + + + t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar) + + .. raw:: html + + + + .. raw:: html + +

+ + Subtract an interval of time from a time type t. Returns the same + type of time. + + .. raw:: html + +

+ + .. raw:: html + +

+ + value is the Float number of interval units. + + .. raw:: html + +

+ + .. raw:: html + +

+ + intervalUnits is + + .. raw:: html + +

+ + .. raw:: html + +
cdtime.[Second(s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]
+ + .. raw:: html + +

+ + calendar is the calendar type. + + .. raw:: html + +

+ + .. raw:: html + +
+ + .. raw:: html + +
>>> from cdtime import *
+       >> r = cdtime.reltime(28,"days since 1996-1-1")
+       >> c = comptime(1996,2,28)
+       >> print r.sub(10,Days)
+       18.00 days since 1996-1-1
+       >> print c.sub(30,Days)
+       1996-1-29 0:0:0.0
+ + .. raw:: html + +

+ + For intervals of years or months, see the note under add(). + + .. raw:: html + +

+ + .. raw:: html + +
+ + Comptime + + .. raw:: html + + + + t.tocomp(calendar = cdtime.DefaultCalendar) + + .. raw:: html + + + + .. raw:: html + +

+ + Convert to component time. Returns the equivalent component time. + + .. raw:: html + +

+ + .. raw:: html + +

+ + calendar is the calendar type. + + .. raw:: html + +

+ + .. raw:: html + +
+ + .. raw:: html + +
>>> r = cdtime.reltime(28,"days since 1996-1-1")
+       >> r.tocomp()
+       1996-1-29 0:0:0.0
+ + .. raw:: html + +
+ + Reltime + + .. raw:: html + + + + t.torel(units, calendar=cdtime.DefaultCalendar) + + .. raw:: html + + + + Convert to relative time. Returns the equivalent relative time. + + .. raw:: html + + + + .. raw:: html + +
>>> c = comptime(1996,2,28)
+       >> print c.torel("days since 1996-1-1")
+       58.00 days since 1996-1-1
+       >> r = reltime(28,"days since 1996-1-1")
+       >> print r.torel("days since 1995")
+       393.00 days since 1995
+       >> print r.torel("days since 1995").value
+       393.0
+ + .. raw:: html + +
diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst new file mode 100644 index 00000000..1195379e --- /dev/null +++ b/docs/source/manual/cdms_4.rst @@ -0,0 +1,1282 @@ +CHAPTER 4 Regridding Data +------------------------- + +4.1 Overview +~~~~~~~~~~~~ + +CDMS provides several methods for interpolating gridded data: + +- from one rectangular, lat-lon grid to another (CDMS regridder) +- between any two lat-lon grids (SCRIP regridder) +- from one set of pressure levels to another +- from one vertical (lat/level) cross-section to another vertical + cross-section. + +4.1.1 CDMS horizontal regridr +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The simplest method to regrid a variable from one rectangular, lat/lon +grid to another is to use the regrid function defined for variables. +This function takes the target grid as an argument, and returns the +variable regridded to the target grid: + +{% highlight python %} >>> import cdms >>> f = +cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') >>> rlsf = f('rls') # +Read the data >>> rlsf.shape (4, 48, 96) + + g = cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') rlsg + = g['rls'] # Get the file variable (no data read) outgrid = + rlsg.getGrid() # Get the target grid rlsnew = + rlsf.regrid(outgrid) rlsnew.shape (4, 46, 72) outgrid.shape + (46, 72) + +{% endhighlight %} + +A somewhat more efficient method is to create a regridder function. This +has the advantage that the mapping is created only once and can be used +for multiple arrays. Also, this method can be used with data in the form +of an MA.MaskedArray or Numeric array. The steps in this process are: + +1. Given an input grid and output grid, generate a regridder function. +2. Call the regridder function on a Numeric array, resulting in an array + defined on the output grid. The regridder function can be called with + any array or variable defined on the input grid. + +The following example illustrates this process. The regridder function +is generated at line 9, and the regridding is performed at line 10: + +{% highlight python %} 1 #!/usr/bin/env python 2 import cdms 3 from +regrid import Regridder 4 f = +cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') 5 rlsf = f['rls'] 6 +ingrid = rlsf.getGrid() 7 g = +cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') 8 outgrid = +g['rls'].getGrid() 9 regridfunc = Regridder(ingrid, outgrid) + +10 rlsnew = regridfunc(rlsf) 11 f.close() 12 g.close() {% endhighlight +%} + +Line Notes + +**2** Makes the CDMS module available. + +**3** Makes the Regridder class available from the regrid module. + +**4** Opens the input dataset. + +**5** Gets the variable object named 'rls'. No data is read. + +**6** Gets the input grid. + +**7** Opens a dataset to retrieve the output grid. + +**8** The output grid is the grid associated with the variable named +'rls' in dataset g. Just the grid is retrieved, not the data. + +**9** Generates a regridder function regridfunc. + +**10** Reads all data for variable rlsf, and calls the regridder +function on that data, resulting in a transient variable rlsnew. + +4.1.2 SCRIP horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To interpolate between grids where one or both grids is non-rectangular, +CDMS provides an interface to the SCRIP regridder package developed at +Los Alamos National Laboratory (http://climate.lanl.gov/Software/ +SCRIP). Figure 3 illustrates the process: + +1. Obtain or generate the source and target grids in SCRIP netCDF + format. A CDMS grid can be written to a netCDF file, in SCRIP format, + using the write-ScripGrid method. +2. Edit the input namelist file scrip\_in to reference the grids and + select the method of interpolation, either conservative, bilinear, + bicubic, or distance-weighted. See the SCRIP documentation for + detailed instructions. +3. Run the scrip executable to generate a remapping file containing the + transformation coefficients. +4. CDMS, open the remapping file and create a regridder function with + the readRegridder method. +5. Call the regridder function on the input variable, defined on the + source grid. The return value is the variable interpolated to the new + grid. Note that the variable may have more than two dimensions. Also + note that the input arguments to the regridder function depend on the + type of regridder. For example, the bicubic interpolation has + additional arguments for the gradients of the variable. + +.. figure:: /images/regridding.jpg + :alt: Regridding + + Regridding + +FIGURE 3. Regridding data with SCRIP + + +**Example:** + +Regrid data from a T42 to POP4/3 grid, using the first-order, +conservative interpolator. + +In this example: + +- The input grid is defined in remap\_grid\_T42.nc. +- The output grid is defined in remap\_grid\_POP43.nc. +- The input data is variable src\_array in file sampleT42Grid.nc. +- The file scrip\_in has contents: + +{% highlight text %} &remap\_inputs num\_maps = 1 + +| grid1\_file = 'remap\_grid\_T42.nc' grid2\_file = + 'remap\_grid\_POP43.nc' interp\_file1 = + 'rmp\_T42\_to\_POP43\_conserv.nc' interp\_file2 = + 'rmp\_POP43\_to\_T42\_conserv.nc' map1\_name = 'T42 to POP43 + Conservative Mapping' +| map2\_name = 'POP43 to T42 Conservative Mapping' map\_method = + 'conservative' normalize\_opt = 'frac' output\_opt = 'scrip' + restrict\_type = 'latitude' num\_srch\_bins = 90 luse\_grid1\_area = + .false. luse\_grid2\_area = .false. / {% endhighlight %} + +``num_maps`` specifies the number of mappings generated, either 1 or 2. +For a single mapping, ``grid1_file`` and ``grid2_file`` are the source +and target grid definitions, respectively. The ``map_method`` specifies +the type of interpolation, either 'conservative', 'bilinear', 'bicubic', +or 'distwgt' (distanceweighted). The remaining parameters are described +in the SCRIP documentation. + +Once the grids and input file are defined, run the scrip executable to +generate the remapping file 'rmp\_T42\_to\_POP43\_conserv.nc' + +{% highlight text %} % scrip Using latitude bins to restrict search. +Computing remappings between: T42 Gaussian Grid and POP 4/3 +Displaced-Pole T grid grid1 sweep grid2 sweep Total number of links = +63112 {% endhighlight %} + +Next, run UV-CDAT and create the regridder: + +{% highlight python %} # Import regrid package for regridder functions +import regrid, cdms # Read the regridder from the remapper file remapf = +cdms.open('rmp\_T42\_to\_POP43\_conserv.nc') regridf = +regrid.readRegridder(remapf) remapf.close() {% endhighlight %} + +Then read the input data and regrid: + +{% highlight python %} # Get the source variable f = +cdms.open('sampleT42Grid.nc') t42dat = f('src\_array') f.close() # +Regrid the source variable popdat = regridf(dat) {% endhighlight %} + +Note that ``t42dat`` can have rank greater than 2. The trailing +dimensions must match the input grid shape. For example, if ``t42dat`` +has shape (12, 64, 128), then the input grid must have shape (64,128). +Similarly if the variable had a generic grid with shape (8092,), the +last dimension of the variable would have length 8092. + +4.1.3 Pressure-level regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To regrid a variable which is a function of latitude, longitude, +pressure level, and (optionally) time to a new set of pressure levels, +use the ``pressureRegrid`` function defined for variables. This function +takes an axis representing the target set of pressure levels, and +returns a new variable ``d`` regridded to that dimension. + +{% highlight pycon %} >>> var.shape (3, 16, 32) >>> var.getAxisIds() +['level', 'latitude', 'longitude'] >>> len(levout) 2 >>> result = +var.pressureRegrid(levout) >>> result.shape (2, 16, 32) {% endhighlight +%} + +4.1.4 Cross-section regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To regrid a variable which is a function of latitude, height, and +(optionally) time to a new latitude/height cross-section, use the +``crossSectionRegridder`` defined for variables. This function takes as +arguments the new latitudes and heights, and returns the variable +regridded to those axes. + +{% highlight python %} >>> varin.shape (11, 46) >>> varin.getAxisIds() +[’level’, ’latitude’] >>> levOut[:][ 10., 30., 50., 70., 100., 200., +300., 400., 500., 700., 850., 1000.,] >>> varout = +varin.crossSectionRegrid(levOut, latOut) >>> varout.shape (12, 64) {% +endhighlight %} + +4.2 regrid module +~~~~~~~~~~~~~~~~~ + +The ``regrid`` module implements the CDMS regridding functionality as +well as the SCRIP interface. Although this module is not strictly a part +of CDMS, it is designed to work with CDMS objects. + +4.2.1 CDMS horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Python command + +{% highlight python %} from regrid import Regridder {% endhighlight %} + +makes the CDMS Regridder class available within a Python program. An +instance of Regridder is a function which regrids data from rectangular +input to output grids. + +Table 4.1 CDMS Regridder Constructor + + ++------+------+ +| Cons | Desc | +| truc | ript | +| tor | ion | ++======+======+ +| regr | Crea | +| idFu | te | +| ncti | a | +| on | regr | +| = | idde | +| Regr | r | +| idde | func | +| r(in | tion | +| putG | whic | +| rid, | h | +| outp | inte | +| utGr | rpol | +| id) | ates | +| | a | +| | data | +| | arra | +| | y | +| | from | +| | inpu | +| | t | +| | to | +| | outp | +| | ut | +| | grid | +| | . | +| | `Tab | +| | le | +| | 4.3 | +| | <#Ta | +| | ble_ | +| | 4.3> | +| | `__ | +| | on | +| | page | +| | 131 | +| | desc | +| | ribe | +| | s | +| | the | +| | call | +| | ing | +| | sequ | +| | ence | +| | of | +| | this | +| | func | +| | tion | +| | . | +| | ``in | +| | putG | +| | rid` | +| | ` | +| | and | +| | ``ou | +| | tput | +| | Grid | +| | `` | +| | are | +| | CDMS | +| | grid | +| | obje | +| | cts. | +| | **No | +| | te:* | +| | * | +| | To | +| | set | +| | the | +| | mask | +| | asso | +| | ciat | +| | ed | +| | with | +| | inpu | +| | tGri | +| | d | +| | or | +| | outp | +| | utGr | +| | id, | +| | use | +| | the | +| | grid | +| | setM | +| | ask | +| | func | +| | tion | +| | . | ++------+------+ + +4.2.2 SCRIP Regridder +^^^^^^^^^^^^^^^^^^^^^ + +SCRIP regridder functions are created with the ``regrid.readRegridder`` +function: + +Table 4.2 SCRIP Regridder Constructor + + +.. raw:: html + + + +:: + + + + + + + + + + + + +.. raw:: html + +
ConstructorDescription
+
regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)
+
+

Read a regridder from an open CDMS file object.

+

fileobj is a CDMS file object, as returned from cdms.open.

+

mapMethod is one of

+
    +
  • 'conservative': conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved.
  • + +
  • 'bilinear': bilinear interpolation
  • + +
  • 'bicubic': bicubic interpolation
  • + +
  • 'distwgt': distance-weighted interpolation.
  • + +
+ +

It is only necessary to specify the map method if it is not defined in the file.

+

If checkGridis 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.

+ +4.3 Regridder Functions +~~~~~~~~~~~~~~~~~~~~~~~ + +It is only necessary to specify the map method if it is not defined in +the file. + +If ``checkGrid`` is 1 (default), the grid cells are checked for +convexity, and 'repaired' if necessary. Grid cells may appear to be +nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of +shifting the cell vertices to the same side modulo 360 degrees. + +4.3.1 CDMS regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A CDMS regridder function is an instance of the CDMS ``Regridder`` +class. The function is associated with rectangular input and output +grids. Typically its use is straightforward: the function is passed an +input array and returns the regridded array. However, when the array has +missing data, or the input and/or output grids are masked, the logic +becomes more complicated. + +Step 1: +''''''' + +The regridder function first forms an input mask. This mask is either +two-dimensional or n-dimensional, depending on the rank of the +user-supplied mask. If no mask or missing value is specified, the mask +is obtained from the data array mask if present. + +**Two-dimensional case:** + +- Let mask\_1 be the two-dimensional user mask supplied via the mask + argument, or the mask of the input grid if no user mask is specified. +- If a missing-data value is specified via the missing argument, let + the implicit\_mask be the two-dimensional mask defined as 0 where the + first horizontal slice of the input array is missing, 1 elsewhere. +- The input mask is the logical AND(mask\_1, implicit\_mask) + +**N-dimensional case:** + +- If the user mask is 3 or 4-dimensional with the same shape as the + input array, it is used as the input mask. + +Step 2: +''''''' + +The data is then regridded. In the two-dimensional case, the input mask +is 'broadcast' across the other dimensions of the array. In other words, +it assumes that all horizontal slices of the array have the same mask. +The result is a new array, defined on the output grid. Optionally, the +regridder function can also return an array having the same shape as the +output array, defining the fractional area of the output array which +overlaps a non-missing input grid cell. This is useful for calculating +area-weighted means of masked data. + +Step 3: +''''''' + +Finally, if the output grid has a mask, it is applied to the result +array. Where the output mask is 0, data values are set to the missing +data value, or 1.0e20 if undefined. The result array or transient +variable will have a mask value of 1 (invalid value) for those output +grid cells which completely overlap input grid cells with missing values + +Table 4.3 CDMS Regridder function + + +.. raw:: html + + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + +.. raw:: html + + + +.. raw:: html + +
TypeFunctionDescription
Array or Transient-VariableregridFunction(array, missing=None, order=None,mask=None) +

Interpolate a gridded data array to a new grid. The interpolation preserves the area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the input array is returned, otherwise a masked array is returned.

+

arrayis a Variable, masked array, or Numeric array of rank 2, 3, or 4.

+

For example, the string “tzyx” indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid.

+

missing is a Float specifying the missing data value. The default is 1.0e20.

+

order is a string indicating the order of dimensions of the array. It has the form returned from variable.getOrder().

+

mask is a Numeric array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MA module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the returnTuple argument.

+

If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. +

+

Array, Array

+
+ regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1) + +

If called with the optional returnTuple argument equal to 1, the function returns a tuple (dataArray, maskArray).

+

dataArray is the result data array.

+

maskArray is a Float32 array of the same shape as dataArray, such that maskArray[i,j] is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid.

+
+ +4.3.2 SCRIP Regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A SCRIP regridder function is an instance of the ScripRegridder class. +Such a function is created by calling the regrid.readRegridder method. +Typical usage is straightforward: + +{% highlight pycon %} >>> regridf = regrid.readRegridder(remap\_file) +>>> outdat = regridf(indat) {% endhighlight %} + +The bicubic regridder takes four arguments: + +{% highlight pycon %} >>> outdat = regridf(indat, gradlat, gradlon, +gradlatlon) {% endhighlight %} + +A regridder function also has associated methods to retrieve the +following fields: + +- Input grid +- Output grid +- Source fraction: the fraction of each source (input) grid cell + participating in the interpolation. +- Destination fraction: the fraction of each destination (output) grid + cell participating in the interpolation. + +In addition, a conservative regridder has the associated grid cell areas +for source and target grids. + +Table 4.4 SCRIP Regridder functions + + ++------+------+------+ +| Retu | Meth | Desc | +| rn | od | ript | +| Type | | ion | ++======+======+======+ +| Arra | [con | Inte | +| y | serv | rpol | +| or | ativ | ate | +| Tran | e, | a | +| sien | bili | grid | +| t-Va | near | ded | +| riab | , | data | +| le | and | arra | +| | dist | y | +| | ance | to a | +| | -wei | new | +| | ghte | grid | +| | d | . | +| | regr | The | +| | idde | retu | +| | rs] | rn | +| | ``re | valu | +| | grid | e | +| | Func | is | +| | tion | the | +| | (arr | regr | +| | ay)` | idde | +| | ` | d | +| | | data | +| | | vari | +| | | able | +| | | . | +| | | ``ar | +| | | ray` | +| | | ` | +| | | is a | +| | | Vari | +| | | able | +| | | , | +| | | Mask | +| | | edAr | +| | | ray, | +| | | or | +| | | Nume | +| | | ric | +| | | arra | +| | | y. | +| | | The | +| | | rank | +| | | of | +| | | the | +| | | arra | +| | | y | +| | | may | +| | | be | +| | | grea | +| | | ter | +| | | than | +| | | the | +| | | rank | +| | | of | +| | | the | +| | | inpu | +| | | t | +| | | grid | +| | | , | +| | | in | +| | | whic | +| | | h | +| | | case | +| | | the | +| | | inpu | +| | | t | +| | | grid | +| | | shap | +| | | e | +| | | must | +| | | matc | +| | | h | +| | | a | +| | | trai | +| | | ling | +| | | port | +| | | ion | +| | | of | +| | | the | +| | | arra | +| | | y | +| | | shap | +| | | e. | +| | | For | +| | | exam | +| | | ple, | +| | | if | +| | | the | +| | | inpu | +| | | t | +| | | grid | +| | | is | +| | | curv | +| | | ilin | +| | | ear | +| | | with | +| | | shap | +| | | e | +| | | (64, | +| | | 128) | +| | | , | +| | | the | +| | | last | +| | | two | +| | | dime | +| | | nsio | +| | | ns | +| | | of | +| | | the | +| | | arra | +| | | y | +| | | must | +| | | matc | +| | | h. | +| | | Simi | +| | | larl | +| | | y, | +| | | if | +| | | the | +| | | inpu | +| | | t | +| | | grid | +| | | is | +| | | gene | +| | | ric | +| | | with | +| | | shap | +| | | e | +| | | (256 | +| | | 0,), | +| | | the | +| | | last | +| | | dime | +| | | nsio | +| | | n | +| | | of | +| | | the | +| | | arra | +| | | y | +| | | must | +| | | have | +| | | that | +| | | leng | +| | | th. | ++------+------+------+ + +\|Array or Transient-Variable\|[bicubic regridders] +``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``\ \| + +.. raw:: html + +

+ +Interpolate a gridded data array to a new grid, using a bicubic +regridder. The return value is the regridded data variable. + +.. raw:: html + +

+ +.. raw:: html + +

+ +array is a Variable, MaskedArray, or Numeric array. The rank of the +array may be greater than the rank of the input grid, in which case the +input grid shape must match a trailing portion of the array shape. For +example, if the input grid is curvilinear with shape (64,128), the last +two dimensions of the array must match. Simiarly, if the input grid is +generic with shape (2560,), the last dimension of the array must have +that length. + +.. raw:: html + +

+ +.. raw:: html + +

+ +gradientLat: df/di (see the SCRIP documentation). Same shape as array. + +.. raw:: html + +

+ +.. raw:: html + +

+ +gradientLon: df/dj. Same shape as array. + +.. raw:: html + +

+ +.. raw:: html + +

+ +gradientLatLon: d(df)/(di)(dj). Same shape as array. + +.. raw:: html + +

+ +\| \|Numeric array\|\ ``getDestinationArea()`` [conservative regridders +only]\|Return the area of the destination (output) grid cell. The array +is 1-D, with length equal to the number of cells in the output grid.\| +\|Numeric array\|\ ``getDestinationFraction()``\ \|Return the area +fraction of the destination (output) grid cell that participates in the +regridding. The array is 1-D, with length equal to the number of cells +in the output grid.\| \|CurveGrid or +Generic-Grid\|\ ``getInputGrid()``\ \|Return the input grid, or None if +no input grid is associated with the regridder.\| \|CurveGrid or +Generic-Grid\|\ ``getOutputGrid()``\ \|Return the output grid.\| +\|Numeric array\|\ ``getSourceArea()`` [conservative regridders +only]\|Return the area of the source (input) grid cell. The array is 1- +D, with length equal to the number of cells in the input grid.\| +\|Numeric array\|\ ``getSourceFraction()``\ \|Return the area fraction +of the source (input) grid cell that participates in the regridding. The +array is 1-D, with length equal to the number of cells in the input +grid\| + +4.4 Examples +~~~~~~~~~~~~ + +4.4.1 CDMS regridder +^^^^^^^^^^^^^^^^^^^^ + +**Example:** + +Regrid data to a uniform output grid. + +{% highlight python %} 1 #!/usr/local/bin/python 2 import cdms 3 from +regrid import Regridder 4 f = cdms.open('rls\_ccc\_per.nc') 5 rlsf = +f.variables['rls'] 6 ingrid = rlsf.getGrid() 7 outgrid = +cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) 8 regridFunc = +Regridder(ingrid, outgrid) 9 newrls = regridFunc(rlsf) 10 f.close() {% +endhighlight %} + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 4 | Open | +| | a | +| | netC | +| | DF | +| | file | +| | for | +| | inpu | +| | t. | ++------+------+ +| 7 | Crea | +| | te | +| | a 4 | +| | x 5 | +| | degr | +| | ee | +| | outp | +| | ut | +| | grid | +| | . | +| | Note | +| | that | +| | this | +| | grid | +| | is | +| | not | +| | asso | +| | ciat | +| | ed | +| | with | +| | a | +| | file | +| | or | +| | data | +| | set | ++------+------+ +| 8 | Crea | +| | te | +| | the | +| | regr | +| | idde | +| | r | +| | func | +| | tion | ++------+------+ +| 9 | Read | +| | all | +| | data | +| | and | +| | regr | +| | id. | +| | The | +| | miss | +| | ing | +| | data | +| | valu | +| | e | +| | is | +| | obta | +| | ined | +| | from | +| | vari | +| | able | +| | rlsf | ++------+------+ + +Return the area fraction of the source (input) grid cell that +participates in the regridding. The array is 1-D, with length equal to +the number of cells in the input grid. + +**Example:** + +Get a mask from a separate file, and set as the input grid mask. + +{% highlight python %} 1 import cdms 2 from regrid import Regridder 3 # +4 f = cdms.open('so\_ccc\_per.nc') 5 sof = f.variables['so'] 6 ingrid = +sof.getGrid() 7 g = cdms.open('rls\_mri\_per.nc') 8 rlsg = +g.variables['rls'] 9 outgrid = rlsg.getGrid() 10 regridFunc = +Regridder(ingrid,outgrid) 11 h = cdms.open('sft\_ccc.nc') 12 sfmaskvar = +h.variables['sfmask'] 13 sfmask = sfmaskvar[:] 14 outArray = +regridFunc(sof.subSlice(time=0),mask=sfmask) 15 f.close() 16 g.close() +17 h.close() {% endhighlight %} + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 6 | Get | +| | the | +| | inpu | +| | t | +| | grid | +| | . | ++------+------+ +| 9 | Get | +| | the | +| | outp | +| | ut | +| | grid | ++------+------+ +| 10 | Crea | +| | te | +| | the | +| | regr | +| | idde | +| | r | +| | func | +| | tion | +| | . | ++------+------+ +| 13 | Get | +| | the | +| | mask | +| | . | ++------+------+ +| 14 | Regr | +| | id | +| | with | +| | a | +| | user | +| | mask | +| | . | +| | The | +| | subs | +| | lice | +| | call | +| | retu | +| | rns | +| | a | +| | tran | +| | sien | +| | t | +| | vari | +| | able | +| | corr | +| | espo | +| | ndin | +| | g | +| | to | +| | vari | +| | able | +| | sof | +| | at | +| | time | +| | 0 | ++------+------+ + +**Note:** Although it cannot be determined from the code, both mask and +the input array sof are four-dimensional. This is the n-dimensional +case. + +**Example:** + +Generate an array of zonal mean values. + +1 f = cdms.open('rls\_ccc\_per.nc') 2 rlsf = f.variables['rls'] 3 ingrid += rlsf.getGrid() 4 outgrid = cdms.createZonalGrid(ingrid) 5 regridFunc = +Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 3 | Get | +| | the | +| | inpu | +| | t | +| | grid | +| | . | +| | Retu | +| | rn | +| | the | +| | area | +| | frac | +| | tion | +| | of | +| | the | +| | sour | +| | ce | +| | (inp | +| | ut) | +| | grid | +| | cell | +| | that | +| | part | +| | icip | +| | ates | +| | in | +| | the | +| | regr | +| | iddi | +| | ng. | +| | The | +| | arra | +| | y | +| | is | +| | 1-D, | +| | with | +| | leng | +| | th | +| | equa | +| | l | +| | to | +| | the | +| | numb | +| | er | +| | of | +| | cell | +| | s | +| | in | +| | the | +| | inpu | +| | t | +| | grid | +| | . | ++------+------+ +| 4 | Crea | +| | te | +| | a | +| | zona | +| | l | +| | grid | +| | . | +| | outg | +| | rid | +| | has | +| | the | +| | same | +| | lati | +| | tude | +| | s | +| | as | +| | ingr | +| | id, | +| | and | +| | a | +| | sing | +| | leto | +| | n | +| | long | +| | itud | +| | e | +| | dime | +| | nsio | +| | n. | +| | crea | +| | teGl | +| | obal | +| | Mean | +| | Grid | +| | coul | +| | d | +| | be | +| | used | +| | here | +| | to | +| | gene | +| | rate | +| | a | +| | glob | +| | al | +| | mean | +| | arra | +| | y. | ++------+------+ +| 5 | Gene | +| | rate | +| | the | +| | regr | +| | idde | +| | r | +| | func | +| | tion | +| | . | ++------+------+ +| 6 | Gene | +| | rate | +| | the | +| | zona | +| | l | +| | mean | +| | arra | +| | y | ++------+------+ + +**Example:** + +Regrid an array with missing data, and calculate the area-weighted mean +of the result. + +{% highlight python %} 1 from cdms.MV import * ... 2 outgrid = +cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) 3 outlatw, outlonw += outgrid.getWeights() 4 outweights = outerproduct(outlatw, outlonw) 5 +grid = var.getGrid() 6 sample = var[0,0] 7 latw, lonw = +grid.getWeights() 8 weights = outerproduct(latw, lonw) 9 inmask = +where(greater(absolute(sample),1.e15),0,1) 10 mean = +add.reduce(ravel(inmask*\ weights\ *sample))/ +add.reduce(ravel(inmask*\ weights)) 11 regridFunc = Regridder(grid, +outgrid) 12 outsample, outmask = regridFunc(sample, mask=inmask, +returnTuple=1) 13 outmean = +add.reduce(ravel(outmask\ *outweights*\ outsample)) / +add.reduce(ravel(outmask\*outweights)) {% endhighlight %} + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 2 | Crea | +| | te | +| | a | +| | unif | +| | orm | +| | targ | +| | et | +| | grid | +| | . | ++------+------+ +| 3 | Get | +| | the | +| | lati | +| | tude | +| | and | +| | long | +| | itud | +| | e | +| | weig | +| | hts. | ++------+------+ +| 4 | Gene | +| | rate | +| | a | +| | 2-D | +| | weig | +| | hts | +| | arra | +| | y. | ++------+------+ +| 5 | Get | +| | the | +| | inpu | +| | t | +| | grid | +| | . | +| | ``va | +| | r`` | +| | is a | +| | 4-D | +| | vari | +| | able | +| | . | ++------+------+ +| 6 | Get | +| | the | +| | firs | +| | t | +| | hori | +| | zont | +| | al | +| | slic | +| | e | +| | from | +| | ``va | +| | r``. | ++------+------+ +| 7-8 | Get | +| | the | +| | inpu | +| | t | +| | weig | +| | hts, | +| | and | +| | gene | +| | rate | +| | a | +| | 2-D | +| | weig | +| | hts | +| | arra | +| | y. | ++------+------+ +| 9 | Set | +| | the | +| | 2-D | +| | inpu | +| | t | +| | mask | +| | . | ++------+------+ +| 10 | Calc | +| | ulat | +| | e | +| | the | +| | inpu | +| | t | +| | arra | +| | y | +| | area | +| | -wei | +| | ghte | +| | d | +| | mean | +| | . | ++------+------+ +| 11 | Crea | +| | te | +| | the | +| | regr | +| | idde | +| | r | +| | func | +| | tion | +| | . | ++------+------+ +| 12 | Regr | +| | id. | +| | Beca | +| | use | +| | retu | +| | rnTu | +| | ple | +| | is | +| | set | +| | to | +| | 1, | +| | the | +| | resu | +| | lt | +| | is a | +| | tupl | +| | e | +| | (dat | +| | aArr | +| | ay, | +| | mask | +| | Arra | +| | y). | ++------+------+ +| 13 | Calc | +| | ulat | +| | e | +| | the | +| | area | +| | -wei | +| | ghte | +| | d | +| | mean | +| | of | +| | the | +| | regr | +| | idde | +| | d | +| | data | +| | . | +| | mean | +| | and | +| | outm | +| | ean | +| | shou | +| | ld | +| | be | +| | appr | +| | oxim | +| | atel | +| | y | +| | equa | +| | l | ++------+------+ + +4.4.2 SCRIP regridder +^^^^^^^^^^^^^^^^^^^^^ + +**Example:** + +Regrid from a curvilinear to a generic grid, using a conservative +remapping. Compute the area-weighted means on input and output for +comparison. + +{% highlight python %} import cdms, regrid, MA + +Open the SCRIP remapping file and data file +=========================================== + +direc = '' fremap = cdms.open(direc+'rmp\_T42\_to\_C02562\_conserv.nc') +fdat = cdms.open(direc+'sampleT42Grid.nc') + +Input data array +================ + +dat = fdat('src\_array') + +Read the SCRIP regridder +======================== + +regridf = regrid.readRegridder(fremap) + +Regrid the variable +=================== + +outdat = regridf(dat) + +Get the cell area and fraction arrays. Areas are computed only +============================================================== + +for conservative regridding. +============================ + +srcfrac = regridf.getSourceFraction() srcarea = regridf.getSourceArea() +dstfrac = regridf.getDestinationFraction() dstarea = +regridf.getDestinationArea() + +Calculate area-weighted means +============================= + +inmean = MA.sum(srcfrac\ *srcarea*\ MA.ravel(dat)) / +MA.sum(srcfrac\ *srcarea) outmean = +MA.sum(dstfrac*\ dstarea\ *MA.ravel(outdat)) / MA.sum(dstfrac*\ dstarea) +print 'Input mean:', inmean print 'Output mean:', outmean + +fremap.close) fdat.close() {% endhighlight %} diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst new file mode 100644 index 00000000..05bdb5f5 --- /dev/null +++ b/docs/source/manual/cdms_5.rst @@ -0,0 +1,486 @@ +CHAPTER 5 Plotting CDMS data in Python +-------------------------------------- + +5.1 Overview +~~~~~~~~~~~~ + +Data read via the CDMS Python interface can be plotted using the ``vcs`` +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the UV-CDAT reference manual. +The ``vcs`` module provides access to the functionality of the VCS +visualization program. + +Examples of plotting data accessed from CDMS are given below, as well as +documentation for the plot routine keywords. + +5.2 Examples +~~~~~~~~~~~~ + +In the following examples, it is assumed that variable ``psl`` is +dimensioned (time, latitude, longitude). ``psl`` is contained in the +dataset named ``'sample.xml'``. + +5.2.1 Example: plotting a gridded variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +{% highlight python %} 1 import cdms, vcs 2 3 f = +cdms.open('sample.xml') 4 psl = f.variables['psl'] 5 sample = psl[0] 6 +w=vcs.init() 7 8 w.plot(sample) 9 f.close() {% endhighlight %} + +**Notes:** + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 5 | Get | +| | a | +| | hori | +| | zont | +| | al | +| | slic | +| | e, | +| | for | +| | the | +| | firs | +| | t | +| | time | +| | poin | +| | t. | ++------+------+ +| 6 | Crea | +| | te | +| | a | +| | VCS | +| | Canv | +| | as | +| | ``w` | +| | `. | ++------+------+ +| 8 | Plot | +| | the | +| | data | +| | . | +| | Beca | +| | use | +| | samp | +| | le | +| | is a | +| | tran | +| | sien | +| | t | +| | vari | +| | able | +| | , | +| | it | +| | enca | +| | psul | +| | ates | +| | all | +| | the | +| | time | +| | , | +| | lati | +| | tude | +| | , | +| | long | +| | itud | +| | e, | +| | and | +| | attr | +| | ibut | +| | e | +| | info | +| | rmat | +| | ion. | ++------+------+ +| 9 | Clos | +| | e | +| | the | +| | file | +| | . | +| | This | +| | must | +| | be | +| | done | +| | afte | +| | r | +| | the | +| | refe | +| | renc | +| | e | +| | to | +| | the | +| | pers | +| | iste | +| | nt | +| | vari | +| | able | +| | ``ps | +| | l``. | ++------+------+ + +Thats it! The axis coordinates, variable name, description, units, etc. +are obtained from variable sample. + +What if the units are not explicitly defined for ``psl``, or a different +description is desired? ``plot`` has a number of other keywords which +fill in the extra plot information. + +5.2.2 Example: using aplot keywords. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +{% highlight python %} w.plot(array, units='mm/day', +file\_comment='High-frequency reanalysis', long\_name="Sea level +pressure", comment1="Sample plot", hms="18:00:00", ymd="1978/01/01") {% +endhighlight %} + +**Note:** Keyword arguments can be listed in any order. + +5.2.3 Example: plotting a time-latitude slice +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Assuming that variable ``psl`` has domain ``(time,latitude,longitude)``, +this example selects and plots a time-latitude slice: + +{% highlight python %} 1 samp = psl[:,:,0] 2 w = vcs.init() 3 +w.plot(samp, name='sea level pressure') {% endhighlight %} + +Notes: + ++------+------+ +| Line | Note | +| | s | ++======+======+ +| 1 | ``sa | +| | mp`` | +| | is a | +| | slic | +| | e | +| | of | +| | ``ps | +| | l``, | +| | at | +| | inde | +| | x | +| | ``0` | +| | ` | +| | of | +| | the | +| | last | +| | dime | +| | nsio | +| | n. | +| | Sinc | +| | e | +| | ``sa | +| | mp`` | +| | was | +| | obta | +| | ined | +| | from | +| | the | +| | slic | +| | e | +| | oper | +| | ator | +| | , | +| | it | +| | is a | +| | tran | +| | sien | +| | t | +| | vari | +| | able | +| | , | +| | whic | +| | h | +| | incl | +| | udes | +| | the | +| | lati | +| | tude | +| | and | +| | time | +| | info | +| | rmat | +| | ion. | ++------+------+ +| 3 | The | +| | ``na | +| | me`` | +| | keyw | +| | ord | +| | defi | +| | nes | +| | the | +| | iden | +| | tifi | +| | er, | +| | by | +| | defa | +| | ult | +| | the | +| | name | +| | in | +| | the | +| | file | +| | . | ++------+------+ + +5.2.4 Example: plotting subsetted data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Calling the variable ``psl`` as a function reads a subset of the +variable. The result variable ``samp`` can be plotted directly: + +{% highlight python %} ... 1 samp = psl(time = (0.0,100.0), longitude = +180.0) 2 w = vcs.init() 3 w.plot(samp) {% endhighlight %} + +5.3 ``plot`` method +~~~~~~~~~~~~~~~~~~~ + +The ``plot`` method is documented in the UV-CDAT Reference Manual. This +section augments the documentation with a description of the optional +keyword arguments. The general form of the plot command is: + +{% highlight python %} canvas.plot(array [, args] [,key=value [, +key=value [, ...] ] ]) {% endhighlight %} + +where: + +- canvas is a VCS Canvas object, created with the vcs.init method. + +- array is a variable, masked array, or Numeric array having between + two and five dimensions. The last dimensions of the array is termed + the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', + and 'w'. For example, if array is three-dimensional, the axes are + (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). + (Note that the t dimension need have no connection with time; any + spatial axis can be mapped to any plot dimension. For a graphics + method which is two-dimensional, such as boxfill, the y-axis is + plotted on the horizontal, and the x-axis on the vertical. + + If array is a gridded variable on a rectangular grid, the plot + function uses a box-fill graphics method. If it is non-rectangular, + the meshfill graphics method is used. + + Note that some plot keywords apply only to rectangular grids only. + +- args are optional positional arguments: + + ``args`` := template\_name, graphics\_method, graphics\_name + + ``template_name``: the name of the VCS template (e.g., 'AMIP') + + ``graphics_method``: the VCS graphics method (boxfill) + + ``graphics_name``: the name of the specific graphics method + ('default') + + See the UV-CDAT Reference Manual and VCS Reference Manual for a + detailed description of these arguments. + +- ``key=value``, ... are optional keyword/value pairs, listed in any + order. These are defined in the table below. + +Table 5.1 ``plot`` keywords + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + +
KeyTypeValue
comment1stringComment plotted above file_comment
comment2stringComment plotted above comment1
comment3stringComment plotted above comment2
continents0 or 1if 1, plot continental outlines (default:plot if xaxis is + longitude, yaxis is latitude -or- xname is 'longitude' and yname is + 'latitude'
file_commentstringComment, defaults to variable.parent.comment
gridCDMS grid objectGrid associated with the data. Defaults to + variable.getGrid()
hmsstringHour, minute, second
long_namestringDescriptive variable name, defaults to variable.long_name.
missing_valuesame type as arrayMissing data value, defaults to variable.getMissing()
namestringVariable name, defaults to variable.id
timecdtime relative or absolute +

Time associated with the data.

+ +

Example:

+ +

cdtime.reltime(30.0, "days since 1978-1-1").

+
unitsstringData units. Defaults to variable.units
variableCDMS variable objectVariable associated with the data. The variable grid must have the + same shape as the data array.
xarray ([y|z|t|w]array)1-D Numeric arrayRectangular grids only. Array of coordinate values, having the + same length as the corresponding dimension. Defaults to xaxis[:\] + (y|z|t|waxis[:])
xaxis ([y|z|t|w]axis)CDMS axis objectRectangular grids only. Axis object. xaxis defaults to + grid.getAxis(0), yaxis defaults to grid.getAxis(1)
xbounds (ybounds)2-D Numeric arrayRectangular grids only. Boundary array of shape (n,2) where + n is the axis length. Defaults to xaxis.getBounds(), or + xaxis.genGenericBounds() if None, similarly for ybounds.
xname ([y|z|t|w]name)stringRectangular grids only. Axis name. Defaults to xaxis.id + ([y|z|t|w]axis.id)
xrev (yrev)0 or 1 +

If xrev (yrev) is 1, reverse the direction of the x-axis (y-axis). Defaults to + 0, with the following exceptions:

+ +
    +
  • If the y-axis is latitude, and has decreasing values, yrev defaults to + 1
  • + +
  • If the y-axis is a vertical level, and has increasing pressure levels, yrev + defaults to 1.
  • +
+
xunits ([y|z|t|w]units)stringRectangular grids only. Axis units. Defaults to xaxis.units + ([y|z|t|w]axis.units).
diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst new file mode 100644 index 00000000..6ee84692 --- /dev/null +++ b/docs/source/manual/cdms_6.rst @@ -0,0 +1,3128 @@ +CHAPTER 6 Climate Data Markup Language (CDML) +--------------------------------------------- + +6.1 Introduction +~~~~~~~~~~~~~~~~ + +The Climate Data Markup Language (CDML) is the markup language used to +represent metadata in CDMS. CDML is based on the W3C XML standard +(http://www.w3.org). This chapter defines the syntax of CDML. Read this +section if you will be building or maintaining a CDMS database. + +XML, the eXtensible Markup Language, makes it possible to define +interoperable dialects of markup languages. The most recent version of +HTML, the Web hypertext markup language, is an XML dialect. CDML is also +an XML dialect, geared toward the representation of gridded climate +datasets. XML provides rigor to the metadata representation, ensuring +that applications can access it correctly. XML also deals with +internationalization issues, and holds forth the promise that utilities +for browsing, editing, and other common tasks will be available in the +future. + +CDML files have the file extension .xml or .cdml. + +6.2 Elements +~~~~~~~~~~~~ + +A CDML document consists of a nested collection of elements. An element +is a description of the metadata associated with a CDMS object. The form +of an element is: + +`` element-content `` + +or + +```` + +where + +- ``tag`` is a string which defines the type of element +- ``attribute-list`` is a blank-separated list of attribute-value + pairs, of the form: + + ``attribute = "value"`` +- ``element-content`` depends on the type of element. It is either a + list of elements, or text which defines the element values. For + example, the content of an axis element either is a list of axis + values, or is a linear element. For datasets, the content is the + blank-separated list of elements corresponding to the axes, grids, + and variables contained in the dataset. + +The CDML elements are: + +Table 6.1 CDML Tags + + ++------------+---------------------------------------+ +| Tag | Description | ++============+=======================================+ +| attr | Extra attribute | ++------------+---------------------------------------+ +| axis | Coordinate axis | ++------------+---------------------------------------+ +| domain | Axes on which a variable is defined | ++------------+---------------------------------------+ +| domElem | Element of a variable domain | ++------------+---------------------------------------+ +| linear | Linearly-spaced axis values | ++------------+---------------------------------------+ +| rectGrid | Rectilinear Grid | ++------------+---------------------------------------+ +| variable | Variable | ++------------+---------------------------------------+ + +6.3 Special Characters +~~~~~~~~~~~~~~~~~~~~~~ + +XML reserves certain characters for markup. If they appear as content, +they must be encoded to avoid confusion with markup: + +Table 6.2 Special Character Encodings + + ++-------------+------------+ +| Character | Encoding | ++=============+============+ +| < | < | ++-------------+------------+ +| > | > | ++-------------+------------+ +| & | & | ++-------------+------------+ +| “ | " | ++-------------+------------+ +| ‘ | ' | ++-------------+------------+ + +For example, the comment + +{% highlight text %} Certain "special characters", such as <, >, and , +must be encoded. {% endhighlight %} + +would appear in an attribute string as: + +{% highlight html %} comment = "Certain "special characters", such as <, +>, and ', must be encoded." {% endhighlight %} + +6.4 Identifiers +~~~~~~~~~~~~~~~ + +In CDMS, all objects in a dataset have a unique string identifier. The +id attribute holds the value of this identifier. If the variable, axis, +or grid has a string name within a data file, then the id attribute +ordinarily has this value. Alternatively, the name of the object in a +data file can be stored in the name\_in\_file attribute, which can +differ from the id. Datasets also have IDs, which can be used within a +larger context (databases). + +An identifer must start with an alphabetic character (upper or lower +case), an underscore (\_), or a colon (:). Characters after the first +must be alphanumeric, an underscore, or colon. There is no restriction +on the length of an identifier. + +6.5 CF Metadata Standard +~~~~~~~~~~~~~~~~~~~~~~~~ + +`The CF metadata standard `__ defines a set +of conventions for usage of netCDF. This standard is supported by CDML. +The document defines names and usage for metadata attributes. CF +supersedes the GDT 1.3 standard. + +6.6 CDML Syntax +~~~~~~~~~~~~~~~ + +The following notation is used in this section: + +- A ``monospaced block`` is used for a syntax specification. +- **Bold** text indicates literals. +- (R\|S) denotes either R or S. +- R\*denotes zero or more R. +- R+ denotes one or more R. + +A CDML document consists of a prolog followed by a single dataset +element. + +``CDML-document ::= prolog dataset-element`` + +The prolog defines the XML version, and the Document Type Definition +(DTD), a formal specification of the document syntax. See http:// +www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML +Version 1.0. + +``prolog ::= `` + +6.6.1 Dataset Element +^^^^^^^^^^^^^^^^^^^^^ + +A dataset element describes a single dataset. The content is a list of +elements corresponding to the axes, grids, and variables contained in +the dataset. Axis, variable, and grid elements can be listed in any +order, and an element ID can be used before the element is actually +defined. + +``dataset-element ::=`` **** ``dataset-content`` **** + +``dataset-content ::= (axis-element | grid-element | variable-element)* extra-attribute-element+`` + +Table 6.3 Dataset Attributes + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Attribute + +.. raw:: html + + + +Required + +.. raw:: html + + + +CF + +.. raw:: html + + + +GDT + +.. raw:: html + + + +Notes + +.. raw:: html + +
+ +appendices + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Version number + +.. raw:: html + +
+ +calendar + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +.. raw:: html + +

+ +Calendar used for encoding time axes. + +.. raw:: html + +

+ +.. raw:: html + +

+ +``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| +``proleptic_gregorian`` \| ``standard`` + +.. raw:: html + +

+ +.. raw:: html + +

+ +Note: for the CF convention, the calendar attribute is placed on the +time axis. + +.. raw:: html + +

+ +.. raw:: html + +
+ +comment + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Additional dataset information + +.. raw:: html + +
+ +conventions + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +The netCDF metadata standard. Example: "CF-1.0" + +.. raw:: html + +
+ +cdms\_filemap + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Map of partitioned axes to files. See note below. + +.. raw:: html + +
+ +directory + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Root directory of the dataset + +.. raw:: html + +
+ +frequency + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Temporal frequency + +.. raw:: html + +
+ +history + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Evolution of the data + +.. raw:: html + +
+ +id + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Dataset identifier + +.. raw:: html + +
+ +institution + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Who made or supplied the data + +.. raw:: html + +
+ +production + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +How the data was produced (see source) + +.. raw:: html + +
+ +project + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Project associated with the data Example: "CMIP 2" + +.. raw:: html + +
+ +references + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +Published or web-based references that describe the data or methods used +to produce it + +.. raw:: html + +
+ +source + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +The method of production of the original data. + +.. raw:: html + +
+ +template + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Filename template. This is an alternate mechanism, other than +cdms\_filemap, for describing the file mapping. See ‘cdimport -h’ for +details. + +.. raw:: html + +
+ +title + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +A succinct description of the data. + +.. raw:: html + +
+ +**Notes:** + +The ``cdms_filemap`` attribute describes how the dataset is partitioned +into files. The format is: + +``filemap ::= [ varmap, varmap, ...]`` + +``varmap ::= [ namelist, slicelist ]`` + +``namelist ::= [ name, name, ... ]`` + +``slicelist ::= [ indexlist, indexlist, ,,, ]`` + +``indexlist ::= [ time0, time1, lev0, lev1, path ]`` + +``name ::= variable name`` + +``time0 ::= first index of time in the file, or '-' if not split on time`` + +``time1 ::= last index of time + 1, in the file, or '-' if not split on time`` + +``lev0 ::= first index of vertical levels in the file, or '-' if not split on level`` + +``lev1 ::= last index +1 of vertical levels in the file, or '-' if not split on level`` + +``path ::= pathname of the file containing data for this time/level range.`` + +The pathname is appended to the value of the directory attribute, to +obtain an absolute pathname. + +6.6.2 Axis Element +^^^^^^^^^^^^^^^^^^ + +An axis element describes a single coordinate axis. The content can be a +blank-separated list of axis values or a linear element. A linear +element is a representation of a linearly-spaced axis as (start, delta, +length). + +``axis-element ::=`` **** ``axis-content`` **** + +``axis-content ::= (axis-values | linear-element) extra-attribute-element*`` + +``axis-values ::= [value*]`` + +``linear-element ::=`` ** ** + +Table 6.4 + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + +
AttributeRequired?CFGDTNotes
associateNNYIDs of variables containing alternative sets of coordinates.
axisNYY +

The spatial type of the axis:

+ +
    +
  • "T" - time
  • + +
  • "X" - longitude
  • + +
  • "Y" - latitude
  • + +
  • "Z" - vertical level
  • + +
  • "-" - not spatiotemporal
  • +
+
boundsNYYID of the boundary variable
calendarNYNSee dataset.calendar
climatologyNYNRange of dates to which climatological statistics apply.
commentNYNString comment
compressNYYDimensions which have been compressed by gathering
datatypeYNNChar, Short, Long, Float, Double, or String
datesNYNRange of dates to which statistics for a typical diurnal cycle apply.
expandNNYCoordinates prior to contraction
formula_termsNYNVariables that correspond to the terms in a formula.
idYNNAxis identifier. Also the name of the axis in the underlying file(s), if + name_in_file is undefined.
isvarNNN +

'true' | 'false'

+ +

'false' if the axis does not have coordinate values explicitly defined in the + underlying file(s).

+ +

Default: 'true'

+
leap_monthNYNFor a user-defined calendar, the month which is lengthened by a day in leap + years.
leap_yearNYNAn example of a leap year for a user-defined calendar. All years that differ + from this year by a multiple of four are leap years.
lengthNNNNumber of axis values, including values for which no data is defined. Cf. + partition_length.
long_nameNYYLong description of a physical quantity
moduloNNYArithmetic modulo of an axis with circular topology.
month_lengthsNYNLength of each month in a non-leap year for a user-defined calendar.
name_in_fileNNNName of the axis in the underlying file(s). See id.
partitionNNNHow the axis is split across files.
partition_lengt hNNNNumber of axis points for which data is actually defined. If data is missing + for some values, this will be smaller than the length.
positiveNYYDirection of positive for a vertical axis
standard_nameNYNReference to an entry in the standard name table.
topologyNNY +

Axis topology.

+ +

'circular' | 'linear'

+
unitsYYYUnits of a physical quantity
weightsNNNName of the weights array
+ +6.6.3 partition attribute +^^^^^^^^^^^^^^^^^^^^^^^^^ + +For an axis in a dataset, the .partition attribute describes how an axis +is split across files. It is a list of the start and end indices of each +axis partition. + +FIGURE 4. Partitioned axis + + +.. figure:: /images/timeLine.jpg + :alt: + +For example, Figure 4 shows a time axis, representing the 36 months, +January 1980 through December 1982, with December 1981 missing. The +first partition interval is (0,12), the second is (12,23), and the third +is (24,36), where the interval (i,j) represents all indices k such that +i <= k < j. The .partition attribute for this axis would be the list: + +``[0, 12, 12, 23, 24, 36]`` + +Note that the end index of the second interval is strictly less than the +start index of the following interval. This indicates that data for that +period is missing. + +6.6.4 Grid Element +^^^^^^^^^^^^^^^^^^ + +A grid element describes a horizontal, latitude-longitude grid which is +rectilinear in topology, + +``grid-element ::=`` **** +``extra-attribute-element*`` **** + +Table 6.5 RectGrid Attributes + + +.. raw:: html + + + +:: + + + +.. raw:: html + + + +:: + + + + + + + + +.. raw:: html + +
Attribute Required? GDT? Notes
idYNGrid identifier
typeYN

Grid classification

"gaussian" | "uniform" | "equalarea" |"generic"

Default: "generic"

latitudeYNLatitude axis name
longitudeYNLongitude axis name
maskNNName of associated mask variable
orderYN

Grid ordering "yx" | "xy"

Default: “yx”, axis order is latitude, longitude

+ +6.6.5 Variable Element +^^^^^^^^^^^^^^^^^^^^^^ + +A variable element describes a data variable. The domain of the variable +is an ordered list of domain elements naming the axes on which the +variable is defined. A domain element is a reference to an axis or grid +in the dataset. + +The length of a domain element is the number of axis points for which +data can be retrieved. The partition\_length is the number of points for +which data is actually defined. If data is missing, this is less than +the length. + +``variable-element ::=`` **** +``variable-content`` **** + +``variable-content ::=`` variable-domain extra-attributeelement\*\` + +``variable-domain ::=`` **** ``domain-element*`` **** + +``domain-element ::=`` **\*\* + +Table 6.6 Variable Attributes + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Attribute + +.. raw:: html + + + +Required? + +.. raw:: html + + + +CF + +.. raw:: html + + + +GDT + +.. raw:: html + + + +Notes + +.. raw:: html + +
+ +id + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Variable identifier. Also, the name of the variable in the underlying +file(s), if name\_in\_file is undefined. + +.. raw:: html + +
+ +add\_offset + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Additive offset for packing data. See scale\_factor. + +.. raw:: html + +
+ +associate + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +IDs of variables containing alternative sets of coordinates + +.. raw:: html + +
+ +axis + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +.. raw:: html + +

+ +Spatio-temporal dimensions. + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: "TYX" for a variable with domain (time, latitude, longitude) + +.. raw:: html + +

+ +.. raw:: html + +

+ +Note: for CF, applies to axes only. + +.. raw:: html + +

+ +.. raw:: html + +
+ +cell\_methods + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +The method used to derive data that represents cell values, e.g., +"maximum", "mean", "variance", etc. + +.. raw:: html + +
+ +comments + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Comment string + +.. raw:: html + +
+ +coordinates + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +IDs of variables containing coordinate data. + +.. raw:: html + +
+ +datatype + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Char, Short, Long, Float, Double, or String + +.. raw:: html + +
+ +grid\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Id of the grid + +.. raw:: html + +
+ +grid\_type + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +"gaussian" \| "uniform" \| "equalarea" \| "generic" + +.. raw:: html + +
+ +long\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Long description of a physical quantity. + +.. raw:: html + +
+ +missing\_value + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Value used for data that are unknown or missint. + +.. raw:: html + +
+ +name\_in\_file + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the variable in the underlying file(s). See id. + +.. raw:: html + +
+ +scale\_factor + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Multiplicative factor for packing data. See add\_offset. + +.. raw:: html + +
+ +standard\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +Reference to an entry in the standard name table. + +.. raw:: html + +
+ +subgrid + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Records how data values represent subgrid variation. + +.. raw:: html + +
+ +template + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the file template to use for this variable. Overrides the +dataset value. + +.. raw:: html + +
+ +units + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Units of a physical quantity. + +.. raw:: html + +
+ +valid\_max + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest valid value of a variable + +.. raw:: html + +
+ +valid\_min + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Smallest valid value of a variable + +.. raw:: html + +
+ +valid\_range + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest and smallest valid values of a variable + +.. raw:: html + +
+ +6.6.6 Attribute Element +^^^^^^^^^^^^^^^^^^^^^^^ + +Attributes which are not explicitly defined by the GDT convention are +represented as extra attribute elements. Any dataset, axis, grid, or +variable element can have an extra attribute as part of its content. +This representation is also useful if the attribute value has non-blank +whitespace characters (carriage returns, tabs, linefeeds) which are +significant. + +The datatype is one of: **Char**, **Short**, **Long**, **Float**, +**Double**, or **String**. + +``extra-attribute-element ::=`` **** ``attribute-value`` +**** + +6.7 A Sample CDML Document +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataset "sample" has two variables, and six axes. + +**Note:** + +- The file is indented for readability. This is not required; the added + whitespace is ignored. +- The dataset contains three axes and two variables. Variables u and v + are functions of time, latitude, and longitude. +- The global attribute cdms\_filemap describes the mapping between + variables and files. The entry + ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` + indicates that variable ``u`` is contained in file u\_2000.nc for + time index 0, u\_2001.nc for time index 1, etc. + +{% highlight xml %} + +.. raw:: html + + + +.. raw:: html + + + + [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] + +:: + + + + [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. + + 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 + + 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 + + 303.75 315. 326.25 337.5 348.75] + + + + + [ 0. 366. 731.] + + + + + + + + + + + + + + + + + + + {% endhighlight %} diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst new file mode 100644 index 00000000..a4b739ad --- /dev/null +++ b/docs/source/manual/cdms_7.rst @@ -0,0 +1,423 @@ +CHAPTER 7 CDMS Utilities +------------------------ + +7.1 ``cdscan``: Importing datasets into CDMS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +7.1.1 Overview +^^^^^^^^^^^^^^ + +A dataset is a partitioned collection of files. To create a dataset, the +files must be scanned to produce a text representation of the dataset. +CDMS represents datasets as an ASCII metafile in the CDML markup +language. The file contains all metadata, together with information +describing how the dataset is partitioned into files. (Note: CDMS +provides a direct interface to individual files as well. It is not +necessary to scan an individual file in order to access it.) + +For CDMS applications to work correctly, it is important that the CDML +metafile be valid. The ``cdscan`` utility generates a metafile from a +collection of data files. + +CDMS assumes that there is some regularity in how datasets are +partitioned: + +- A variable can be partitioned (split across files) in at most two + dimensions. The partitioned dimension(s) must be either time or + vertical level dimensions; variables may not be partitioned across + longitude or latitude. Datasets can be parti-tioned by variable as + well. For example, one set of files might contain heat fluxes, while + another set contains wind speeds. + +Otherwise, there is considerable flexibility in how a dataset can be +partitioned: + +- Files can contain a single variable or all variables in the dataset. +- The time axis can have gaps. +- Horizontal grid boundary information and related information can be + duplicated across files. +- Variables can be on different grids. +- Files may be in any of the self-describing formats supported by CDMS, + including netCDF, HDF, GrADS/GRIB, and DRS. + +7.1.2 ``cdscan`` Syntax +^^^^^^^^^^^^^^^^^^^^^^^ + +The syntax of the ``cdscan`` command is + +{% highlight text %} cdscan [options] file1 file2 ... {% endhighlight %} + +or + +{% highlight text %} cdscan [options] -f file\_list {% endhighlight %} + +where + +- ``file1 file2 ...`` is a blank-separated list of files to scan +- ``file_list`` is the name of a file containing a list of files to + scan, one pathname per line. + +Output is written to standard output by default. Use the -x option to +specify an output filename. + +Table 7.1 cdscan command options + + +.. raw:: html + + + +:: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +.. raw:: html + +
OptionDescription
-a alias_file +

Change variable names to the aliases defined in an alias file.

+ +

Each line of the alias file consists of two blank separated fields: + variable_id alias. variable_id is the ID of the + variable in the file, and alias is the name that will be substituted + for it in the output dataset. Only variables with entries in the + alias_file are renamed.

+
-c calendarSpecify the dataset calendar attribute. One of "gregorian" (default), "julian", + "noleap", "proleptic_gregorian", "standard", or "360_day".
-d dataset_idString identifier of the dataset. Should not contain blanks or non-printing + characters. Default: "none"
+ -e newattr + +

Add or modify attributes of a file, variable, or axis. The form of + newattr is either:

+ +

var.attr = value

+ +

to modify a variable or attribute, or

+ +

.attr = value

+ +

to modify a global (file) attribute. In either case, value may be quoted to + preserve spaces or force the attribute to be treated as a string. If value is not + quoted and the first character is a digit, it is converted to integer or + floating-point. This option does not modify the input datafiles. See notes and + examples below.

+
--exclude var,var,... +

Exclude specified variables. The argument is a comma-separated list of + variables containing no blanks. Also see --include.

+
-f file_list +

File containing a list of absolute data file names, one per line.

+
-hPrint a help message.
-i time_deltaCauses the time dimension to be represented as linear, producing a more compact + representation. This is useful if the time dimension is very long. + time_delta is a float or integer. For example, if the time delta is 6 + hours, and the reference units are 'hours since xxxx' , set the time delta to 6. + See the -r option. See Note 2.
--include var,var,... +

Only include specified variables in the output. The argument is a + comma-separated list of variables containing no blanks.

+

Also see --exclude.

+
-j +

Scan time as a vector dimension. Time values are listed individually.

+ +

Note: Turns off the -i option.

+
-l levelsSpecify that the files are partitioned by vertical level. That is, data for + different vertical levels may appear in different files. levels is a + comma-separated list of levels containing no blanks. See Note 3.
-m levelidName of the vertical level dimension. The default is the vertical dimension as + determined by CDMS. See Note 3.
-p templateAdd a file template string, for compatibility with pre-V3.0 datasets. + cdimport -h describes template strings.
-qQuiet mode.
-r time_unitsTime units of the form units since yyyy-mm-dd hh:mi:ss, where + units is one of "year", "month","day", "hour", "minute", + "second".
-s suffix_fileAppend a suffix to variable names, depending on the directory containing the + data file. This can be used to distinguish variables having the same name but + generated by different models or ensemble runs. suffix_file is the + name of a file describing a mapping between directories and suffixes. Each line + consists of two blank-separated fields: directory suffix. Each file + path is compared to the directories in the suffix file. If the file path is in that + directory or a subdirectory, the corresponding suffix is appended to the variable + IDs in the file. If more than one such directory is found, the first directory + found is used. If no match is made, the variable ids are not altered. Regular + expressions can be used: see the example in the Notes section.
-t timeidID of the partitioned time dimension. The default is the name of the time + dimension as determined by CDMS. See Note 1.
--time-linear tzero,delta,units[,calendar] +

Override the time dimensions(s) with a linear time dimension. The arguments + are comma-separated list:

+ +
    +
  • zero is the initial time point, a floating-point value.
  • + +
  • delta is the time delta, floating-point.
  • + +
  • units are time units as specified in the [-r] option.
  • + +
  • calendar is optional, and is specified as in the [-c] option.
  • +
+ +

If omitted, it defaults to the value specified by [-c], otherwise as specified + in the file. Example: --time-linear '0,1,months since + 1980,noleap'

+
-x xmlfileOutput file name. By default, output is written to standard output.
+ +**Notes:** + +.. raw:: html + +
    + +.. raw:: html + +
  1. + +Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be +listed in any order. Most commonly, the files are the result of a single +experiment, and the 'partitioned' dimension is time. The time dimension +of a variable is the coordinate variable having a name that starts with +'time' or having an attribute axis='T'. If this is not the case, specify +the time dimension with the -t option. The time dimension should be in +the form supported by cdtime. If this is not the case (or to override +them) use the -r option. + +.. raw:: html + +
  2. + +.. raw:: html + +
  3. + +By default, the time values are listed explicitly in the output XML. +This can cause a problem if the time dimension is very long, say for +6-hourly data. To handle this the form cdscan -i delta may be +used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given +file is not linear. + +.. raw:: html + +
  4. + +.. raw:: html + +
  5. + +Another form of the command is cdscan -l lev1,lev2,..,levn . This +asserts that the dataset is partitioned in both time and vertical level +dimensions. The level dimension of a variable is the dimension having a +name that starts with "lev", or having an attribute "axis=Z". If this is +not the case, set the level name with the -m option. + +.. raw:: html + +
  6. + +.. raw:: html + +
  7. + +:: + +

    An example of a suffix file:

    +
    /exp/pr/ncar-a _ncar-a
    +
    +/exp/pr/ecm-a \_ecm-a /exp/ta/ncar-a \_ncar-a /exp/ta/ecm-a \_ecm-a
    +
    +.. raw:: html
    +
    +   
    + +:: + +

    For all files in directory /exp/pr/ncar-a or a subdirectory, the corresponding variable ids will be appended with the suffix '_ncar-a'. Regular expressions can be used, as defined in the Python 're' module. For example, The previous example can be replaced with the single line:

    +
    /exp/[^/]*/([^/]*) _\g<1>
    +

    Note the use of parentheses to delimit a group. The syntax \g<n> refers to the nth group matched in the regular expression, with the first group being n=1. The string [^/]* matches any sequence of characters other than a forward slash.

    + +.. raw:: html + +
  8. + +.. raw:: html + +
  9. + +:: + +

    Adding or modifying attributes with the -e option:

    +
    time.units = "days since 1979-1-1"
    +

    sets the units of all variables/axes to "days since 1979-1-1". Note that since this is done before any other processing is done, it allows overriding of non-COARDS time units.

    +
    .newattr=newvalue
    +

    Set the global file attribute 'newattr' to 'newvalue'.

    + +.. raw:: html + +
  10. + +.. raw:: html + +
  11. + +:: + +

    The [--time-linear] option overrides the time values in the file(s). The resulting dimension does not have any gaps. In contrast, the [-i], [-r] options use the specified time units (from [-r]), and calendar from [-c] if specified, to convert the file times to the new units. The resulting linear dimension may have gaps.

    +

    In either case, the files are ordered by the time values in the files.

    +

    The [--time-linear] option should be used with caution, as it is applied to all the time dimensions found.

    + +.. raw:: html + +
  12. + +.. raw:: html + +
+ +7.1.3 Examples +^^^^^^^^^^^^^^ + +{% highlight text %} cdscan -c noleap -d test -x test.xml [uv]\*.nc {% +endhighlight %} + +{% highlight text %} cdscan -d pcmdi\_6h -i 0.25 -r 'days since +1979-1-1' *6h*.ctl {% endhighlight %} + +7.1.4 File Formats +^^^^^^^^^^^^^^^^^^ + +Data may be represented in a variety of self-describing binary file +formats, including + +- netCDF, the Unidata Network Common Data Format +- HDF, the NCSA Hierarchical Data Format +- GrADS/GRIB, WMO GRIB plus a GrADS control file (.ctl) The first + non-comment line of the control file must be a dset specification. +- DRS, the PCMDI legacy format. + +7.1.5 Name Aliasing +^^^^^^^^^^^^^^^^^^^ + +A problem can occur if variables in different files are defined on +different grids. What if the axis names are the same? CDMS requires that +within a dataset, axis and variable IDs (names) be unique. What should +the longitude axes be named in CDMS to ensure uniqueness? The answer is +to allow CDMS IDs to differ from file names. + +If a variable or axis has a CDMS ID which differs from its name in the +file, it is said to have an alias. The actual name of the object in the +file is stored in the attribute ``name_in_file``. ``cdscan`` uses this +mechanism (with the ``-a`` and ``s`` options) to resolve name conflicts; +a new axis or variable ID is generated, and the ``name_in_file`` is set +to the axis name in the file. + +Name aliases also can be used to enforce naming standards. For data +received from an outside organization, variable names may not be +recognized by existing applications. Often it is simpler and safer to +add an alias to the metafile rather than rewrite the data diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst new file mode 100644 index 00000000..6229e776 --- /dev/null +++ b/docs/source/manual/cdms_appendix.rst @@ -0,0 +1,1411 @@ +APPENDIX A +---------- + +CDMS Classes +~~~~~~~~~~~~ + +Figure 1, "CDMS Classes", on page 175 illustrates the class inheritance +structure of CDMS. The classes may be categorized as abstract or +concrete. Only concrete classes are meant to be used directly. In +contrast an abstract class defines the common interface of its +subclasses. For example, the class AbstractAxis2D defines the common +interface for two-dimensional coordinate axes. It has concrete +subclasses DatasetAxis2D, FileAxis2D, and TransientAxis2D, which are +used in applications. Abstract classes are denoted in italics. + +For many abstract classes there are three 'flavors' of subclass: +dataset, file, and transient. Dataset-related objects are thought of as +being contained in datasets in the sense that operations on those +objects result in I/O operations on the corresponding dataset. The same +is true of file-related objects. Objects in datasets and files are +examples of persistent objects, whose state persists after the +application exits. On the other hand, transient objects live in memory +and are not persistent. + +In general the concrete subclasses closely mirror the interface of the +abstract parent class. For this reason this document defines the +interfaces of the abstract classes, and only discusses a concrete class +in the few cases where the interface has been extended. This allows +applications to treat the behavior of, say a dataset axis and file axis, +as identical. + +.. figure:: /images/cdms_classes.jpg + :alt: + +FIGURE 1. CDMS Classes + + +APPENDIX B +---------- + +Version Notes +~~~~~~~~~~~~~ + +B.1 Version 4.0 +^^^^^^^^^^^^^^^ + +CDMS version 4.0 adds support for nonrectangular grids: + +- The following grid classes were added: AbstractHorizontalGrid, + AbstractCurve-Grid, AbstractGenericGrid, DatasetCurveGrid, + FileCurveGrid, TransientCurve-Grid, DatasetGenericGrid, + FileGenericGrid, and TransientGenericGrid. +- The following axis classes were added: AbstractCoordinateAxis, + AbstractAuxAxis1D, AbstractAxis2D, DatasetAuxAxis1D, FileAuxAxis1D, + TransientAuxAxis1D, DatasetAxis2D, FileAxis2D, and TransientAxis2D. +- The getMesh and clone methods were added for grids. +- An interface to the SCRIP package was added. + +B.2 Version 3.0 Overview +^^^^^^^^^^^^^^^^^^^^^^^^ + +CDMS version 3.0 is a significant enhancement of previous versions. The +major changes were: + +- UV-CDAT/CDMS was integrated with the Numerical Python masked array + class MA.MaskedVariable. The MV submodule was added as a wrapper + around MA. +- Methods that read data, such as subRegion, subSlice, and the slice + operations, return instances of class TransientVariable. The plot and + regrid modules were modified to handle masked array input. The + specifiers time=..., latitude=..., etc. were added to the I/O + routines. +- The class TransientVariable was added. +- A number of new functions were added, notably subRegion and subSlice, + which return instances of TransientVariable. +- When a masked array is returned from a method, it is "squeezed": + singleton dimensions are removed. In contrast, transient variables + are not squeezed. I/O functions have a squeeze option. The method + setAutoReshapeMode was removed. +- Internal attributes are handled in the InternalAttributes class. This + allows CDMS classes to be subclassed more readily. +- The class Variable was renamed DatasetVariable. +- The cu module was emulated in cdms. cu and cdms methods can be mixed. +- The code was modularized, so that Python, CDMS, and Numerical Python + can be built and installed separately. This significantly enhances + the portability of the code. + +B.3 V3.0 Details +^^^^^^^^^^^^^^^^ + +B.3.1 AbstractVariable +'''''''''''''''''''''' + +- Functions getDomain, getSlice, rank, regrid, setMissing, size, + subRegion, and subSlice were added. +- The functions getRegion, getSlice, getValue, and the slice operators + all return an instance of MA, a masked array. Singleton dimensions + are squeezed. +- The functions subRegion and subSlice return an instance of + TransientVariable. Singleton dimensions are not squeezed. +- The xxSlice and xxRegion functions have keywords time, level, + latitude, and longitude. +- The input functions have the keyword squeeze. +- AbstractVariable inherits from class Slab. The following functions + previously available in module cu are Slab methods: getattribute, + setattribute, listdimattributes, getdimattribute, listall, and info. +- AbstractVariable implements arithmetic functions, astype. +- The write function was added. + +B.3.2 AbstractAxis +'''''''''''''''''' + +- The functions asComponentTime, asRelativeTime, clone, getAxisIds, + getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were + added. +- subaxis was renamed subAxis for consistency. +- Generalized wraparound was implemented, to handle multiple cycles, + reversing, and negative strides. By default, coordinate intervals are + closed. The intersection options 'n','e','b',and 's' were added to + the interval indicator - see mapIntervalExt. + +B.3.3 AbstractDatabase +'''''''''''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.4 Dataset +''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.5 cdms module +''''''''''''''''' + +- The functions asVariable, isVariable, and createVariable were added. +- The function setAutoReshapeMode was removed. It is replaced by the + squeeze option for all I/O functions. + +B.3.6 CdmsFile +'''''''''''''' + +- The function createVariable has a keyword fill\_value. The datatype + may be a Numeric/MA typecode. +- The function write was added. + +B.3.7 CDMSError +''''''''''''''' + +- All errors are an instance of the class CDMSError. + +B.3.8 AbstractRectGrid +'''''''''''''''''''''' + +- The function createGaussianGrid was added. + +B.3.9 InternalAttributes +'''''''''''''''''''''''' + +- The class InternalAttributes was added. It has methods + add\_internal\_attribute, is\_internal\_attribute, and + replace\_external\_attributes. + +B.3.10 TransientVariable +'''''''''''''''''''''''' + +- The class TransientVariable was added. It inherits from both + AbstractVariable and MA. +- The cdms module function createVariable returns a transient variable. +- This class does not implement the functions getPaths or getTemplate. + +B.3.11 MV +''''''''' + +- The MV submodule of cdms was added. + +APPENDIX C +---------- + +``cu`` Module +~~~~~~~~~~~~~ + +The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 +it is emulated in the ``cdms`` module. It is maintained for backward +compatibility. + +The ``cu`` classes are ``Slab``, corresponding to ``TransientVariable`` +in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. + +C.1 Slab +~~~~~~~~ + +Table C.1 Slab Methods + + ++------+------+------+ +| Type | Meth | Defi | +| | od | niti | +| | | on | ++======+======+======+ +| Vari | ``ge | Get | +| ous | tatt | the | +| | ribu | valu | +| | te(n | e | +| | ame) | of | +| | `` | an | +| | | attr | +| | | ibut | +| | | e. | +| | | ``na | +| | | me`` | +| | | is | +| | | the | +| | | stri | +| | | ng | +| | | name | +| | | of | +| | | the | +| | | attr | +| | | ibut | +| | | e. | +| | | The | +| | | foll | +| | | owin | +| | | g | +| | | spec | +| | | ial | +| | | name | +| | | s | +| | | can | +| | | alwa | +| | | ys | +| | | be | +| | | used | +| | | : | +| | | 'fil | +| | | enam | +| | | e', | +| | | 'com | +| | | ment | +| | | s', | +| | | 'gri | +| | | d\_n | +| | | ame' | +| | | , | +| | | 'gri | +| | | d\_t | +| | | ype' | +| | | , | +| | | 'tim | +| | | e\_s | +| | | tati | +| | | stic | +| | | ', | +| | | 'lon | +| | | g\_n | +| | | ame' | +| | | , | +| | | 'uni | +| | | ts'. | ++------+------+------+ +| Vari | ``ge | Get | +| ous | tdim | the | +| | attr | valu | +| | ibut | e | +| | e(di | of a | +| | m, f | dime | +| | ield | nsio | +| | )`` | n | +| | | attr | +| | | ibut | +| | | e. | +| | | ``di | +| | | m`` | +| | | is | +| | | the | +| | | dime | +| | | nsio | +| | | n | +| | | numb | +| | | er, | +| | | an | +| | | inte | +| | | ger | +| | | in | +| | | the | +| | | rang | +| | | e | +| | | 0..r | +| | | ank- | +| | | 1. | +| | | ``fi | +| | | eld` | +| | | ` | +| | | is a | +| | | stri | +| | | ng, | +| | | one | +| | | of: | +| | | "nam | +| | | e", | +| | | "val | +| | | ues" | +| | | , | +| | | "len | +| | | gth" | +| | | , | +| | | "uni | +| | | ts", | +| | | "wei | +| | | ghts | +| | | ", | +| | | "bou | +| | | nds" | +| | | . | ++------+------+------+ +| None | ``in | Prin | +| | fo(f | t | +| | lag= | slab | +| | None | info | +| | , de | rmat | +| | vice | ion. | +| | =sys | If | +| | .std | ``fl | +| | out) | ag`` | +| | `` | is | +| | | nonz | +| | | ero, | +| | | dime | +| | | nsio | +| | | n | +| | | valu | +| | | es, | +| | | weig | +| | | hts, | +| | | and | +| | | boun | +| | | ds | +| | | are | +| | | also | +| | | prin | +| | | ted. | +| | | Outp | +| | | ut | +| | | is | +| | | sent | +| | | to | +| | | ``de | +| | | vice | +| | | ``. | ++------+------+------+ +| List | ``li | Prin | +| | stal | t | +| | l(al | slab | +| | l=No | info | +| | ne)` | rmat | +| | ` | ion. | +| | | If | +| | | ``al | +| | | l`` | +| | | is | +| | | nonz | +| | | ero, | +| | | dime | +| | | nsio | +| | | n | +| | | valu | +| | | es, | +| | | weig | +| | | hts, | +| | | and | +| | | boun | +| | | ds | +| | | are | +| | | also | +| | | prin | +| | | ted. | ++------+------+------+ +| List | ``li | List | +| | stdi | dime | +| | matt | nsio | +| | ribu | n | +| | tes( | attr | +| | dim, | ibut | +| | fie | es. | +| | ld)` | Retu | +| | ` | rns | +| | | a | +| | | list | +| | | of | +| | | stri | +| | | ng | +| | | attr | +| | | ibut | +| | | e | +| | | name | +| | | s | +| | | whic | +| | | h | +| | | can | +| | | be | +| | | inpu | +| | | t | +| | | to | +| | | ``ge | +| | | tdim | +| | | attr | +| | | ibut | +| | | e``. | +| | | ``di | +| | | m`` | +| | | is | +| | | the | +| | | dime | +| | | nsio | +| | | n | +| | | numb | +| | | er, | +| | | an | +| | | inte | +| | | ger | +| | | in | +| | | the | +| | | rang | +| | | e | +| | | 0..r | +| | | ank- | +| | | 1. | +| | | ``fi | +| | | eld` | +| | | ` | +| | | is a | +| | | stri | +| | | ng, | +| | | one | +| | | of: | +| | | "nam | +| | | e", | +| | | "val | +| | | ues" | +| | | , | +| | | "len | +| | | gth" | +| | | , | +| | | "uni | +| | | ts", | +| | | "wei | +| | | ghts | +| | | ", | +| | | "bou | +| | | nds" | +| | | . | ++------+------+------+ +| None | ``se | Set | +| | tatt | an | +| | ribu | attr | +| | te(n | ibut | +| | ame, | e. | +| | val | ``na | +| | ue)` | me`` | +| | ` | is | +| | | the | +| | | stri | +| | | ng | +| | | name | +| | | of | +| | | the | +| | | attr | +| | | ibut | +| | | e. | +| | | ``va | +| | | lue` | +| | | ` | +| | | is | +| | | the | +| | | valu | +| | | e | +| | | of | +| | | the | +| | | attr | +| | | ibut | +| | | e | ++------+------+------+ + +C.2 ``cuDataset`` +~~~~~~~~~~~~~~~~~ + +Table C.2 cuDataset Methods + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Type + +.. raw:: html + + + +Method + +.. raw:: html + + + +Definition + +.. raw:: html + +
+ +None + +.. raw:: html + + + +cleardefault() + +.. raw:: html + + + +Clear the default variable name. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +default\_variable(vname ) + +.. raw:: html + + + +.. raw:: html + +

+ +Set the default variable name. + +.. raw:: html + +

+ +.. raw:: html + +

+ +vname is the string variable name. + +.. raw:: html + +

+ +.. raw:: html + +
+ +Array + +.. raw:: html + + + +dimensionarray(dname, vname=None) + +.. raw:: html + + + +.. raw:: html + +

+ +Values of the axis named dname. + +.. raw:: html + +

+ +.. raw:: html + +

+ +dname is the string axis name. + +.. raw:: html + +

+ +.. raw:: html + +

+ +vname is the string variable name. The default is the variable name set +by default\_variable. + +.. raw:: html + +

+ +.. raw:: html + +
+ +Axis + +.. raw:: html + + + +dimensionobject(dname, vname=None) + +.. raw:: html + + + +Get an axis. dname is the string name of an axis. vname is a string +variable name. The default is the variable name set by +default\_variable. + +.. raw:: html + +
+ +Various + +.. raw:: html + + + +getattribute (vname, attribute) + +.. raw:: html + + + +Get an attribute value. vname is a string variable name. attribute is +the string attribute name. + +.. raw:: html + +
+ +String + +.. raw:: html + + + +getdimensionunits (dname,vname=None) + +.. raw:: html + + + +.. raw:: html + +

+ +Get the units for the given dimension. + +.. raw:: html + +

+ +.. raw:: html + +

+ +dname is the string name of an axis. + +.. raw:: html + +

+ +.. raw:: html + +

+ +vnameis a string variable name. The default is the variable name set by +default\_variable. + +.. raw:: html + +

+ +.. raw:: html + +
+ +Various + +.. raw:: html + + + +getglobal (attribute) + +.. raw:: html + + + +Get the value of the global attribute. attribute is the string attribute +name. + +.. raw:: html + +
+ +Variable + +.. raw:: html + + + +getslab (vname, \*args) + +.. raw:: html + + + +.. raw:: html + +

+ +Read data for a variable. + +.. raw:: html + +

+ +.. raw:: html + +

+ +vname is the string name of the variable. + +.. raw:: html + +

+ +.. raw:: html + +

+ +args is an argument list corresponding to the dimensions of the +variable. Arguments for each dimension can be: + +.. raw:: html + +

+ +.. raw:: html + +
    + +.. raw:: html + +
  1. + +":" or None -- select the entire dimension + +.. raw:: html + +
  2. + +.. raw:: html + +
  3. + +Ellipsis -- select entire dimensions between the ones given. + +.. raw:: html + +
  4. + +.. raw:: html + +
  5. + +a pair of successive arguments giving an interval in world coordinates. + +.. raw:: html + +
  6. + +.. raw:: html + +
  7. + +a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc') + +.. raw:: html + +
  8. + +.. raw:: html + +
+ +.. raw:: html + +
+ +List + +.. raw:: html + + + +listall (vname=None, all=None) + +.. raw:: html + + + +.. raw:: html + +

+ +Get info about data from the file. + +.. raw:: html + +

+ +.. raw:: html + +

+ +vname is the string name of the variable. + +.. raw:: html + +

+ +.. raw:: html + +

+ +If all is non-zero, dimension values, weights, and bounds are returned +as well + +.. raw:: html + +

+ +.. raw:: html + +
+ +List + +.. raw:: html + + + +listattribute (vname=None ) + +.. raw:: html + + + +Return a list of attribute names. vname is the name of the variable. The +default is the variable name set by default\_variable. + +.. raw:: html + +
+ +List + +.. raw:: html + + + +listdimension (vname=None) + +.. raw:: html + + + +Return a list of the dimension names associated with a variable. vname +is the name of the variable. The default is the variable name set by +default\_variable. + +.. raw:: html + +
+ +List + +.. raw:: html + + + +listglobal () + +.. raw:: html + + + +Return a list of the global attribute names. + +.. raw:: html + +
+ +List + +.. raw:: html + + + +listvariable () + +.. raw:: html + + + +Return a list of the variables in the file. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +showall (vname=None, all=None, device=sys.stdout) + +.. raw:: html + + + +Print a description of the variable. vname is the string name of the +variable. If all is non-zero, dimension values, weights, and bounds are +returned as well. Output is sent to device. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +showattribute (vname=None, device=sys.stdout) + +.. raw:: html + + + +Print the attributes of a variable. vname is the string name of the +variable. Output is sent to device. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +showdimension (vname=None, device=sys.stdout) + +.. raw:: html + + + +Print the dimension names associated with a variable. vname is the +string name of the variable. Output is sent to device. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +showglobal (device=sys.stdout ) + +.. raw:: html + + + +Print the global file attributes. Output is sent to device. + +.. raw:: html + +
+ +None + +.. raw:: html + + + +showvariable (device=sys.stdout ) + +.. raw:: html + + + +Print the list of variables in the file. + +.. raw:: html + +
From 36d3e04afc3367d0c6ab19b4582d398d9dacd640 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 9 May 2017 16:16:33 -0700 Subject: [PATCH 008/239] continue to work on docs --- docs/source/manual/cdms_1.rst | 368 ++++++++++++++++++++++------------ 1 file changed, 240 insertions(+), 128 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 96bfa16c..c02d2a8c 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -31,7 +31,10 @@ the eastward and northward components of wind speed, respectively, and both variables are functions of time, latitude, and longitude, then the velocity for time 0 (first index) can be calculated as ->>> from cdms import MV vel = MV.sqrt(u[0]**2 + v[0]2) +.. doctest:: + + >>> from cdms2 import MV + >>> vel = MV.sqrt(u[0]**2 + v[0]**2) This illustrates several points: @@ -60,26 +63,43 @@ control file), or PCMDI DRS. (HDF and DRS support is optional, and is configured at the time UV-CDAT is installed.) For instance, to read data from file sample.nc into variable u: - >>> import cdms - >>> f = cdms.open('sample.nc') - >>> u = f('u') +.. testsetup:: * + + import MV2 + import cdms2 + f = cdms2.open('clt.nc') + u = f('u') + v = f('v') + smallvar=MV2.reshape(MV2.arange(20),(4,5),id='small variable').astype(MV2.float32) + largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') Data can be read by index or by world coordinate values. The following reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k such that i <= k < j): - >>> u0 = f('u',time=slice(n,n+1)) +.. doctest:: + + >>> n = 0 + >>> u0 = f('u',time=slice(n,n+1)) -To read ``u`` at time 366.0: +To read ``u`` at time 1.: - >>> u1 = f('u',time=366.) +.. doctest:: + + >>> u1 = f('u',time=1.) A variable can be written to a file with the write function: - >>> g = cdms.open('sample2.nc','w') - >>> g.write(u) - - >>> g.close() +.. doctest:: + + >>> g = cdms2.open('sample2.nc','w') + >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >> g.close() 1.4 Coordinate Axes ^^^^^^^^^^^^^^^^^^^ @@ -102,27 +122,53 @@ latitude, longitude). This indicates the order of the dimensions, with the slowest- varying dimension listed first (time). The domain may be accessed with the ``getAxisList()`` method: - >>> s.getAxisList() - [ id: lat Designated a latitude axis. - units: degrees_north - Length: 64 - First: -87.8637970305 - Last: 87.8637970305 +.. doctest:: + + >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + [ id: time1 + Designated a time axis. + units: months since 1978-12 + Length: 1 + First: 1.0 + Last: 1.0 + Other axis attributes: + calendar: gregorian + axis: T + Python id: ... + , id: plev + Designated a level axis. + units: hPa + Length: 2 + First: 200.0 + Last: 850.0 Other axis attributes: - long_name: latitude - axis: Y - Python id: 833efa4, - id: lon Designated a longitude axis. - units: degrees_east Length: 128 - First: 0.0 - Last: 357.1875 + axis: Z + realtopology: linear + Python id: ... + , id: latitude1 + Designated a latitude axis. + units: degrees_north + Length: 80 + First: -88.2884 + Last: 88.2884 Other axis attributes: - modulo: 360.0 - topology: circular - long_name: longitude - axis: X - Python id: 833f174 - ] + axis: Y + realtopology: linear + Python id: ... + , id: longitude1 + Designated a longitude axis. + units: degrees_east + Length: 97 + First: -180.0 + Last: 180.0 + Other axis attributes: + axis: X + topology: circular + modulo: 360.0 + realtopology: linear + Python id: ... + ] + In the above example, the domain elements are axes that are also spatiotemporal. In general it is not always the case that an element of @@ -140,8 +186,13 @@ associated with a variable. The methods getLatitude, getLongitude, getLevel, and getTime return the associated coordinate axes. For example: - >>> t = u.getTime() >>> print t[:][ 0., 366., 731.,] - >>> print t.units 'days since 2000-1-1' +.. doctest:: + + >>> t = u.getTime() + >>> print t[:] + [ 1.] + >>> print t.units + months since 1978-12 1.5 Attributes ^^^^^^^^^^^^^^ @@ -150,7 +201,11 @@ As mentioned above, variables can have associated attributes , name-value pairs. In fact, nearly all CDMS objects can have associated attributes, which are accessed using the Python dot notation: - >>> u.units='m/s' >>> print u.units m/s +.. doctest:: + + >>> u.units='m/s' + >>> print u.units + m/s Attribute values can be strings, scalars, or 1-D Numeric arrays. @@ -162,11 +217,17 @@ written to an output file along with the variable. By default, when an attribute is set, it is treated as external. Every variable has a field attributes, a Python dictionary that defines the external attributes: - >>> print u.attributes.keys() ['datatype', 'name', 'missing_value', 'units'] +.. doctest:: + + >>> print u.attributes.keys() + ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] The Python dir command lists the internal attribute names: - >>> dir(u) ['_MaskedArray__data', '_MaskedArray__fill_value,' ..., 'id', 'parent'] +.. doctest:: + + >>> dir(u) + ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] In general internal attributes should not be modified directly. One exception is the id attribute, the name of the variable. It is used in @@ -183,14 +244,28 @@ corresponding data array element is missing or invalid. Arithmetic operations in CDMS take missing data into account. The same is true of the functions defined in the cdms.MV module. For example: - >>> a = MV.array([1,2,3]) # Create array a, with no mask - >>> b = MV.array([4,5,6]) # Same for b - >>> a+b variable_13 array([5,7,9,]) - - a[1]=MV.masked # Mask the second value of a a.mask() # View the mask [0,1,0,] - - a+b # The sum is masked also variable_14 array( data = [5,0,9,], mask = [0,1,0,], fill_value=[0,] ) +.. doctest:: + >>> a = MV2.array([1,2,3]) # Create array a, with no mask + >>> b = MV2.array([4,5,6]) # Same for b + >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS + variable_... + masked_array(data = [5 7 9], + mask = False, + fill_value = 999999) + + + >>> a[1]=MV2.masked # Mask the second value of a a.mask() + >>> a.mask + array([False, True, False], dtype=bool) + >>> a+b # The sum is masked also + variable_... + masked_array(data = [5 -- 9], + mask = [False True False], + fill_value = 999999) + + + When data is read from a file, the result variable is masked if the file variable has a missing_value attribute. The mask is set to one for those elements equal to the missing value, zero elsewhere. If no such @@ -205,7 +280,7 @@ Masking is covered in `Section 2.9 `__. See also the documentation of the Python Numeric and MA modules, on which ``cdms.MV`` is based, at -[http://numpy.sourceforge.net](http://numpy.sourceforge.net/). +`http://www.numpy.org/ `__. 1.7 File Variables ^^^^^^^^^^^^^^^^^^ @@ -230,9 +305,10 @@ passing the name of the variable, or by calling the getVariable function. Note that obtaining a file variable does not actually read the data array: - >>> f = cdms.open('sample.nc','r+') - >>> u = f.getVariable('u') # or u=f['u'] - >>> u.shape (3, 16, 32) +.. doctest:: + >>> f = cdms.open('sample.nc','r+') + >>> u = f.getVariable('u') # or u=f['u'] + >>> u.shape (3, 16, 32) File variables are also useful for fine-grained I/O. They behave like transient variables, but operations on them also affect the associated @@ -245,43 +321,69 @@ file. Specifically: - and calling a file variable like a function reads data associated with the variable: - >>> f = cdms.open('sample.nc','r+') # Open read/write - >>> uvar = f['u'] # Note square brackets - >>> uvar.shape (3, 16, 32) - - u0 = uvar[0] # Reads data from sample.nc u0.shape (16, 32) - - uvar[1]=u0 # Writes data to sample.nc uvar.units # Reads the - attribute 'm/s' - - uvar.units='meters/second' # Writes the attribute # Calling - a variable like a function reads data u24 = uvar(time=24.0) - f.close() # Save changes to sample.nc (I/O may be buffered) - +.. doctest:: + >>> f = cdms.open('sample.nc','r+') # Open read/write + >>> uvar = f['u'] # Note square brackets + >>> uvar.shape (3, 16, 32) + >>> u0 = uvar[0] # Reads data from sample.nc u0.shape (16, 32) + >>> uvar[1]=u0 # Writes data to sample.nc uvar.units + # Reads the attribute 'm/s' + >>> uvar.units='meters/second' # Writes the attribute + # Calling a variable like a function reads data + >>> u24 = uvar(time=24.0) + >>> .close() # Save changes to clt.nc (I/O may be buffered) In an interactive application, the type of variable can be determined simply by printing the variable: - >>> rlsf # Transient variable rls array( array (4,48,96) , type = f, has 18432 elements) - >>> rlsg # Dataset variable - >>> prc # File variable +- rlsf # Transient variable + - rlsf array( array (4,48,96) , type = f, has 18432 elements) +- rlsg # Dataset variable + - +- prc # File variable + - Note that the data values themselves are not printed. For transient variables, the data is printed only if the size of the array is less than the print limit . This value can be set with the function MV.set_print_limit to force the data to be printed: - >>> smallvar.size() # Number of elements 20 - >>> MV.get_print_limit() # Current limit 300 - >>> smallvar small variable array( [[ 0., 1., 2., 3.,][ 4., 5., 6., 7.,] [ 8., 9., 10., 11.,][ 12., 13., 14., 15.,] [ 16., 17., 18., 19.,] ]) - >>> largevar.size() 400 - >>> largevar large variable array( array (20,20) , type = d, has 400 elements) - >>> MV.set_print_limit(500) # Reset the print limit - >>> largevar large variable array( [[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19.,] ... ]) +.. doctest:: + >>> smallvar.size() # Number of elements 20 + >>> MV2.get_print_limit() # Current limit 1000 + 1000 + >>> smallvar + small variable + maksed_array( + [[ 0., 1., 2., 3.,] + [ 4., 5., 6., 7.,] + [ 8., 9., 10., 11.,] + [ 12., 13., 14., 15.,] + [ 16., 17., 18., 19.,]], + mask = False, + fill_value = 1e+20) + ) + >>> largevar.size() + 400 + >>> MV2.set_print_limit(100) + >>> largevar + large variable + masked_array(data = + [[ 0. 1. 2. ..., 17. 18. 19.] + [ 20. 21. 22. ..., 37. 38. 39.] + [ 40. 41. 42. ..., 57. 58. 59.] + ..., + [ 340. 341. 342. ..., 357. 358. 359.] + [ 360. 361. 362. ..., 377. 378. 379.] + [ 380. 381. 382. ..., 397. 398. 399.]], + mask = False, + fill_value = 999999.0) The datatype of the variable is determined with the typecode function: - >>> x.typecode() 'd' +.. doctest:: + >>> u.typecode() + 'f' 1.8 Dataset Variables ^^^^^^^^^^^^^^^^^^^^^ @@ -295,17 +397,30 @@ dataset typically represents the data generated by one run of a general circulation or coupled ocean-atmosphere model. For example, suppose data for variables u and v are stored in six files: -u_2000.nc, u_2001.nc, u_2002.nc, v_2000.nc, v_2001.nc , and -v_2002.nc. A metafile can be generated with the command: + +1. u_2000.nc, +2. u_2001.nc, +3. u_2002.nc, +4. v_2000.nc, +5. v_2001.nc, +6. v_2002.nc. + +A metafile can be generated with the command: {% highlight text %} $ cdscan -x cdsample.xml [uv]\*.nc {% endhighlight %} The metafile **cdsample.xml** is then used like an ordinary data file: - >>> f = cdms.open('cdsample.xml') - >>> u = f('u') - >>> u.shape (3, 16, 32) +.. doctest:: + + >>> import os + >>> os.system("cdscan -x cdsample.xml [uv]*.nc") + 0 + >>> f = cdms2.open('cdsample.xml') + >>> u = f('u') + >>> u.shape + (3, 16, 32) 1.9 Grids ^^^^^^^^^ @@ -332,7 +447,7 @@ CDMS supports two types of nonrectangular grid: which is a two-dimensional coordinate axis. Curvilinear grids are often used in ocean model applications. - A generic grid consists of a latitude and longitude axis, each of - which is an auxiliary one-dimensional coordinate axis. An auxiliary + which is an auxiliary one-dimensional coordinate axis. An auxiliarycdscan -x cdsample.xml [uv]\*.nc axis has values that are not necessarily monotonic. As the name suggests, generic grids can represent virtually any type of grid. However, it is more difficult to determine adjacency relationships @@ -352,11 +467,8 @@ grid. Note that: >>> f = cdms.open('sampleCurveGrid.nc') -lat and lon are coordinate axes, but are grouped -================================================ - -with data variables -=================== +lat and lon are coordinate axes, but are grouped with data variables +==================================================================== f.variables.keys() ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] @@ -394,9 +506,9 @@ the domain of 'sample' lat and lon are variables ... ============================= - lat.shape (128, 192) lat lat array( array (128,192) , type = d, has 24576 elements) # ... so can be used in computation + lat.shape (128, 192) lat lat array( array (128,192) , type = d, has 24576 elements) # ... so can be used in computation - >>> lat_in_radians = lat\*Numeric.pi/180.0 + >>> lat_in_radians = lat\*Numeric.pi/180.0 .. figure:: /images/curvilinear_grid.jpg :alt: curvilinear grid @@ -409,14 +521,14 @@ lat and lon are variables ... In this example variable zs is defined on a generic grid. Figure 2 illustrates the grid, in this case a geodesic grid. - >>> f.variables.keys() ['lat', 'bounds_lon', 'lon', 'zs', 'bounds_lat'] - >>> f.axes.keys() ['cell', 'nvert'] - >>> zs = f('zs') - >>> g = zs.getGrid() - >>> g - >>> lat = g.getLatitude() - >>> lon = g.getLongitude() - >>> lat.shape (2562,) + >>> f.variables.keys() ['lat', 'bounds_lon', 'lon', 'zs', 'bounds_lat'] + >>> f.axes.keys() ['cell', 'nvert'] + >>> zs = f('zs') + >>> g = zs.getGrid() + >>> g + >>> lat = g.getLatitude() + >>> lon = g.getLongitude() + >>> lat.shape (2562,) >>> lon.shape (2562,) # variable zs is defined in terms of a single index coordinate axis, 'cell' @@ -435,7 +547,7 @@ lat and lon are one-dimensional, 'auxiliary' coordinate axes: values are not monotonic ============================== - lat. **class** + lat. **class** .. figure:: /images/generic_grid.jpg :alt: generic grid @@ -450,16 +562,16 @@ representation. Similarly, a rectangular grid can be represented as curvilinear. The method toCurveGrid is used to convert a non-generic grid to curvilinear representation: - >>> import cdms - >>> f = cdms.open('clt.nc') - >>> clt = f('clt') - >>> rectgrid = clt.getGrid() - >>> rectgrid.shape (46, 72) - >>> curvegrid = rectgrid.toCurveGrid() - >>> curvegrid - >>> genericgrid = curvegrid.toGenericGrid() - >>> genericgrid - >>> + >>> import cdms + >>> f = cdms.open('clt.nc') + >>> clt = f('clt') + >>> rectgrid = clt.getGrid() + >>> rectgrid.shape (46, 72) + >>> curvegrid = rectgrid.toCurveGrid() + >>> curvegrid + >>> genericgrid = curvegrid.toGenericGrid() + >>> genericgrid + >>> 1.10 Regridding ^^^^^^^^^^^^^^^ @@ -482,19 +594,19 @@ The built-in CDMS regridder is used to transform data from one rectangular grid to another. For example, to regrid variable ``u`` (from a rectangular grid) to a 96x192 rectangular Gaussian grid: - >>> u = f('u') - >>> u.shape (3, 16, 32) - >>> t63_grid = cdms.createGaussianGrid(96) - >>> u63 = u.regrid(t63_grid) - >>> u63.shape (3, 96, 192) + >>> u = f('u') + >>> u.shape (3, 16, 32) + >>> t63_grid = cdms.createGaussianGrid(96) + >>> u63 = u.regrid(t63_grid) + >>> u63.shape (3, 96, 192) To regrid a variable ``uold`` to the same grid as variable ``vnew``: - >>> uold.shape (3, 16, 32) - >>> vnew.shape (3, 96, 192) - >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew - >>> u63 = u.regrid(t63_grid) - >>> u63.shape (3, 96, 192) + >>> uold.shape (3, 16, 32) + >>> vnew.shape (3, 96, 192) + >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew + >>> u63 = u.regrid(t63_grid) + >>> u63.shape (3, 96, 192) 1.10.2 SCRIP Regridder '''''''''''''''''''''' @@ -543,7 +655,7 @@ regrid.readRegridder(remapf) remapf.close() Regrid the source variable ========================== -popdat = regridf(dat) +popdat = regridf(dat) Regridding is discussed in `Chapter 4 `__. @@ -563,11 +675,11 @@ Relative time is time relative to a fixed base time. It consists of: For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and units=" days since 1996-1-1". To create a relative time type: - >>> import cdtime - >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") - >>> rt 28.00 days since 1996-1-1 - >>> rt.value 28.0 - >>> rt.units 'days since 1996-1-1' + >>> import cdtime + >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") + >>> rt 28.00 days since 1996-1-1 + >>> rt.value 28.0 + >>> rt.units 'days since 1996-1-1' A component time consists of the integer fields year, month, day, hour, minute , and the floating-point field second . For example: @@ -632,13 +744,13 @@ To generate a plot: For example: - >>> import cdms, vcs - >>> f = cdms.open('sample.nc') - >>> f['time'][:] # Print the time coordinates [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] - >>> precip = f('prc', time=24.0) # Read precip data - >>> precip.shape (1, 32, 64) - >>> w = vcs.init() # Initialize a canvas 'Template' is currently set to P_default. Graphics method 'Boxfill' is currently set to Gfb_default. - >>> w.plot(precip) # Generate a plot (generates a boxfill plot) + >>> import cdms, vcs + >>> f = cdms.open('sample.nc') + >>> f['time'][:] # Print the time coordinates [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] + >>> precip = f('prc', time=24.0) # Read precip data + >>> precip.shape (1, 32, 64) + >>> w = vcs.init() # Initialize a canvas 'Template' is currently set to P_default. Graphics method 'Boxfill' is currently set to Gfb_default. + >>> w.plot(precip) # Generate a plot (generates a boxfill plot) By default for rectangular grids, a boxfill plot of the lat-lon slice is produced. Since variable precip includes information on time, latitude, @@ -667,9 +779,9 @@ Protocol (LDAP). Here is an example of accessing data via a database: - >>> db = cdms.connect() # Connect to the default database. - >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. - >>> f.variables.keys() # List the variables in the dataset. + >>> db = cdms.connect() # Connect to the default database. + >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. + >>> f.variables.keys() # List the variables in the dataset. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] From e782886d2e3e322901d9a7132ad6ec3d3b375d82 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 10 May 2017 15:03:51 -0700 Subject: [PATCH 009/239] sphinx doctest in manual.rst --- docs/source/conf.py | 1 + docs/source/manual/cdms_1.rst | 268 ++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 127 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4b5150d1..6bbf35f1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,6 +52,7 @@ 'easydev.copybutton', 'sphinx.ext.todo', 'sphinx.ext.autodoc', + 'sphinx.ext.graphviz', 'sphinx.ext.doctest', 'sphinx.ext.napoleon' ] diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index c02d2a8c..9c00b1de 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -248,7 +248,7 @@ is true of the functions defined in the cdms.MV module. For example: >>> a = MV2.array([1,2,3]) # Create array a, with no mask >>> b = MV2.array([4,5,6]) # Same for b - >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS + >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE variable_... masked_array(data = [5 7 9], mask = False, @@ -258,7 +258,7 @@ is true of the functions defined in the cdms.MV module. For example: >>> a[1]=MV2.masked # Mask the second value of a a.mask() >>> a.mask array([False, True, False], dtype=bool) - >>> a+b # The sum is masked also + >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE variable_... masked_array(data = [5 -- 9], mask = [False True False], @@ -306,9 +306,10 @@ function. Note that obtaining a file variable does not actually read the data array: .. doctest:: - >>> f = cdms.open('sample.nc','r+') + >>> u = f.getVariable('u') # or u=f['u'] - >>> u.shape (3, 16, 32) + >>> u.shape + (1, 2, 80, 97) File variables are also useful for fine-grained I/O. They behave like transient variables, but operations on them also affect the associated @@ -322,52 +323,45 @@ file. Specifically: with the variable: .. doctest:: - >>> f = cdms.open('sample.nc','r+') # Open read/write + + >>> import os + >>> os.system("cp clt.nc /tmp") + 0 + >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write >>> uvar = f['u'] # Note square brackets - >>> uvar.shape (3, 16, 32) - >>> u0 = uvar[0] # Reads data from sample.nc u0.shape (16, 32) - >>> uvar[1]=u0 # Writes data to sample.nc uvar.units - # Reads the attribute 'm/s' - >>> uvar.units='meters/second' # Writes the attribute - # Calling a variable like a function reads data - >>> u24 = uvar(time=24.0) - >>> .close() # Save changes to clt.nc (I/O may be buffered) - -In an interactive application, the type of variable can be determined -simply by printing the variable: - -- rlsf # Transient variable - - rlsf array( array (4,48,96) , type = f, has 18432 elements) -- rlsg # Dataset variable - - -- prc # File variable - - - -Note that the data values themselves are not printed. For transient -variables, the data is printed only if the size of the array is less + >>> uvar.shape + (1, 2, 80, 97) + >>> u0 = uvar[0] # Reads data from sample.nc + >>> u0.shape + (2, 80, 97) + >>> uvar[1]=u0 # Writes data to sample.nc + >>> uvar.units # Reads the attribute 'm/s' + 'm/s' + >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data + >>> f.close() # Save changes to clt.nc (I/O may be buffered) + + +For transient variables, the data is printed only if the size of the array is less than the print limit . This value can be set with the function MV.set_print_limit to force the data to be printed: .. doctest:: - >>> smallvar.size() # Number of elements 20 + >>> MV2.get_print_limit() # Current limit 1000 1000 - >>> smallvar - small variable - maksed_array( - [[ 0., 1., 2., 3.,] - [ 4., 5., 6., 7.,] - [ 8., 9., 10., 11.,] - [ 12., 13., 14., 15.,] - [ 16., 17., 18., 19.,]], - mask = False, - fill_value = 1e+20) - ) - >>> largevar.size() - 400 + >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + small variable + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.] + [ 10. 11. 12. 13. 14.] + [ 15. 16. 17. 18. 19.]], + mask = + False, + fill_value = 999999.0) >>> MV2.set_print_limit(100) - >>> largevar - large variable + >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + large variable masked_array(data = [[ 0. 1. 2. ..., 17. 18. 19.] [ 20. 21. 22. ..., 37. 38. 39.] @@ -382,6 +376,7 @@ MV.set_print_limit to force the data to be printed: The datatype of the variable is determined with the typecode function: .. doctest:: + >>> u.typecode() 'f' @@ -447,7 +442,7 @@ CDMS supports two types of nonrectangular grid: which is a two-dimensional coordinate axis. Curvilinear grids are often used in ocean model applications. - A generic grid consists of a latitude and longitude axis, each of - which is an auxiliary one-dimensional coordinate axis. An auxiliarycdscan -x cdsample.xml [uv]\*.nc + which is an auxiliary one-dimensional coordinate axis. An auxiliary axis has values that are not necessarily monotonic. As the name suggests, generic grids can represent virtually any type of grid. However, it is more difficult to determine adjacency relationships @@ -465,55 +460,67 @@ grid. Note that: lon ), each a two-dimensional coordinate axis. - lat and lon each have domain ( y , x ) - >>> f = cdms.open('sampleCurveGrid.nc') - -lat and lon are coordinate axes, but are grouped with data variables -==================================================================== - - f.variables.keys() ['lat', 'sample', 'bounds_lon', 'lon', - 'bounds_lat'] - -y and x are index coordinate axes -================================= - - f.axes.keys() ['y', 'x', 'nvert'] # Read data for variable - sample sample = f('sample') - -The associated grid g is curvilinear -==================================== - - g = sample.getGrid() g - -The domain of the variable consists of index axes -================================================= - - sample.getAxisIds() ['y', 'x'] - -Get the coordinate axes associated with the grid -================================================ - - lat = g.getLatitude() # or sample.getLatitude() lon = - g.getLongitude() # or sample.getLongitude() - -lat and lon have the same domain, a subset of -============================================= - -the domain of 'sample' -====================== - - lat.getAxisIds() ['y', 'x'] +.. doctest:: -lat and lon are variables ... -============================= + >>> f = cdms2.open('sampleCurveGrid4.nc') - lat.shape (128, 192) lat lat array( array (128,192) , type = d, has 24576 elements) # ... so can be used in computation - >>> lat_in_radians = lat\*Numeric.pi/180.0 + >>> # lat and lon are coordinate axes, but are grouped with data variables + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] -.. figure:: /images/curvilinear_grid.jpg + >>> # y and x are index coordinate axes + >>> f.axes.keys() + ['y', 'x', 'nvert'] + + >>> # Read data for variable sample + >>> sample = f('sample') + + >>> # The associated grid g is curvilinear + >>> g = sample.getGrid() + + >>> # The domain of the variable consfigists of index axes + >>> sample.getAxisIds() + ['y', 'x'] + + >>> # Get the coordinate axes associated with the grid + >>> lat = g.getLatitude() # or sample.getLatitude() + >>> lon = g.getLongitude() # or sample.getLongitude() + + >>> # lat and lon have the same domain, a subset of the domain of 'sample' + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are variables ... + >>> lat.shape + (32, 48) + + >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + lat + masked_array(data = + [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 + -76.08465554] + [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 + -73.92641847] + [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 + -71.44420823] + ..., + [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 + 42.32854943] + [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 + 42.70106429] + [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 + 43.0307341 ]], + mask = + False, + fill_value = 1e+20) + + >>> lat_in_radians = lat*MV2.pi/180.0 + +.. figure:: images/curvilinear_grid.jpg :alt: curvilinear grid - curvilinear grid + Figure1: Curvilinear Grid 1.9.2 Example: a generic grid ''''''''''''''''''''''''''''' @@ -521,40 +528,42 @@ lat and lon are variables ... In this example variable zs is defined on a generic grid. Figure 2 illustrates the grid, in this case a geodesic grid. - >>> f.variables.keys() ['lat', 'bounds_lon', 'lon', 'zs', 'bounds_lat'] - >>> f.axes.keys() ['cell', 'nvert'] - >>> zs = f('zs') - >>> g = zs.getGrid() - >>> g - >>> lat = g.getLatitude() - >>> lon = g.getLongitude() - >>> lat.shape (2562,) - >>> lon.shape (2562,) # variable zs is defined in terms of a single index coordinate - -axis, 'cell' -============ - - zs.shape (2562,) zs.getAxisIds() ['cell'] - -lat and lon are also defined in terms of the cell axis -====================================================== - - lat.getAxisIds() ['cell'] - -lat and lon are one-dimensional, 'auxiliary' coordinate -======================================================= - -axes: values are not monotonic -============================== - - lat. **class** +.. doctest:: -.. figure:: /images/generic_grid.jpg + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + >>> f.axes.keys() + ['y', 'x', 'nvert'] + >>> zs = f('sample') + >>> g = zs.getGrid() + >>> g + + >>> lat = g.getLatitude() + >>> lon = g.getLongitude() + >>> lat.shape + (32, 48) + >>> lon.shape # variable zs is defined in terms of a single index coordinate + (32, 48) + >>> # axis, 'cell' + >>> zs.shape + (32, 48) + >>> zs.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are also defined in terms of the cell axis + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are one-dimensional, 'auxiliary' coordinate + >>> # axes: values are not monotonic + >>> lat.__class__ + + + +.. figure:: images/generic_grid.jpg :alt: generic grid - generic grid - -FIGURE 2. Generic grid + Figure 2: Generic Grid Generic grids can be used to represent any of the grid types. The method toGenericGrid can be applied to any grid to convert it to a generic @@ -562,16 +571,21 @@ representation. Similarly, a rectangular grid can be represented as curvilinear. The method toCurveGrid is used to convert a non-generic grid to curvilinear representation: - >>> import cdms - >>> f = cdms.open('clt.nc') - >>> clt = f('clt') - >>> rectgrid = clt.getGrid() - >>> rectgrid.shape (46, 72) - >>> curvegrid = rectgrid.toCurveGrid() - >>> curvegrid - >>> genericgrid = curvegrid.toGenericGrid() - >>> genericgrid - >>> +.. testcode:: * + + >>> f = cdms2.open('clt.nc') + >>> clt = f('clt') + >>> rectgrid = clt.getGrid() + >>> rectgrid.shape + >>> curvegrid = rectgrid.toCurveGrid() + >>> curvegrid + >>> genericgrid = curvegrid.toGenericGrid() + >>> genericgrid + +.. testoutput:: + + (46, 72) + 1.10 Regridding ^^^^^^^^^^^^^^^ From 855ac00c22772943a76d0a7990f78c1936538260 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 16 May 2017 12:33:56 -0700 Subject: [PATCH 010/239] chapter 1 continu --- docs/source/manual/cdms_1.rst | 135 ++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 9c00b1de..aad1ba00 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -402,8 +402,7 @@ For example, suppose data for variables u and v are stored in six files: A metafile can be generated with the command: -{% highlight text %} $ cdscan -x cdsample.xml [uv]\*.nc {% endhighlight -%} +**$ cdscan -x cdsample.xml [uv]*.nc** The metafile **cdsample.xml** is then used like an ordinary data file: @@ -608,19 +607,26 @@ The built-in CDMS regridder is used to transform data from one rectangular grid to another. For example, to regrid variable ``u`` (from a rectangular grid) to a 96x192 rectangular Gaussian grid: - >>> u = f('u') - >>> u.shape (3, 16, 32) - >>> t63_grid = cdms.createGaussianGrid(96) - >>> u63 = u.regrid(t63_grid) - >>> u63.shape (3, 96, 192) +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') + >>> u.shape + ((1, 2, 80, 97) + >>> t63_grid = cdms2.createGaussianGrid(96) + >>> u63 = u.regrid(t63_grid) + >>> u63.shape + (3, 96, 192) To regrid a variable ``uold`` to the same grid as variable ``vnew``: - >>> uold.shape (3, 16, 32) - >>> vnew.shape (3, 96, 192) - >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew - >>> u63 = u.regrid(t63_grid) - >>> u63.shape (3, 96, 192) +.. doctest:: + + >>> uold.shape(3, 16, 32) + >>> vnew.shape(3, 96, 192) + >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew + >>> u63 = u.regrid(t63_grid) + >>> u63.shape(3, 96, 192) 1.10.2 SCRIP Regridder '''''''''''''''''''''' @@ -651,27 +657,25 @@ For example, suppose the source data on a T42 grid is to be mapped to a POP curvilinear grid. Assume that SCRIP generated a remapping file named rmp_T42_to_POP43_conserv.nc: - >>> # Import regrid package for regridder functions - -import regrid, cdms - -Get the source variable -======================= - -f = cdms.open('sampleT42Grid.nc') dat = f('src_array') f.close() - -Read the regridder from the remapper file -========================================= - -remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') regridf = -regrid.readRegridder(remapf) remapf.close() - -Regrid the source variable -========================== +.. doctest:: -popdat = regridf(dat) + >>> # Import regrid package for regridder functions + >>> import regrid, cdms + + >>> # Get the source variable + >>> f = cdms.open('sampleT42Grid.nc') + >>> dat = f('src_array') + >>> f.close() + + >>> # Read the regridder from the remapper file + >>> remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid.readRegridder(remapf) + >>> remapf.close() + + >>> # Regrid the source variable + >>> popdat = regridf(dat) -Regridding is discussed in `Chapter 4 `__. +Regridding is discussed in `Chapter 4 `__. 1.11 Time types ^^^^^^^^^^^^^^^ @@ -689,22 +693,28 @@ Relative time is time relative to a fixed base time. It consists of: For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and units=" days since 1996-1-1". To create a relative time type: - >>> import cdtime - >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") - >>> rt 28.00 days since 1996-1-1 - >>> rt.value 28.0 - >>> rt.units 'days since 1996-1-1' +.. doctest:: + + >>> import cdtime + >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") + >>> rt + 28.00 days since 1996-1-1 + >>> rt.value + 28.0 + >>> rt.units + 'days since 1996-1-1' A component time consists of the integer fields year, month, day, hour, minute , and the floating-point field second . For example: -:: + +.. doctest:: >>> ct = cdtime.comptime(1996,2,28,12,10,30) >>> ct - -2-28 12:10:30.0 - ct.year - ct.month + -2-28 12:10:30.0 + ct.year + ct.month The conversion functions tocomp and torel convert between the two @@ -712,31 +722,32 @@ representations. For instance, suppose that the time axis of a variable is represented in units " days since 1979" . To find the coordinate value corresponding to January 1, 1990: -:: +.. doctest:: >>> ct = cdtime.comptime(1990,1) >>> rt = ct.torel("days since 1979") >>> rt.value - .0 + .0 Time values can be used to specify intervals of time to read. The syntax time=(c1,c2) specifies that data should be read for times t such that c1<=t<=c2: -:: +.. doctest:: >>> c1 = cdtime.comptime(1990,1) >>> c2 = cdtime.comptime(1991,1) >>> ua = f[' ua'] >>> ua.shape - 480, 17, 73, 144) + 480, 17, 73, 144) >>> x = ua.subRegion(time=(c1,c2)) >>> x.shape - 12, 17, 73, 144) + 12, 17, 73, 144) or string representations can be used: -:: + +.. doctest:: >>> x = ua.subRegion(time=('1990-1','1991-1')) @@ -758,13 +769,20 @@ To generate a plot: For example: - >>> import cdms, vcs - >>> f = cdms.open('sample.nc') - >>> f['time'][:] # Print the time coordinates [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] - >>> precip = f('prc', time=24.0) # Read precip data - >>> precip.shape (1, 32, 64) - >>> w = vcs.init() # Initialize a canvas 'Template' is currently set to P_default. Graphics method 'Boxfill' is currently set to Gfb_default. - >>> w.plot(precip) # Generate a plot (generates a boxfill plot) +.. doctest:: + + >>> import cdms, vcs + >>> f = cdms.open('sample.nc') + >>> f['time'][:] # Print the time coordinates + [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] + >>> precip = f('prc', time=24.0) # Read precip data + >>> precip.shape + (1, 32, 64) + >>> w = vcs.init() # Initialize a canvas + 'Template' is currently set to P_default. + Graphics method 'Boxfill' is currently set to Gfb_default. + >>> w.plot(precip) # Generate a plot + (generates a boxfill plot) By default for rectangular grids, a boxfill plot of the lat-lon slice is produced. Since variable precip includes information on time, latitude, @@ -793,10 +811,13 @@ Protocol (LDAP). Here is an example of accessing data via a database: - >>> db = cdms.connect() # Connect to the default database. - >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. - >>> f.variables.keys() # List the variables in the dataset. -['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] +.. doctest:: + + >>> db = cdms.connect() # Connect to the default database. + >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. + >>> f.variables.keys() # List the variables in the dataset. + ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] + Databases are discussed further in `Section 2.7 `__. From 2cad39cc4d0b36c1db9a6033dd2a2d7a5c632315 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 5 Jun 2017 13:23:17 -0700 Subject: [PATCH 011/239] add requirments.txt for read-the-doc --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..e48f7c2c --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +easydev From 2ba86ab2549aa9cd706cb7f90179e95c68f5cc6b Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 5 Jun 2017 13:25:29 -0700 Subject: [PATCH 012/239] move requirements.txt into docs dir --- requirements.txt => docs/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename requirements.txt => docs/requirements.txt (100%) diff --git a/requirements.txt b/docs/requirements.txt similarity index 100% rename from requirements.txt rename to docs/requirements.txt From f14455ed89caf9e2cd672f618e86bbbdb921e8dc Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Jun 2017 15:21:30 -0700 Subject: [PATCH 013/239] add requirements --- docs/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index e48f7c2c..7dd06d02 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,3 @@ easydev +cdat_info + From 188946ee751ba9a4c429286d5868bd177193a751 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 3 Oct 2017 18:20:14 -0700 Subject: [PATCH 014/239] Chapter 2 --- docs/source/AbstractAxis.rst | 8 - docs/source/AbstractVariable.rst | 8 - docs/source/Lib.rst | 6 - docs/source/MV2.rst | 6 - docs/source/Makefile | 192 - docs/source/api.rst | 6 - docs/source/auxcoord.rst | 6 - docs/source/avariable.rst | 6 - docs/source/axis.rst | 6 - docs/source/bindex.rst | 6 - docs/source/cache.rst | 6 - docs/source/cdmsfile.rst | 8 - docs/source/cdmsobj.rst | 8 - docs/source/conf.py | 6 +- docs/source/convention.rst | 6 - docs/source/coord.rst | 6 - docs/source/database.rst | 6 - docs/source/dataset.rst | 6 - docs/source/error.rst | 6 - docs/source/fvariable.rst | 6 - docs/source/gengrid.rst | 6 - docs/source/globe.png | Bin 30178 -> 0 bytes docs/source/grid.rst | 6 - docs/source/gsHost.rst | 6 - docs/source/gsStaticVariable.rst | 6 - docs/source/gsTimeVariable.rst | 6 - docs/source/hgrid.rst | 6 - docs/source/index.rst | 46 +- docs/source/manual/cdms.rst | 283 - docs/source/manual/cdms_1.rst | 149 +- docs/source/manual/cdms_2.rst | 11388 +++++++------------------ docs/source/manual/cdms_3.rst | 659 -- docs/source/manual/cdms_4.rst | 1282 --- docs/source/manual/cdms_5.rst | 486 -- docs/source/manual/cdms_6.rst | 3128 ------- docs/source/manual/cdms_7.rst | 423 - docs/source/manual/cdms_appendix.rst | 1411 --- docs/source/mvBaseWriter.rst | 6 - docs/source/mvCdmsRegrid.rst | 6 - docs/source/mvSphereMesh.rst | 6 - docs/source/mvVsWriter.rst | 6 - docs/source/selectors.rst | 6 - docs/source/sliceut.rst | 6 - docs/source/tvariable.rst | 6 - docs/source/uvcdat.png | Bin 37672 -> 0 bytes docs/source/variable.rst | 6 - 46 files changed, 3396 insertions(+), 16257 deletions(-) delete mode 100644 docs/source/AbstractAxis.rst delete mode 100644 docs/source/AbstractVariable.rst delete mode 100644 docs/source/Lib.rst delete mode 100644 docs/source/MV2.rst delete mode 100644 docs/source/Makefile delete mode 100644 docs/source/api.rst delete mode 100644 docs/source/auxcoord.rst delete mode 100644 docs/source/avariable.rst delete mode 100644 docs/source/axis.rst delete mode 100644 docs/source/bindex.rst delete mode 100644 docs/source/cache.rst delete mode 100644 docs/source/cdmsfile.rst delete mode 100644 docs/source/cdmsobj.rst delete mode 100644 docs/source/convention.rst delete mode 100644 docs/source/coord.rst delete mode 100644 docs/source/database.rst delete mode 100644 docs/source/dataset.rst delete mode 100644 docs/source/error.rst delete mode 100644 docs/source/fvariable.rst delete mode 100644 docs/source/gengrid.rst delete mode 100644 docs/source/globe.png delete mode 100644 docs/source/grid.rst delete mode 100644 docs/source/gsHost.rst delete mode 100644 docs/source/gsStaticVariable.rst delete mode 100644 docs/source/gsTimeVariable.rst delete mode 100644 docs/source/hgrid.rst delete mode 100644 docs/source/manual/cdms.rst delete mode 100644 docs/source/manual/cdms_3.rst delete mode 100644 docs/source/manual/cdms_4.rst delete mode 100644 docs/source/manual/cdms_5.rst delete mode 100644 docs/source/manual/cdms_6.rst delete mode 100644 docs/source/manual/cdms_7.rst delete mode 100644 docs/source/manual/cdms_appendix.rst delete mode 100644 docs/source/mvBaseWriter.rst delete mode 100644 docs/source/mvCdmsRegrid.rst delete mode 100644 docs/source/mvSphereMesh.rst delete mode 100644 docs/source/mvVsWriter.rst delete mode 100644 docs/source/selectors.rst delete mode 100644 docs/source/sliceut.rst delete mode 100644 docs/source/tvariable.rst delete mode 100644 docs/source/uvcdat.png delete mode 100644 docs/source/variable.rst diff --git a/docs/source/AbstractAxis.rst b/docs/source/AbstractAxis.rst deleted file mode 100644 index 3d6314d6..00000000 --- a/docs/source/AbstractAxis.rst +++ /dev/null @@ -1,8 +0,0 @@ -AbstractAxis -============ - -.. py:currentmodule:: cdms2.axis - -.. autoclass:: AbstractAxis - :members: - diff --git a/docs/source/AbstractVariable.rst b/docs/source/AbstractVariable.rst deleted file mode 100644 index a7db97e0..00000000 --- a/docs/source/AbstractVariable.rst +++ /dev/null @@ -1,8 +0,0 @@ -AbstractVariable -================ - -.. py:currentmodule:: cdms2.avariable - -.. autoclass:: AbstractVariable - :members: - diff --git a/docs/source/Lib.rst b/docs/source/Lib.rst deleted file mode 100644 index 8f8e34d3..00000000 --- a/docs/source/Lib.rst +++ /dev/null @@ -1,6 +0,0 @@ -Lib -======== - -.. automodule:: cdms2.Lib - :members: - diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst deleted file mode 100644 index d9c3a216..00000000 --- a/docs/source/MV2.rst +++ /dev/null @@ -1,6 +0,0 @@ -MV2 -======== - -.. automodule:: cdms2.MV2 - :members: - diff --git a/docs/source/Makefile b/docs/source/Makefile deleted file mode 100644 index 314da453..00000000 --- a/docs/source/Makefile +++ /dev/null @@ -1,192 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdms2.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdms2.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/cdms2" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdms2" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index 5a561c63..00000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,6 +0,0 @@ -MV2 -======== - -.. automodule:: cdms2.MV2 - :members: - diff --git a/docs/source/auxcoord.rst b/docs/source/auxcoord.rst deleted file mode 100644 index 892cff84..00000000 --- a/docs/source/auxcoord.rst +++ /dev/null @@ -1,6 +0,0 @@ -auxcoord -======== - -.. automodule:: cdms2.auxcoord - :members: - diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst deleted file mode 100644 index ae0cb3ca..00000000 --- a/docs/source/avariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -avariable -======== - -.. automodule:: cdms2.avariable - :members: - diff --git a/docs/source/axis.rst b/docs/source/axis.rst deleted file mode 100644 index 1d0e9aee..00000000 --- a/docs/source/axis.rst +++ /dev/null @@ -1,6 +0,0 @@ -axis -======== - -.. automodule:: cdms2.axis - :members: - diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst deleted file mode 100644 index 84f1d88a..00000000 --- a/docs/source/bindex.rst +++ /dev/null @@ -1,6 +0,0 @@ -bindex -======== - -.. automodule:: cdms2.bindex - :members: - diff --git a/docs/source/cache.rst b/docs/source/cache.rst deleted file mode 100644 index 9904d1fa..00000000 --- a/docs/source/cache.rst +++ /dev/null @@ -1,6 +0,0 @@ -cache -======== - -.. automodule:: cdms2.cache - :members: - diff --git a/docs/source/cdmsfile.rst b/docs/source/cdmsfile.rst deleted file mode 100644 index b4882112..00000000 --- a/docs/source/cdmsfile.rst +++ /dev/null @@ -1,8 +0,0 @@ -CdmsFile -======== - -.. py:currentmodule:: cdms2.dataset - -.. autoclass:: CdmsFile - :members: - diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst deleted file mode 100644 index c66c4576..00000000 --- a/docs/source/cdmsobj.rst +++ /dev/null @@ -1,8 +0,0 @@ -cdmsobj -======= - -.. py:currentmodule:: cdms2.cdmsobj - -.. autoclass:: CdmsObj - :members: - diff --git a/docs/source/conf.py b/docs/source/conf.py index 6bbf35f1..8cf53b44 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ #sys.path.insert(0, os.path.abspath('.')) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) -sys.path.insert(0,"/software/anaconda2/envs/uvcdat-2.6.1/lib/python2.7/site-packages") +sys.path.insert(0,"/software/anaconda2/envs/dev/lib/python2.7/site-packages") print os.path.join(sys.prefix,"lib","python2.7","site-packages") # -- General configuration ------------------------------------------------ @@ -171,12 +171,12 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'uvcdat.png' +html_logo = 'manual/images/uvcdat.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = 'globe.png' +# html_favicon = 'globe.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/docs/source/convention.rst b/docs/source/convention.rst deleted file mode 100644 index e4079a75..00000000 --- a/docs/source/convention.rst +++ /dev/null @@ -1,6 +0,0 @@ -convention -======== - -.. automodule:: cdms2.convention - :members: - diff --git a/docs/source/coord.rst b/docs/source/coord.rst deleted file mode 100644 index 0cb886a2..00000000 --- a/docs/source/coord.rst +++ /dev/null @@ -1,6 +0,0 @@ -coord -======== - -.. automodule:: cdms2.coord - :members: - diff --git a/docs/source/database.rst b/docs/source/database.rst deleted file mode 100644 index ae772ae8..00000000 --- a/docs/source/database.rst +++ /dev/null @@ -1,6 +0,0 @@ -database -======== - -.. automodule:: cdms2.database - :members: - diff --git a/docs/source/dataset.rst b/docs/source/dataset.rst deleted file mode 100644 index b59562aa..00000000 --- a/docs/source/dataset.rst +++ /dev/null @@ -1,6 +0,0 @@ -dataset -======== - -.. automodule:: cdms2.dataset - :members: - diff --git a/docs/source/error.rst b/docs/source/error.rst deleted file mode 100644 index 8b37e9cd..00000000 --- a/docs/source/error.rst +++ /dev/null @@ -1,6 +0,0 @@ -error -======== - -.. automodule:: cdms2.error - :members: - diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst deleted file mode 100644 index 18b3288e..00000000 --- a/docs/source/fvariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -fvariable -======== - -.. automodule:: cdms2.fvariable - :members: - diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst deleted file mode 100644 index 41b08364..00000000 --- a/docs/source/gengrid.rst +++ /dev/null @@ -1,6 +0,0 @@ -gengrid -======== - -.. automodule:: cdms2.gengrid - :members: - diff --git a/docs/source/globe.png b/docs/source/globe.png deleted file mode 100644 index 75f6d8bd5d0c5ad550a606c5ace024d48aef6c47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30178 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 -'''''''''''''''''''''''''''''''''''''''' - -- `1.1 Overview `__ -- `1.2 Variables `__ -- `1.3 File I/O `__ -- `1.4 Coordinate Axes `__ -- `1.5 Attributes `__ -- `1.6 Masked values `__ -- `1.7 File Variables `__ -- `1.8 Dataset Variables `__ -- `1.9 Grids `__ - - - `1.9.1 Example: a curvilinear grid `__ - - `1.9.2 Example: a generic grid `__ - -- `1.10 Regridding `__ - - - `1.10.1 CDMS Regridder `__ - - `1.10.2 SCRIP Regridder `__ - -- `1.11 Time types `__ -- `1.12 Plotting data `__ -- `1.13 Databases `__ - -`CHAPTER 2 CDMS Python Application Programming Interface `__ -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -- `2.1 Overview `__ - - - `Table 2.1 Python types used in CDMS `__ - -- `2.2 A first example `__ -- `2.3 cdms module `__ - - - `Table 2.2 cdms module functions `__ - - `Table 2.3 Class Tags `__ - -- `2.4 CdmsObj `__ - - - `Table 2.4 Attributes common to all CDMS - objects `__ - - `Table 2.5 Getting and setting - attributes `__ - -- `2.5 CoordinateAxis `__ - - - `Table 2.6 CoordinateAxis types `__ - - `Table 2.7 CoordinateAxis Internal - Attributes `__ - - `Table 2.8 Axis Constructors `__ - - `Table 2.9 CoordinateAxis Methods `__ - - `Table 2.10 Axis Methods, additional to CoordinateAxis - methods `__ - - `Table 2.11 Axis Slice Operators `__ - -- `2.6 CdmsFile `__ - - - `Table 2.12 CdmsFile Internal - Attributes `__ - - `Table 2.13 CdmsFile Constructors `__ - - `Table 2.14 CdmsFile Methods `__ - - `Table 2.15 CDMS Datatypes `__ - -- `2.7 Database `__ - - - `2.7.1 Overview `__ - - - `Table 2.16 Database Internal - Attributes `__ - - `Table 2.17 Database Constructors `__ - - `Table 2.18 Database Methods `__ - - - `2.7.2 Searching a database `__ - - - `Table 2.19 SearchResult Methods `__ - - `Table 2.20 ResultEntry Attributes `__ - - `Table 2.21 ResultEntry Methods `__ - - - `2.7.3 Accessing data `__ - - `2.7.4 Examples of database searches `__ - -- `2.8 Dataset `__ - - - `Table 2.22 Dataset Internal - Attributes `__ - - `Table 2.23 Dataset Constructors `__ - - `Table 2.24 Open Modes `__ - - `Table 2.25 Dataset Methods `__ - -- `2.9 MV module `__ - - - `Table 2.26 Variable Constructors in module - MV `__ - - `Table 2.27 MV functions `__ - -- `2.10 HorizontalGrid `__ - - - `Table 2.28 `__ - - `Table 2.29 HorizontalGrid Internal - Attributes `__ - - `Table 2.30 RectGrid Constructors `__ - - `Table 2.31 HorizontalGrid Methods `__ - - `Table 2.32 RectGrid Methods, additional to HorizontalGrid - Methods `__ - -- `2.11 Variable `__ - - - `Table 2.33 Variable Internal - Attributes `__ - - `Table 2.34 Variable Constructors `__ - - `Table 2.35 Variable Methods `__ - - `Table 2.36 Variable Slice Operators `__ - - `Table 2.37 Index and Coordinate - Intervals `__ - - `2.11.1 Selectors `__ - - - `Table 2.38 Selector keywords `__ - - - `2.11.2 Selector examples `__ - -- `2.12 Examples `__ - -`CHAPTER 3 cdtime Module `__ -''''''''''''''''''''''''''''''''''''''''' - -- `3.1 Time types `__ -- `3.2 Calendars `__ -- `3.3 Time Constructors `__ - - - `Table 3.1 Time Constructors `__ - -- `3.4 Relative Time `__ - - - `Table 3.2 Relative Time Members `__ - -- `3.5 Component Time `__ - - - `Table 3.3 Component Time Members `__ - -- `3.6 Time Methods `__ - - - `Table 3.4 Time Methods `__ - -`CHAPTER 4 Regridding Data `__ -''''''''''''''''''''''''''''''''''''''''''' - -- `4.1 Overview `__ - - - `4.1.1 CDMS horizontal regridder `__ - - `4.1.2 SCRIP horizontal regridder `__ - - `4.1.3 Pressure-level regridder `__ - - `4.1.4 Cross-section regridder `__ - -- `4.2 regrid module `__ - - - `4.2.1 CDMS horizontal regridder `__ - - - `Table 4.1 CDMS Regridder - Constructor `__ - - - `4.2.2 SCRIP Regridder `__ - - - `Table 4.2 SCRIP Regridder - Constructor `__ - -- `4.3 regridder functions `__ - - - `4.3.1 CDMS regridder functions `__ - - - `Table 4.3 CDMS Regridder function `__ - - - `4.3.2 SCRIP Regridder functions `__ - - - `Table 4.4 SCRIP Regridder functions `__ - -- `4.4 Examples `__ - - - `4.4.1 CDMS regridder `__ - - `4.4.2 SCRIP regridder `__ - -`CHAPTER 5 Plotting CDMS data in Python `__ -'''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -- `5.1 Overview `__ -- `5.2 Examples `__ - - - `5.2.1 Example: plotting a gridded variable `__ - - `5.2.2 Example: using plot keywords. `__ - - `5.2.3 Example: plotting a time-latitude - slice `__ - - `5.2.4 Example: plotting subsetted data `__ - -- `5.3 plot method `__ - - - `Table 5.1 plot keywords `__ - -`CHAPTER 6 Climate Data Markup Language (CDML) `__ -''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -- `6.1 Introduction `__ -- `6.2 Elements `__ - - - `Table 6.1 CDML Tags `__ - -- `6.3 Special Characters `__ - - - `Table 6.2 Special Character Encodings `__ - -- `6.4 Identifiers `__ -- `6.5 CF Metadata Standard `__ -- `6.6 CDML Syntax `__ - - - `6.6.1 Dataset Element `__ - - - `Table 6.3 Dataset Attributes `__ - - - `6.6.2 Axis Element `__ - - - `Table 6.4 Axis Attributes `__ - - - `6.6.3 partition attribute `__ - - `6.6.4 Grid Element `__ - - - `Table 6.5 RectGrid Attributes `__ - - - `6.6.5 Variable Element `__ - - - `Table 6.6 Variable Attributes `__ - - - `6.6.6 Attribute Element `__ - -- `6.7 A Sample CDML Document `__ - -`CHAPTER 7 CDMS Utilities `__ -'''''''''''''''''''''''''''''''''''''''''' - -- `7.1 cdscan: Importing datasets into CDMS `__ - - - `7.1.1 Overview `__ - - `7.1.2 cdscan Syntax `__ - - - `Table 7.1 cdscan command options `__ - - - `7.1.3 Examples `__ - - `7.1.4 File Formats `__ - - `7.1.5 Name Aliasing `__ - -`APPENDIX A CDMS Classes `__ -'''''''''''''''''''''''''''''''''''''''''''''''''' - -`APPENDIX B Version Notes `__ -''''''''''''''''''''''''''''''''''''''''''''''''''' - -- `B.1 Version 4.0 `__ -- `B.2 Version 3.0 Overview `__ -- `B.3 V3.0 Details `__ - - - `B.3.1 AbstractVariable `__ - - `B.3.2 AbstractAxis `__ - - `B.3.3 AbstractDatabase `__ - - `B.3.4 Dataset `__ - - `B.3.5 cdms module `__ - - `B.3.6 CdmsFile `__ - - `B.3.7 CDMSError `__ - - `B.3.8 AbstractRectGrid `__ - - `B.3.9 InternalAttributes `__ - - `B.3.10 TransientVariable `__ - - `B.3.11 MV `__ - -`APPENDIX C cu Module `__ -''''''''''''''''''''''''''''''''''''''''''''''' - -- `C.1 Slab `__ - - - `Table C.1 Slab Methods `__ - -- `C.2 cuDataset `__ - - - `Table C.2 cuDataset Methods `__ diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index aad1ba00..895a4722 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -67,11 +67,14 @@ from file sample.nc into variable u: import MV2 import cdms2 - f = cdms2.open('clt.nc') + import cdat_info + f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') + f2 = cdms2.open(cdat_info.get_sampledata_path()+'/geos5-sample.nc') u = f('u') v = f('v') smallvar=MV2.reshape(MV2.arange(20),(4,5),id='small variable').astype(MV2.float32) largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) + .. doctest:: >>> f = cdms2.open('clt.nc') @@ -470,7 +473,7 @@ grid. Note that: >>> # y and x are index coordinate axes >>> f.axes.keys() - ['y', 'x', 'nvert'] + ['nvert', 'x', 'y'] >>> # Read data for variable sample >>> sample = f('sample') @@ -532,7 +535,7 @@ illustrates the grid, in this case a geodesic grid. >>> f.variables.keys() ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] >>> f.axes.keys() - ['y', 'x', 'nvert'] + ['nvert', 'x', 'y'] >>> zs = f('sample') >>> g = zs.getGrid() >>> g @@ -570,21 +573,19 @@ representation. Similarly, a rectangular grid can be represented as curvilinear. The method toCurveGrid is used to convert a non-generic grid to curvilinear representation: -.. testcode:: * +.. doctest:: * - >>> f = cdms2.open('clt.nc') + >>> f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') >>> clt = f('clt') >>> rectgrid = clt.getGrid() >>> rectgrid.shape + (46, 72) >>> curvegrid = rectgrid.toCurveGrid() >>> curvegrid + >>> genericgrid = curvegrid.toGenericGrid() >>> genericgrid - -.. testoutput:: - - (46, 72) - + 1.10 Regridding ^^^^^^^^^^^^^^^ @@ -612,21 +613,27 @@ a rectangular grid) to a 96x192 rectangular Gaussian grid: >>> f = cdms2.open('clt.nc') >>> u = f('u') >>> u.shape - ((1, 2, 80, 97) + (1, 2, 80, 97) >>> t63_grid = cdms2.createGaussianGrid(96) >>> u63 = u.regrid(t63_grid) >>> u63.shape - (3, 96, 192) + (1, 2, 96, 192) To regrid a variable ``uold`` to the same grid as variable ``vnew``: .. doctest:: - >>> uold.shape(3, 16, 32) - >>> vnew.shape(3, 96, 192) - >>> t63_grid = vnew.getGrid() # Obtain the grid for vnew + >>> f = cdms2.open('clt.nc') + >>> uold = f('u') + >>> unew = f2('uwnd') + >>> uold.shape + (1, 2, 80, 97) + >>> unew.shape + (1, 14, 181, 360) + >>> t63_grid = unew.getGrid() # Obtain the grid for vnew >>> u63 = u.regrid(t63_grid) - >>> u63.shape(3, 96, 192) + >>> u63.shape + (1, 2, 181, 360) 1.10.2 SCRIP Regridder '''''''''''''''''''''' @@ -653,27 +660,27 @@ The steps to regrid a variable are: Steps 1 and 2 need only be done once. The regridder can be used as often as necessary. -For example, suppose the source data on a T42 grid is to be mapped to a -POP curvilinear grid. Assume that SCRIP generated a remapping file named -rmp_T42_to_POP43_conserv.nc: - -.. doctest:: - - >>> # Import regrid package for regridder functions - >>> import regrid, cdms - - >>> # Get the source variable - >>> f = cdms.open('sampleT42Grid.nc') - >>> dat = f('src_array') - >>> f.close() - - >>> # Read the regridder from the remapper file - >>> remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') - >>> regridf = regrid.readRegridder(remapf) - >>> remapf.close() - - >>> # Regrid the source variable - >>> popdat = regridf(dat) +#For example, suppose the source data on a T42 grid is to be mapped to a +#POP curvilinear grid. Assume that SCRIP generated a remapping file named +#rmp_T42_to_POP43_conserv.nc: +# +#.. doctest:: +# +# >>> # Import regrid package for regridder functions +# >>> import regrid2, cdms2 +# +# >>> # Get the source variable +# >>> f = cdms2.open('sampleT42Grid.nc') +# >>> dat = f('src_array') +# >>> f.close() +# +# >>> # Read the regridder from the remapper file +# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') +# >>> regridf = regrid2.readRegridder(remapf) +# >>> remapf.close() +# +# >>> # Regrid the source variable +# >>> popdat = regridf(dat) Regridding is discussed in `Chapter 4 `__. @@ -698,7 +705,7 @@ units=" days since 1996-1-1". To create a relative time type: >>> import cdtime >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") >>> rt - 28.00 days since 1996-1-1 + 28.000000 days since 1996-1-1 >>> rt.value 28.0 >>> rt.units @@ -712,10 +719,11 @@ minute , and the floating-point field second . For example: >>> ct = cdtime.comptime(1996,2,28,12,10,30) >>> ct - -2-28 12:10:30.0 - ct.year - ct.month - + 1996-2-28 12:10:30.0 + >>> ct.year + 1996 + >>> ct.month + 2 The conversion functions tocomp and torel convert between the two representations. For instance, suppose that the time axis of a variable @@ -727,7 +735,7 @@ value corresponding to January 1, 1990: >>> ct = cdtime.comptime(1990,1) >>> rt = ct.torel("days since 1979") >>> rt.value - .0 + 4018.0 Time values can be used to specify intervals of time to read. The syntax time=(c1,c2) specifies that data should be read for times t such that @@ -735,21 +743,24 @@ c1<=t<=c2: .. doctest:: - >>> c1 = cdtime.comptime(1990,1) - >>> c2 = cdtime.comptime(1991,1) - >>> ua = f[' ua'] - >>> ua.shape - 480, 17, 73, 144) - >>> x = ua.subRegion(time=(c1,c2)) + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> c1 = cdtime.comptime(1980,1) + >>> c2 = cdtime.comptime(1980,2) + >>> tas = fh['tas'] + >>> tas.shape + (484, 45, 72) + >>> x = tas.subRegion(time=(c1,c2)) >>> x.shape - 12, 17, 73, 144) + (125, 45, 72) or string representations can be used: .. doctest:: - >>> x = ua.subRegion(time=('1990-1','1991-1')) + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> tas = fh['tas'] + >>> x = tas.subRegion(time=('1980-1','1980-2')) Time types are described in Chapter 3. @@ -771,18 +782,18 @@ For example: .. doctest:: - >>> import cdms, vcs - >>> f = cdms.open('sample.nc') - >>> f['time'][:] # Print the time coordinates - [ 0., 6., 12., 18., 24., 30., 36., 42., 48., 54., 60., 66., 72., 78., 84., 90.,] - >>> precip = f('prc', time=24.0) # Read precip data - >>> precip.shape - (1, 32, 64) + >>> import cdms2, vcs, cdat_info + >>> fh=cdms2.open(cdat_info.get_sampledata_path() + "/tas_cru_1979.nc") + >>> fh['time'][:] # Print the time coordinates + array([ 1476., 1477., 1478., 1479., 1480., 1481., 1482., 1483., + 1484., 1485., 1486., 1487.]) + + >>> tas = fh('tas', time=1479) + >>> tas.shape + (1, 36, 72) >>> w = vcs.init() # Initialize a canvas - 'Template' is currently set to P_default. - Graphics method 'Boxfill' is currently set to Gfb_default. - >>> w.plot(precip) # Generate a plot - (generates a boxfill plot) + >>> w.plot(tas) # Generate a plot + >> db = cdms.connect() # Connect to the default database. - >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. - >>> f.variables.keys() # List the variables in the dataset. - ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] - - +#.. doctest:: +# +# >>> db = cdms.connect() # Connect to the default database. +# >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. +# >>> f.variables.keys() # List the variables in the dataset. +# ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 1c1aa20f..c66978eb 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1,5 +1,5 @@ CHAPTER 2 CDMS Python Application Programming Interface -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------------------------------------- 2.1 Overview ^^^^^^^^^^^^ @@ -23,116 +23,30 @@ the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: + Table 2.1 Python types used in CDMS - - -+-------+--------------+ -| Type | Description | -+=======+==============+ -| Array | Numeric or | -| | masked | -| | multidimensi | -| | onal | -| | data array. | -| | All elements | -| | of the array | -| | are of the | -| | same type. | -| | Defined in | -| | the Numeric | -| | and MA | -| | modules. | -+-------+--------------+ -| Compt | Absolute | -| ime | time value, | -| | a time with | -| | representati | -| | on | -| | (year, | -| | month, day, | -| | hour, | -| | minute, | -| | second). | -| | Defined in | -| | the cdtime | -| | module. cf. | -| | reltime | -+-------+--------------+ -| Dicti | An unordered | -| onary | 2,3collectio | -| | n | -| | of objects, | -| | indexed by | -| | key. All | -| | dictionaries | -| | in CDMS are | -| | indexed by | -| | strings, | -| | e.g.: | -| | ``axes['time | -| | ']`` | -+-------+--------------+ -| Float | Floating-poi | -| | nt | -| | value. | -+-------+--------------+ -| Integ | Integer | -| er | value. | -+-------+--------------+ -| List | An ordered | -| | sequence of | -| | objects, | -| | which need | -| | not be of | -| | the same | -| | type. New | -| | members can | -| | be inserted | -| | or appended. | -| | Lists are | -| | denoted with | -| | square | -| | brackets, | -| | e.g., | -| | ``[1, 2.0, ' | -| | x', 'y']`` | -+-------+--------------+ -| None | No value | -| | returned. | -+-------+--------------+ -| Relti | Relative | -| me | time value, | -| | a time with | -| | representati | -| | on | -| | (value, | -| | units since | -| | basetime). | -| | Defined in | -| | the cdtime | -| | module. cf. | -| | comptime | -+-------+--------------+ -| Tuple | An ordered | -| | sequence of | -| | objects, | -| | which need | -| | not be of | -| | the same | -| | type. Unlike | -| | lists, | -| | tuples | -| | elements | -| | cannot be | -| | inserted or | -| | appended. | -| | Tuples are | -| | denoted with | -| | parentheses, | -| | e.g., | -| | ``(1, 2.0, ' | -| | x', 'y')`` | -+-------+--------------+ + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Description | ++==============+=======================================================================================================================================================================================================+ +| Array | Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Comptime | Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Dictionary | An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Float | Floating-point value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | Integer value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| List | An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| None | No value returned. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Reltime | Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 2.2 A first example ^^^^^^^^^^^^^^^^^^^ @@ -142,7746 +56,3130 @@ data from an input dataset, averages over time, and writes the results to an output file. The input temperature data is ordered (time, latitude, longitude). -{% highlight python %} 1 #!/usr/bin/env python 2 import cdms 3 from cdms -import MV 4 jones = cdms.open('/pcmdi/cdms/obs/jones\_mo.nc') 5 tasvar = -jones['tas'] 6 jans = tasvar[0::12] 7 julys = tasvar[6::12] 8 janavg = -MV.average(jans) 9 janavg.id = "tas\_jan" 10 janavg.long\_name = "mean -January surface temperature" 11 julyavg = MV.average(julys) 12 -julyavg.id = "tas\_jul" 13 julyavg.long\_name = "mean July surface -temperature" 14 out = cdms.open('janjuly.nc','w') 15 out.write(janavg) -16 out.write(julyavg) 17 out.comment = "Average January/July from Jones -dataset" 18 jones.close() 19 out.close() {% endhighlight %} - -+-------+--------+ -| Line | Notes | -+=======+========+ -| 2,3 | Makes | -| | the | -| | CDMS | -| | and MV | -| | module | -| | s | -| | availa | -| | ble. | -| | MV | -| | define | -| | s | -| | arithm | -| | etic | -| | functi | -| | ons. | -+-------+--------+ -| 4 | Opens | -| | a | -| | netCDF | -| | file | -| | read-o | -| | nly. | -| | The | -| | result | -| | jones | -| | is a | -| | datase | -| | t | -| | object | -| | . | -+-------+--------+ -| 5 | Gets | -| | the | -| | surfac | -| | e | -| | air | -| | temper | -| | ature | -| | variab | -| | le. | -| | 'tas' | -| | is the | -| | name | -| | of the | -| | variab | -| | le | -| | in the | -| | input | -| | datase | -| | t. | -| | This | -| | does | -| | not | -| | actual | -| | ly | -| | read | -| | the | -| | data. | -+-------+--------+ -| 6 | Read | -| | all | -| | Januar | -| | y | -| | monthl | -| | y | -| | mean | -| | data | -| | into a | -| | variab | -| | le | -| | jans. | -| | Variab | -| | les | -| | can be | -| | sliced | -| | like | -| | arrays | -| | . | -| | The | -| | slice | -| | operat | -| | or | -| | [0::12 | -| | ] | -| | means | -| | take | -| | every | -| | 12th | -| | slice | -| | from | -| | dimens | -| | ion | -| | 0, | -| | starti | -| | ng | -| | at | -| | index | -| | 0 and | -| | ending | -| | at the | -| | last | -| | index. | -| | If the | -| | stride | -| | 12 | -| | were | -| | omitte | -| | d, | -| | it | -| | would | -| | defaul | -| | t | -| | to 1. | -| | Note | -| | that | -| | the | -| | variab | -| | le | -| | is | -| | actual | -| | ly | -| | 3-dime | -| | nsiona | -| | l. | -| | Since | -| | no | -| | slice | -| | is | -| | specif | -| | ied | -| | for | -| | the | -| | second | -| | or | -| | third | -| | dimens | -| | ions, | -| | all | -| | values | -| | of | -| | those | -| | 2,3 | -| | dimens | -| | ions | -| | are | -| | retrie | -| | ved. | -| | The | -| | slice | -| | operat | -| | ion | -| | could | -| | also | -| | have | -| | been | -| | writte | -| | n | -| | [0::12 | -| | , | -| | : , | -| | :]. | -| | Also | -| | note | -| | that | -| | the | -| | same | -| | script | -| | works | -| | for | -| | multi- | -| | file | -| | datase | -| | ts. | -| | CDMS | -| | opens | -| | the | -| | needed | -| | data | -| | files, | -| | extrac | -| | ts | -| | the | -| | approp | -| | riate | -| | slices | -| | , | -| | and | -| | concat | -| | enates | -| | them | -| | into | -| | the | -| | result | -| | array. | -+-------+--------+ -| 7 | Reads | -| | all | -| | July | -| | data | -| | into a | -| | masked | -| | array | -| | julys. | -+-------+--------+ -| 8 | Calcul | -| | ate | -| | the | -| | averag | -| | e | -| | Januar | -| | y | -| | value | -| | for | -| | each | -| | grid | -| | zone. | -| | Any | -| | missin | -| | g | -| | data | -| | is | -| | handle | -| | d | -| | automa | -| | ticall | -| | y. | -+-------+--------+ -| 9,10 | Set | -| | the | -| | variab | -| | le | -| | id and | -| | long\_ | -| | name | -| | attrib | -| | utes. | -| | The id | -| | is | -| | used | -| | as the | -| | name | -| | of the | -| | variab | -| | le | -| | when | -| | plotte | -| | d | -| | or | -| | writte | -| | n | -| | to a | -| | file. | -+-------+--------+ -| 14 | Create | -| | a new | -| | netCDF | -| | output | -| | file | -| | named | -| | 'janju | -| | ly.nc' | -| | to | -| | hold | -| | the | -| | result | -| | s. | -+-------+--------+ -| 15 | Write | -| | the | -| | Januar | -| | y | -| | averag | -| | e | -| | values | -| | to the | -| | output | -| | file. | -| | The | -| | variab | -| | le | -| | will | -| | have | -| | id | -| | "tas\_ | -| | jan" | -| | in the | -| | file. | -| | ``writ | -| | e`` | -| | is a | -| | utilit | -| | y | -| | functi | -| | on | -| | which | -| | create | -| | s | -| | the | -| | variab | -| | le | -| | in the | -| | file, | -| | then | -| | writes | -| | data | -| | to the | -| | variab | -| | le. | -| | A more | -| | genera | -| | l | -| | method | -| | of | -| | data | -| | output | -| | is | -| | first | -| | to | -| | create | -| | a | -| | variab | -| | le, | -| | then | -| | set a | -| | slice | -| | of the | -| | variab | -| | le. | -| | Note | -| | that | -| | janavg | -| | and | -| | julavg | -| | have | -| | the | -| | same | -| | latitu | -| | de | -| | and | -| | longit | -| | ude | -| | inform | -| | ation | -| | as | -| | tasvar | -| | . | -| | It is | -| | carrie | -| | d | -| | along | -| | with | -| | the | -| | comput | -| | ations | -| | . | -+-------+--------+ -| 17 | Set | -| | the | -| | global | -| | attrib | -| | ute | -| | 'comme | -| | nt'. | -+-------+--------+ -| 18 | Close | -| | the | -| | output | -| | file. | -+-------+--------+ +.. doctest:: + + >>> import cdms2, cdat_info + >>> from cdms2 import MV + >>> jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc') + >>> tasvar = jones['tas'] + >>> jans = tasvar[0::12] + >>> julys = tasvar[6::12] + >>> janavg = MV.average(jans) + >>> janavg.id = "tas_jan" + >>> janavg.long_name = "mean January surface temperature" + >>> julyavg = MV.average(julys) + >>> julyavg.id = "tas_jul" + >>> julyavg.long_name = "mean July surface temperature" + >>> out = cdms2.open('janjuly.nc','w') + >>> out.write(janavg) + >>> out.write(julyavg) + >>> out.comment = "Average January/July from Jones dataset" + >>> jones.close() + >>> out.close() + + ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| 2,3 | Makes the CDMS and MV modules available. MV defines arithmetic functions. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 4 | Opens a netCDF file read-only. The result jones is a dataset object. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 5 | Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 6 | Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 7 | Reads all July data into a masked array julys. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 8 | Calculate the average January value for each grid zone. Any missing data is handled automatically. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 9,10 | Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 14 | Create a new netCDF output file named ‘janjuly.nc’ to hold the results. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 15 | Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 17 | Set the global attribute ‘comment’. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 18 | Close the output file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + 2.3 cdms module -^^^^^^^^^^^^^^^ The cdms module is the Python interface to CDMS. The objects and methods in this chapter are made accessible with the command: -{% highlight python %} import cdms {% endhighlight %} - -The functions described in this section are not associated with a class. -Rather, they are called as module functions, e.g., - -{% highlight python %} file = cdms.open('sample.nc') {% endhighlight %} - -Table 2.2 cdms module functions - - -.. raw:: html - - - .. raw:: html - +
:: -
- - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - + -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - +The functions described in this section are not associated with a class. +Rather, they are called as module functions, e.g., .. raw:: html - - -.. raw:: html +
-
- -.. raw:: html + - -.. raw:: html +Table 2.3 Class Tags - ++--------------+---------------------+ +| Tag | Class | ++==============+=====================+ +| ‘axis’ | Axis | ++--------------+---------------------+ +| ‘database’ | Database | ++--------------+---------------------+ +| ‘dataset’ | Dataset, CdmsFile | ++--------------+---------------------+ +| ‘grid’ | RectGrid | ++--------------+---------------------+ +| ‘variable’ | Variable | ++--------------+---------------------+ +| ‘xlink’ | Xlink | ++--------------+---------------------+ -.. raw:: html - +2.4 CdmsObj +^^^^^^^^^^^ -.. raw:: html +A CdmsObj is the base class for all CDMS database objects. At the +application level, CdmsObj objects are never created and used directly. +Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the +basis of user application programming. - +
-.. raw:: html - -
- -.. raw:: html + - -.. raw:: html +Table 2.4 Attributes common to all CDMS objects - ++--------------+--------------+--------------------------------------------------+ +| Type | Name | Definition | ++==============+==============+==================================================+ +| Dictionary | attributes | External attribute dictionary for this object. | ++--------------+--------------+--------------------------------------------------+ -.. raw:: html - +2.5 CoordinateAxis +^^^^^^^^^^^^^^^^^^ -.. raw:: html +A CoordinateAxis is a variable that represents coordinate information. +It may be contained in a file or dataset, or may be transient +(memoryresident). Setting a slice of a file CoordinateAxis writes to the +file, and referencing a file CoordinateAxis slice reads data from the +file. Axis objects are also used to define the domain of a Variable. - ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Definition | ++======================+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``CoordinateAxis`` | A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis2D`` | A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``AuxAxis1D`` | A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -.. raw:: html - +Table 2.7 CoordinateAxis Internal Attributes -.. raw:: html ++------------------+------------------+--------------------------------------------+ +| Type | Name | Definition | ++==================+==================+============================================+ +| ``Dictionary`` | ``attributes`` | External attribute dictionary. | ++------------------+------------------+--------------------------------------------+ +| ``String`` | ``id`` | CoordinateAxis identifer. | ++------------------+------------------+--------------------------------------------+ +| ``Dataset`` | ``parent`` | The dataset which contains the variable. | ++------------------+------------------+--------------------------------------------+ +| ``Tuple`` | ``shape`` | The length of each axis. | ++------------------+------------------+--------------------------------------------+ - -.. raw:: html +Table 2.8 Axis Constructors - ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+====================================================================+================================================================================================================================================================================================================================================================================+ +| ``Array`` | ``array = axis[i:j]`` | Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``axis[i:j] = array`` | Write a slice of data to the external file. Dataset axes are read-only. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``assignValue(array)`` | Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | ``clone(copyData=1)`` | Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLatitude(persistent=0)`` | Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLevel(persistent=0)`` | Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLongitude(persistent=0, modulo=360.0)`` | Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateTime(persistent=0, calendar = cdtime.MixedCalendar)`` | Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getBounds()`` | Get the associated boundary array. The shape of the return array depends on the type of axis: | +|   |   | * ``Axis``: ``(n,2)`` | +|   |   | * ``Axis2D``: ``(i,j,4)`` | +|   |   | * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. | +|   |   | If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``getCalendar()`` | Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: | +|   |   | * ``cdtime.GregorianCalendar``: the standard Gregorian calendar | +|   |   | * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar | +|   |   | * ``cdtime.JulianCalendar``: years divisible by 4 are leap years | +|   |   | * ``cdtime.NoLeapCalendar``: a year is 365 days | +|   |   | * ``cdtime.Calendar360``: a year is 360 days | +|   |   | * ``None``: no calendar can be identified | +|   |   | Note: If the axis is not a time axis, the global, file-related calendar is returned. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getValue()`` | Get the entire axis vector. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLatitude()`` | Returns true iff the axis is a latitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLevel()`` | Returns true iff the axis is a level axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLongitude()`` | Returns true iff the axis is a longitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isTime()`` | Returns true iff the axis is a time axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``len(axis)`` | The length of the axis if one-dimensional. If multidimensional, the length of the first dimension. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``size()`` | The number of elements in the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``String`` | ``typecode()`` | The ``Numeric`` datatype identifier. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.10 Axis Methods, additional to CoordinateAxis + ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============================+===============================================+==========================================================================================================================================================================================================================================================================================================================+ +| ``List`` of component times | ``asComponentTime(calendar=None)`` | ``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``List`` of relative times | ``asRelativeTime()`` | ``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateCircular(modulo, persistent=0)`` | Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isCircular()`` | Returns ``True`` if the axis has circular topology. An axis is defined as circular if: | +|   |   | * ``axis.topology == 'circular'``, or | +|   |   | * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0 | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLinear()`` | Returns ``True`` if the axis has a linear representation. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Tuple`` | ``mapInterval(interval)`` | Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``(i,j,k)`` | ``mapIntervalExt(interval)`` | Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: | +|   |   | * ``(x,y)`` | +|   |   | * ``(x,y,indicator)`` | +|   |   | * ``(x,y,indicator,cycle)`` | +|   |   | * ``None or ':'`` | +|   |   | * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: | +|   |   | * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis| +|   |   | * ``'n'`` - select node values which are contained in the interval | +|   |   | * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval | +|   |   | * ``'e'`` - same as n, but include an extra node on either side | +|   |   | * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval | +|   |   | * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. | +|   |   | * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. | +|   |   | * An interval of ``None`` or ``':'`` returns the full index interval of the axis. | +|   |   | * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. | +|   |   | * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` | +|   |   | * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. | +|   |   | * otherwise the interval wraps around the axis endpoint. | +|   |   | * see also: ``mapinterval``, ``variable.subregion()`` | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``transientaxis`` | ``subaxis(i,j,k=1)`` | create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -.. raw:: html - +a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length +``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index +interval(s), with wraparound. the result index interval ``-2 <= n < 3`` +wraps around, since ``-2 < 0``, and has a stride of ``1``. this is +equivalent to the two contiguous index intervals ``2 <= n < 0`` and +``0 <= n < 3`` .. raw:: html - +
-.. raw:: html +:: -
+ >>> axis.isCircular() + 1 + >>> axis.mapIntervalExt((-5.0,5.0,'co')) + (-2,3,1) .. raw:: html - +2.6 CdmsFile +^^^^^^^^^^^^ +A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` +interface. netCDF files are accessible in read-write mode. All other +formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. -.. raw:: html +As of CDMS V3, the legacy cuDataset interface is also supported by +Cdms-Files. See “cu Module” on page 180. - ++------------------+------------------+---------------------------------------+ +| Type | Name | Definition | ++==================+==================+=======================================+ +| ``Dictionary`` | ``attributes`` | Global, external file attributes | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``grids`` | Grids contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``String`` | ``id`` | File pathname. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``variables`` | Variables contained in the file. | ++------------------+------------------+---------------------------------------+ -.. raw:: html - +Table 2.13 CdmsFile Constructors -.. raw:: html ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++==========================================+==================================================================================================================================================================================+ +| ``fileobj = cdms.open(path, mode)`` | Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``fileobj = cdms.createDataset(path)`` | Create the file specified by path, a string. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -.. raw:: html +Table 2.14 CdmsFile Methods - ++-----------------+-----------------------------------+ +| CDMS Datatype | Definition | ++=================+===================================+ +| ``CdChar`` | character | ++-----------------+-----------------------------------+ +| ``CdDouble`` | double-precision floating-point | ++-----------------+-----------------------------------+ +| ``CdFloat`` | floating-point | ++-----------------+-----------------------------------+ +| ``CdInt`` | integer | ++-----------------+-----------------------------------+ +| ``CdLong`` | long integer | ++-----------------+-----------------------------------+ +| ``CdShort`` | short integer | ++-----------------+-----------------------------------+ -.. raw:: html - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
TypeDefinition
- -Variable - -.. raw:: html - - - -asVariable(s): Transform s into a transient variable. s is a masked -array, Numeric array, or Variable. If s is already a transient variable, -s is returned. See also: isVariable. - -.. raw:: html - -
- -Axis - -.. raw:: html - - - -createAxis(data, bounds=None): Create a one-dimensional coordinate Axis, -which is not associated with a file or dataset. This is useful for -creating a grid which is not contained in a file or dataset. data is a -one-dimensional, monotonic Numeric array. bounds is an array of shape -(len(data),2), such that for all i, data[i] is in the range -[bounds[i,0],bounds[i,1] ]. If bounds is not specified, the default -boundaries are generated at the midpoints between the consecutive data -values, provided that the autobounds mode is 'on' (the default). See -setAutoBounds. Also see: CdmsFile.createAxis - -.. raw:: html - -
- -Axis + import cdms2 .. raw:: html - - -createEqualAreaAxis(nlat): Create an equal-area latitude axis. The -latitude values range from north to south, and for all axis values x[i], -sin(x[i])sin(x[i+1]) is constant. nlat is the axis length. The axis is -not associated with a file or dataset. - -.. raw:: html - -
- -Axis - -.. raw:: html - - - -createGaussianAxis(nlat): Create a Gaussian latitude axis. Axis values -range from north to south. nlat is the axis length. The axis is not -associated with a file or dataset. - -.. raw:: html - -
+:: -RectGrid + file = cdms2.open('sample.nc') .. raw:: html - -createGaussianGrid(nlats, xorigin=0.0, order="yx"): Create a Gaussian -grid, with shape (nlats, 2\*nlats). nlats is the number of latitudes. -xorigin is the origin of the longitude axis. order is either "yx" -(lat-lon, default) or "xy" (lon-lat) +Table 2.2 cdms module functions -.. raw:: html ++-------------+-------------------------------------------------------------------------+ +| Type | Definition | ++=============+=========================================================================+ +| ``Variable``| ``asVariable(s)``: Transform ``s`` | +| | into a transient variable. ``s`` is | +| | a masked array, Numeric array, or | +| | Variable. If ``s`` is already a | +| | transient variable, ``s`` is | +| | returned. See also: ``isVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createAxis(data, bounds=None)``: | +| | Create a one-dimensional coordinate | +| | Axis, which is not associated with a | +| | file or dataset. This is useful for | +| | creating a grid which is not | +| | contained in a file or dataset. | +| | ``data`` is a one-dimensional, | +| | monotonic Numeric array. ``bounds`` | +| | is an array of shape | +| | ``(len(data),2)``, such that for all | +| | ``i``, ``data[i]`` is in the range | +| | ``[bounds[i,0],bounds[i,1] ]``. If | +| | ``bounds`` is not specified, the | +| | default boundaries are generated at | +| | the midpoints between the | +| | consecutive data values, provided | +| | that the autobounds mode is 'on' | +| | (the default). See | +| | ``setAutoBounds``. Also see: | +| | ``CdmsFile.createAxis`` | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createEqualAreaAxis(nlat)``: | +| | Create an equal-area latitude axis. | +| | The latitude values range from north | +| | to south, and for all axis values | +| | ``x[i]``, ``sin(x[i])sin(x[i+1])`` | +| | is constant. ``nlat`` is the axis | +| | length. The axis is not associated | +| | with a file or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createGaussianAxis(nlat)``: Create | +| | a Gaussian latitude axis. Axis | +| | values range from north to south. | +| | ``nlat`` is the axis length. The | +| | axis is not associated with a file | +| | or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGaussianGrid(nlats, xorigin= | +| | 0.0, order="yx")``: | +| | Create a Gaussian grid, with shape | +| | ``(nlats, 2*nlats)``. ``nlats`` is | +| | the number of latitudes. ``xorigin`` | +| | is the origin of the longitude axis. | +| | ``order`` is either "yx" (lat-lon, | +| | default) or "xy" (lon-lat) | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, | +| | order="yx", mask=None)``: | +| | Create a generic grid, that is, a | +| | grid which is not typed as Gaussian, | +| | uniform, or equal-area. The grid is | +| | not associated with a file or | +| | dataset. ``latArray`` is a NumPy | +| | array of latitude values. | +| | ``lonArray`` is a NumPy array of | +| | longitude values. ``latBounds`` is a | +| | NumPy array having shape | +| | ``(len(latArray),2)``, of latitude | +| | boundaries. ``lonBounds`` is a NumPy | +| | array having shape | +| | ``(len(lonArray),2)``, of longitude | +| | boundaries. ``order`` is a | +| | ``string`` specifying the order of | +| | the axes, either "yx" for (latitude, | +| | longitude), or "xy" for the reverse. | +| | ``mask`` (optional) is an | +| | ``integer``-valued NumPy mask array, | +| | having the same shape and ordering | +| | as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGlobalMeanGrid(grid)``: | +| | Generate a grid for calculating the | +| | global mean via a regridding | +| | operation. The return grid is a | +| | single zone covering the range of | +| | the input grid. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createRectGrid(lat, lon, order, ty | +| | pe="generic", mask=None)``: | +| | Create a rectilinear grid, not | +| | associated with a file or dataset. | +| | This might be used as the target | +| | grid for a regridding operation. | +| | ``lat`` is a latitude axis, created | +| | by ``cdms.createAxis``. ``lon`` is a | +| | longitude axis, created by | +| | ``cdms.createAxis``. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). ``type`` is one of | +| | 'gaussian','uniform','equalarea',or | +| | 'generic'. If specified, ``mask`` is | +| | a two-dimensional, logical Numeric | +| | array (all values are zero or one) | +| | with the same shape as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createUniformGrid(startLat, nlat, | +| | deltaLat, start-Lon, nlon, deltaLon, | +| | order="yx", mask=None)``: | +| | Create a uniform rectilinear grid. | +| | The grid is not associated with a | +| | file or dataset. The grid boundaries | +| | are at the midpoints of the axis | +| | values. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. If ``nlat`` is | +| | 1, the grid latitude boundaries will | +| | be ``startLat`` +/- ``deltaLat/2``. | +| | ``deltaLat`` is the increment | +| | between latitudes. ``startLon`` is | +| | the starting longitude value. | +| | ``nlon`` is the number of | +| | longitudes. If ``nlon`` is 1, the | +| | grid longitude boundaries will be | +| | ``startLon`` +/- ``deltaLon/2``. | +| | ``deltaLon`` is the increment | +| | between longitudes. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). If specified, ``mask`` | +| | is a two-dimensional, logical | +| | Numeric array (all values are zero | +| | or one) with the same shape as the | +| | grid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLatitudeAxis(startLat | +| | , nlat, deltaLat)``: | +| | Create a uniform latitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular latitude | +| | axis. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. ``deltaLat`` is | +| | the increment between latitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createZonalGrid(grid)``: Create a | +| | zonal grid. The output grid has the | +| | same latitude as the input grid, and | +| | a single longitude. This may be used | +| | to calculate zonal averages via a | +| | regridding operation. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLongitudeAxis(startLo | +| | n, nlon, delta-Lon)``: | +| | Create a uniform longitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular longitude | +| | axis. ``startLon`` is the starting | +| | longitude value. ``nlon`` is the | +| | number of longitudes. ``deltaLon`` | +| | is the increment between longitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``Variable``| ``createVariable(array, typecode=Non | +| | e, copy=0, savespace=0, mask=None, f | +| | ill_value=None, grid=None, axes=None | +| | , attributes=None, id=None)``: | +| | This function is documented in Table | +| | 2.34 on page 90. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``getAutoBounds()``: Get the current | +| | autobounds mode. Returns 0, 1, or 2. | +| | See ``setAutoBounds``. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``isVariable(s)``: Return ``1`` if | +| | ``s`` is a variable, ``0`` | +| | otherwise. See also: ``asVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Dataset`` | ``open(url,mode='r')``: Open or | +| | create a ``Dataset`` or | +| | ``CdmsFile``. ``url`` is a Uniform | +| | Resource Locator, referring to a | +| | cdunif or XML file. If the URL has | +| | the extension '.xml' or '.cdml', a | +| | ``Dataset`` is returned, otherwise a | +| | ``CdmsFile`` is returned. If the URL | +| | protocol is 'http', the file must be | +| | a '.xml' or '.cdml' file, and the | +| | mode must be 'r'. If the protocol is | +| | 'file' or is omitted, a local file | +| | or dataset is opened. ``mode`` is | +| | the open mode. See Table 2.24 on | +| | page 70. | +| | **Example**: Open an existing | +| | dataset: | +| | ``f = cdms.open("sampleset.xml")`` | +| | | +| | **Example**: Create a netCDF file: | +| | ``f = cdms.open("newfile.nc",'w')`` | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``order2index (axes, orderstring)``: | +| | Find the index permutation of axes | +| | to match order. Return a list of | +| | indices. ``axes`` is a list of axis | +| | objects. ``orderstring`` is defined | +| | as in ``orderparse``. | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``orderparse(orderstring)``: Parse | +| | an order string. Returns a list of | +| | axes specifiers. ``orderstring`` | +| | consists of: | +| | | +| | - Letters t, x, y, z meaning time, | +| | longitude, latitude, level | +| | - Numbers 0-9 representing position | +| | in axes | +| | - Dash (-) meaning insert the next | +| | available axis here. | +| | - The ellipsis ... meaning fill | +| | these positions with any | +| | remaining axes. | +| | - (name) meaning an axis whose id | +| | is name | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setAutoBounds(mode)``: Set | +| | autobounds mode. In some | +| | circumstances CDMS can generate | +| | boundaries for 1-D axes and | +| | rectilinear grids, when the bounds | +| | are not explicitly defined. The | +| | autobounds mode determines how this | +| | is done: If ``mode`` is ``'grid'`` | +| | or ``2`` (the default), the | +| | ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid if | +| | the axis is designated as a latitude | +| | or longitude axis, and the | +| | boundaries are not explicitly | +| | defined. If ``mode`` is ``'on'`` or | +| | ``1``, the ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid, if | +| | the boundaries are not explicitly | +| | defined. If ``mode`` is ``'off'`` or | +| | ``0``, and no boundary data is | +| | explicitly defined, the bounds will | +| | NOT be generated; the ``getBounds`` | +| | method will return ``None`` for the | +| | boundaries. Note: In versions of | +| | CDMS prior to V4.0, the default | +| | ``mode`` was ``'on'``. | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setClassifyGrids(mode)``: Set the | +| | grid classification mode. This | +| | affects how grid type is determined, | +| | for the purpose of generating grid | +| | boundaries. If ``mode`` is ``'on'`` | +| | (the default), grid type is | +| | determined by a grid classification | +| | method, regardless of the value of | +| | ``grid.get-Type()``. If ``mode`` is | +| | ``'off'``, the value of | +| | ``grid.getType()`` determines the | +| | grid type | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``writeScripGrid(path, grid, gridTit | +| | le=None)``: | +| | Write a grid to a SCRIP grid file. | +| | ``path`` is a string, the path of | +| | the SCRIP file to be created. | +| | ``grid`` is a CDMS grid object. It | +| | may be rectangular. ``gridTitle`` is | +| | a string ID for the grid. | ++-------------+-------------------------------------------------------------------------+ -
+All objects derived from CdmsObj have a special attribute .attributes. +This is a Python dictionary, which contains all the external +(persistent) attributes associated with the object. This is in contrast +to the internal, non-persistent attributes of an object, which are +built-in and predefined. When a CDMS object is written to a file, the +external attributes are written, but not the internal attributes. -RectGrid +**Example**: get a list of all external attributes of obj. .. raw:: html - +:: -createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, -order="yx", mask=None): Create a generic grid, that is, a grid which is -not typed as Gaussian, uniform, or equal-area. The grid is not -associated with a file or dataset. latArray is a NumPy array of latitude -values. lonArray is a NumPy array of longitude values. latBounds is a -NumPy array having shape (len(latArray),2), of latitude boundaries. -lonBounds is a NumPy array having shape (len(lonArray),2), of longitude -boundaries. order is a string specifying the order of the axes, either -"yx" for (latitude, longitude), or "xy" for the reverse. mask (optional) -is an integer-valued NumPy mask array, having the same shape and -ordering as the grid. + extatts = obj.attributes.keys() .. raw:: html -
+Table 2.5 Getting and setting attributes -RectGrid ++--------------------------------------+--------------------------------------+ +| Type | Definition | ++======================================+======================================+ +| various | ``value = obj.attname`` | +| | Get an internal or external | +| | attribute value. If the attribute is | +| | external, it is read from the | +| | database. If the attribute is not | +| | already in the database, it is | +| | created as an external attribute. | +| | Internal attributes cannot be | +| | created, only referenced. | ++--------------------------------------+--------------------------------------+ +| various | ``obj.attname = value`` | +| | Set an internal or external | +| | attribute value. If the attribute is | +| | external, it is written to the | +| | database. | ++--------------------------------------+--------------------------------------+ -.. raw:: html - +CDMS defines several different types of CoordinateAxis objects. Table +2.9 on page 45 documents methods that are common to all CoordinateAxis +types. Table 2.10 on page 48 specifies methods that are unique to 1D +Axis objects. -createGlobalMeanGrid(grid): Generate a grid for calculating the global -mean via a regridding operation. The return grid is a single zone -covering the range of the input grid. grid is a RectGrid. -.. raw:: html +Table 2.6 CoordinateAxis types -
++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================+ +| ``cdms.createAxis(data, bounds=None)`` | Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Dataset.createAxis(name,ar)`` | Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented. ) | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``CdmsFile.createAxis(name,ar,unlimited=0)`` | Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited`` | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createEqualAreaAxis(nlat)`` | See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createGaussianAxis(nlat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -RectGrid -.. raw:: html +Table 2.9 CoordinateAxis Methods - +table 2.11 axis slice operators -createRectGrid(lat, lon, order, type="generic", mask=None): Create a -rectilinear grid, not associated with a file or dataset. This might be -used as the target grid for a regridding operation. lat is a latitude -axis, created by cdms.createAxis. lon is a longitude axis, created by -cdms.createAxis. order is a string with value "yx" (the first grid -dimension is latitude) or "xy" (the first grid dimension is longitude). -type is one of 'gaussian','uniform','equalarea',or 'generic'. If -specified, mask is a two-dimensional, logical Numeric array (all values -are zero or one) with the same shape as the grid. ++---------------+-----------------------------------------------------------------------------+ +| slice | definition | ++===============+=============================================================================+ +| ``[i]`` | the ``ith`` element, starting with index ``0`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:]`` | the ``ith`` element through and including the end | ++---------------+-----------------------------------------------------------------------------+ +| ``[:j]`` | the beginning element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[:]`` | the entire array | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | ++---------------+-----------------------------------------------------------------------------+ -.. raw:: html +**example:** -
+ -RectGrid -.. raw:: html - - - -createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, -order="yx", mask=None): Create a uniform rectilinear grid. The grid is -not associated with a file or dataset. The grid boundaries are at the -midpoints of the axis values. startLat is the starting latitude value. -nlat is the number of latitudes. If nlat is 1, the grid latitude -boundaries will be startLat +/- deltaLat/2. deltaLat is the increment -between latitudes. startLon is the starting longitude value. nlon is the -number of longitudes. If nlon is 1, the grid longitude boundaries will -be startLon +/- deltaLon/2. deltaLon is the increment between -longitudes. order is a string with value "yx" (the first grid dimension -is latitude) or "xy" (the first grid dimension is longitude). If -specified, mask is a two-dimensional, logical Numeric array (all values -are zero or one) with the same shape as the grid. -.. raw:: html +Table 2.12 CdmsFile Internal Attributes -
++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| ``Transient-Variable`` | ``fileobj(varname, selec | Calling a ``CdmsFile`` | +| | tor)`` | object as a function | +| | | reads the region of data | +| | | specified by the | +| | | ``selector``. The result | +| | | is a transient variable, | +| | | unless ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | nc') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| ``Variable``, ``Axis``, | ``fileobj['id']`` | Get the persistent | +| or ``Grid`` | | variable, axis or grid | +| | | object having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. | +| | | | +| | | **Example:** The | +| | | following gets the | +| | | persistent variable | +| | | ``v``, equivalent to | +| | | ``v = f.variables['prc'] | +| | | ``. | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.nc') | +| | | v = f['prc'] | +| | | | +| | | **Example:** The | +| | | following gets the axis | +| | | named time, equivalent | +| | | to | +| | | ``t = f.axes['time']``. | +| | | | +| | | ``t = f['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``copyAxis(axis, newname | Copy ``axis`` values and | +| | =None)`` | attributes to a new axis | +| | | in the file. The | +| | | returned object is | +| | | persistent: it can be | +| | | used to write axis data | +| | | to or read axis data | +| | | from the file. If an | +| | | axis already exists in | +| | | the file, having the | +| | | same name and coordinate | +| | | values, it is returned. | +| | | It is an error if an | +| | | axis of the same name | +| | | exists, but with | +| | | different coordinate | +| | | values. ``axis`` is the | +| | | axis object to be | +| | | copied. ``newname``, if | +| | | specified, is the string | +| | | identifier of the new | +| | | axis object. If not | +| | | specified, the | +| | | identifier of the input | +| | | axis is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Grid`` | ``copyGrid(grid, newname | Copy grid values and | +| | =None)`` | attributes to a new grid | +| | | in the file. The | +| | | returned grid is | +| | | persistent. If a grid | +| | | already exists in the | +| | | file, having the same | +| | | name and axes, it is | +| | | returned. An error is | +| | | raised if a grid of the | +| | | same name exists, having | +| | | different axes. ``grid`` | +| | | is the grid object to be | +| | | copied. ``newname``, if | +| | | specified is the string | +| | | identifier of the new | +| | | grid object. If | +| | | unspecified, the | +| | | identifier of the input | +| | | grid is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``createAxis(id, ar, unl | Create a new ``Axis``. | +| | imited=0)`` | This is a persistent | +| | | object which can be used | +| | | to read or write axis | +| | | data to the file. ``id`` | +| | | is an alphanumeric | +| | | string identifier, | +| | | containing no blanks. | +| | | ``ar`` is the | +| | | one-dimensional axis | +| | | array. Set ``unlimited`` | +| | | to ``cdms.Unlimited`` to | +| | | indicate that the axis | +| | | is extensible. | ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a ``RectGrid`` in | +| | , lon, order, type="gene | the file. This is not a | +| | ric", mask=None)`` | persistent object: the | +| | | order, type, and mask | +| | | are not written to the | +| | | file. However, the grid | +| | | may be used for | +| | | regridding operations. | +| | | ``lat`` is a latitude | +| | | axis in the file. | +| | | ``lon`` is a longitude | +| | | axis in the file. | +| | | ``order`` is a string | +| | | with value ``"yx"`` (the | +| | | first grid dimension is | +| | | latitude) or ``"xy"`` | +| | | (the first grid | +| | | dimension is longitude). | +| | | ``type`` is one of | +| | | ``'gaussian'``,\ ``'unif | +| | | orm'``,\ ``'equalarea'`` | +| | | , | +| | | or ``'generic'``. If | +| | | specified, ``mask`` is a | +| | | two-dimensional, logical | +| | | Numeric array (all | +| | | values are zero or one) | +| | | with the same shape as | +| | | the grid. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariable(String | Create a new Variable. | +| | id, String datatype,List | This is a persistent | +| | axes, fill_value=None)` | object which can be used | +| | ` | to read or write | +| | | variable data to the | +| | | file. ``id`` is a String | +| | | name which is unique | +| | | with respect to all | +| | | other objects in the | +| | | file. ``datatype`` is an | +| | | ``MA`` typecode, e.g., | +| | | ``MA.Float``, | +| | | ``MA.Int``. ``axes`` is | +| | | a list of Axis and/or | +| | | Grid objects. | +| | | ``fill_value`` is the | +| | | missing value | +| | | (optional). | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariableCopy(var | Create a new | +| | , newname=None)`` | ``Variable``, with the | +| | | same name, axes, and | +| | | attributes as the input | +| | | variable. An error is | +| | | raised if a variable of | +| | | the same name exists in | +| | | the file. ``var`` is the | +| | | ``Variable`` to be | +| | | copied. ``newname``, if | +| | | specified is the name of | +| | | the new variable. If | +| | | unspecified, the | +| | | returned variable has | +| | | the same name as | +| | | ``var``. | +| | | | +| | | **Note:** Unlike | +| | | copyAxis, the actual | +| | | data is not copied to | +| | | the new variable. | ++--------------------------+--------------------------+--------------------------+ +| ``CurveGrid`` or | ``readScripGrid(self, wh | Read a curvilinear or | +| ``Generic-Grid`` | ichGrid='destination', c | generic grid from a | +| | heck-Grid=1)`` | SCRIP netCDF file. The | +| | | file can be a SCRIP grid | +| | | file or remapping file. | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. If | +| | | ``checkGrid`` is ``1`` | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``sync()`` | Writes any pending | +| | | changes to the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | :: | Write a variable or | +| | | array to the file. The | +| | write(var, attribute | return value is the | +| | s=None, axes=None, extbo | associated file | +| | unds=None, id=None, exte | variable. | +| | nd=None, fill_value=None | | +| | , index=None, typecode=N | If the variable does not | +| | one) | exist in the file, it is | +| | | first defined and all | +| | | attributes written, then | +| | | the data is written. By | +| | | default, the time | +| | | dimension of the | +| | | variable is defined as | +| | | the unlimited dimension | +| | | of the file. If the data | +| | | is already defined, then | +| | | data is extended or | +| | | overwritten depending on | +| | | the value of keywords | +| | | ``extend`` and | +| | | ``index``, and the | +| | | unlimited dimension | +| | | values associated with | +| | | ``var``. | +| | | | +| | | ``var`` is a Variable, | +| | | masked array, or Numeric | +| | | array. ``attributes`` is | +| | | the attribute dictionary | +| | | for the variable. The | +| | | default is | +| | | ``var.attributes``. | +| | | ``axes`` is the list of | +| | | file axes comprising the | +| | | domain of the variable. | +| | | The default is to copy | +| | | ``var.getAxisList()``. | +| | | ``extbounds`` is the | +| | | unlimited dimension | +| | | bounds. Defaults to | +| | | ``var.getAxis(0).getBoun | +| | | ds()``. | +| | | ``id`` is the variable | +| | | name in the file. | +| | | Default is ``var.id``. | +| | | ``extend = 1`` causes | +| | | the first dimension to | +| | | be unlimited: | +| | | iteratively writeable. | +| | | The default is ``None``, | +| | | in which case the first | +| | | dimension is extensible | +| | | if it is ``time.Set`` to | +| | | ``0`` to turn off this | +| | | behaviour. | +| | | ``fill_value`` is the | +| | | missing value flag. | +| | | ``index`` is the | +| | | extended dimension index | +| | | to write to. The default | +| | | index is determined by | +| | | lookup relative to the | +| | | existing extended | +| | | dimension. | +| | | | +| | | **Note:** data can also | +| | | be written by setting a | +| | | slice of a file | +| | | variable, and attributes | +| | | can be written by | +| | | setting an attribute of | +| | | a file variable. | ++--------------------------+--------------------------+--------------------------+ -Axis -.. raw:: html +Table 2.15 CDMS Datatypes - +2.7 Database +^^^^^^^^^^^^ +A Database is a collection of datasets and other CDMS objects. It +consists of a hierarchical collection of objects, with the database +being at the root, or top of the hierarchy. A database is used to: -createUniformLatitudeAxis(startLat, nlat, deltaLat): Create a uniform -latitude axis. The axis boundaries are at the midpoints of the axis -values. The axis is designated as a circular latitude axis. startLat is -the starting latitude value. nlat is the number of latitudes. deltaLat -is the increment between latitudes. - -.. raw:: html - -
- -RectGrid - -.. raw:: html - - - -createZonalGrid(grid): Create a zonal grid. The output grid has the same -latitude as the input grid, and a single longitude. This may be used to -calculate zonal averages via a regridding operation. grid is a RectGrid. - -.. raw:: html - -
- -Axis - -.. raw:: html - - - -createUniformLongitudeAxis(startLon, nlon, delta-Lon): Create a uniform -longitude axis. The axis boundaries are at the midpoints of the axis -values. The axis is designated as a circular longitude axis. startLon is -the starting longitude value. nlon is the number of longitudes. deltaLon -is the increment between longitudes. - -.. raw:: html - -
- -Variable - -.. raw:: html - - - -createVariable(array, typecode=None, copy=0, savespace=0, mask=None, -fill\_value=None, grid=None, axes=None, attributes=None, id=None): This -function is documented in Table 2.34 on page 90. - -.. raw:: html - -
- -Integer - -.. raw:: html - - - -getAutoBounds(): Get the current autobounds mode. Returns 0, 1, or 2. -See setAutoBounds. - -.. raw:: html - -
- -Integer - -.. raw:: html - - - -isVariable(s): Return 1 if s is a variable, 0 otherwise. See also: -asVariable. - -.. raw:: html - -
- -Dataset or CdmsFile - -.. raw:: html - - - -open(url,mode='r'): Open or create a Dataset or CdmsFile. url is a -Uniform Resource Locator, referring to a cdunif or XML file. If the URL -has the extension '.xml' or '.cdml', a Dataset is returned, otherwise a -CdmsFile is returned. If the URL protocol is 'http', the file must be a -'.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is -'file' or is omitted, a local file or dataset is opened. mode is the -open mode. See Table 2.24 on page 70. - -.. raw:: html - -

- -Example: Open an existing dataset: - -f = cdms.open("sampleset.xml") - -.. raw:: html - -

- -.. raw:: html - -

- -Example: Create a netCDF file: - -f = cdms.open("newfile.nc",'w') - -.. raw:: html - -

- -.. raw:: html - -
- -List - -.. raw:: html - - - -order2index (axes, orderstring): Find the index permutation of axes to -match order. Return a list of indices. axes is a list of axis objects. -orderstring is defined as in orderparse. - -.. raw:: html - -
- -List - -.. raw:: html - - - -orderparse(orderstring): Parse an order string. Returns a list of axes -specifiers. orderstring consists of: - -.. raw:: html - -
    - -:: - -
  • Letters t, x, y, z meaning time, longitude, latitude, level
  • - -
  • Numbers 0-9 representing position in axes
  • - -
  • Dash (-) meaning insert the next available axis here.
  • - -
  • The ellipsis ... meaning fill these positions with any remaining axes.
  • - -
  • (name) meaning an axis whose id is name
  • - -.. raw:: html - -
- -.. raw:: html - -
- -None - -.. raw:: html - - - -setAutoBounds(mode): Set autobounds mode. In some circumstances CDMS can -generate boundaries for 1-D axes and rectilinear grids, when the bounds -are not explicitly defined. The autobounds mode determines how this is -done: If mode is 'grid' or 2 (the default), the getBounds method will -automatically generate boundary information for an axis or grid if the -axis is designated as a latitude or longitude axis, and the boundaries -are not explicitly defined. If mode is 'on' or 1, the getBounds method -will automatically generate boundary information for an axis or grid, if -the boundaries are not explicitly defined. If mode is 'off' or 0, and no -boundary data is explicitly defined, the bounds will NOT be generated; -the getBounds method will return None for the boundaries. Note: In -versions of CDMS prior to V4.0, the default mode was 'on'. - -.. raw:: html - -
- -None - -.. raw:: html - - - -setClassifyGrids(mode): Set the grid classification mode. This affects -how grid type is determined, for the purpose of generating grid -boundaries. If mode is 'on' (the default), grid type is determined by a -grid classification method, regardless of the value of grid.get-Type(). -If mode is 'off', the value of grid.getType() determines the grid type - -.. raw:: html - -
- -None - -.. raw:: html - - - -writeScripGrid(path, grid, gridTitle=None): Write a grid to a SCRIP grid -file. path is a string, the path of the SCRIP file to be created. grid -is a CDMS grid object. It may be rectangular. gridTitle is a string ID -for the grid. - -.. raw:: html - -
- -Table 2.3 Class Tags - - -+--------------+---------------------+ -| Tag | Class | -+==============+=====================+ -| 'axis' | Axis | -+--------------+---------------------+ -| 'database' | Database | -+--------------+---------------------+ -| 'dataset' | Dataset, CdmsFile | -+--------------+---------------------+ -| 'grid' | RectGrid | -+--------------+---------------------+ -| 'variable' | Variable | -+--------------+---------------------+ -| 'xlink' | Xlink | -+--------------+---------------------+ - -2.4 CdmsObj -^^^^^^^^^^^ - -A CdmsObj is the base class for all CDMS database objects. At the -application level, CdmsObj objects are never created and used directly. -Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the -basis of user application programming. - -All objects derived from CdmsObj have a special attribute .attributes. -This is a Python dictionary, which contains all the external -(persistent) attributes associated with the object. This is in contrast -to the internal, non-persistent attributes of an object, which are -built-in and predefined. When a CDMS object is written to a file, the -external attributes are written, but not the internal attributes. - -**Example**: get a list of all external attributes of obj. - -{% highlight python %} extatts = obj.attributes.keys() {% endhighlight -%} - -Table 2.4 Attributes common to all CDMS objects - - -+--------------+--------------+--------------------------------------------------+ -| Type | Name | Definition | -+==============+==============+==================================================+ -| Dictionary | attributes | External attribute dictionary for this object. | -+--------------+--------------+--------------------------------------------------+ - -Table 2.5 Getting and setting attributes - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
TypeDefinition
- -various - -.. raw:: html - - - -value = obj.attname - -.. raw:: html - -

- -Get an internal or external attribute value. If the attribute is -external, it is read from the database. If the attribute is not already -in the database, it is created as an external attribute. Internal -attributes cannot be created, only referenced. - -.. raw:: html - -

- -.. raw:: html - -
- -various - -.. raw:: html - - - -obj.attname = value - -.. raw:: html - -

- -Set an internal or external attribute value. If the attribute is -external, it is written to the database. - -.. raw:: html - -

- -.. raw:: html - -
- -2.5 CoordinateAxis -^^^^^^^^^^^^^^^^^^ - -A CoordinateAxis is a variable that represents coordinate information. -It may be contained in a file or dataset, or may be transient -(memoryresident). Setting a slice of a file CoordinateAxis writes to the -file, and referencing a file CoordinateAxis slice reads data from the -file. Axis objects are also used to define the domain of a Variable. - -CDMS defines several different types of CoordinateAxis objects. Table -2.9 on page 45 documents methods that are common to all CoordinateAxis -types. Table 2.10 on page 48 specifies methods that are unique to 1D -Axis objects. - -Table 2.6 CoordinateAxis types - - -+----------+-------------+ -| Type | Definition | -+==========+=============+ -| ``Coordi | A variable | -| nateAxis | that | -| `` | represents | -| | coordinate | -| | information | -| | . | -| | Has | -| | subtypes | -| | ``Axis2D`` | -| | and | -| | ``AuxAxis1D | -| | ``. | -+----------+-------------+ -| ``Axis`` | A | -| | one-dimensi | -| | onal | -| | coordinate | -| | axis whose | -| | values are | -| | strictly | -| | monotonic. | -| | Has | -| | subtypes | -| | ``DatasetAx | -| | is``, | -| | ``FileAxis` | -| | `, | -| | and | -| | ``Transient | -| | Axis``. | -| | May be an | -| | index axis, | -| | mapping a | -| | range of | -| | integers to | -| | the | -| | equivalent | -| | floating | -| | point | -| | value. If a | -| | latitude or | -| | longitude | -| | axis, may | -| | be | -| | associated | -| | with a | -| | ``RectGrid` | -| | `. | -+----------+-------------+ -| ``Axis2D | A | -| `` | two-dimensi | -| | onal | -| | coordinate | -| | axis, | -| | typically a | -| | latitude or | -| | longitude | -| | axis | -| | related to | -| | a | -| | ``Curviline | -| | arGrid``. | -| | Has | -| | subtypes | -| | ``DatasetAx | -| | is2D``, | -| | ``FileAxis2 | -| | D``, | -| | and | -| | ``Transient | -| | Axis2D``. | -+----------+-------------+ -| ``AuxAxi | A | -| s1D`` | one-dimensi | -| | onal | -| | coordinate | -| | axis whose | -| | values need | -| | not be | -| | monotonic. | -| | Typically a | -| | latitude or | -| | longitude | -| | axis | -| | associated | -| | with a | -| | ``GenericGr | -| | id``. | -| | Has | -| | subtypes | -| | ``DatasetAu | -| | xAxis1D``, | -| | ``FileAuxAx | -| | is1D``, | -| | and | -| | ``Transient | -| | AuxAxis1D`` | -| | . | -| | An axis in | -| | a | -| | ``CdmsFile` | -| | ` | -| | may be | -| | designated | -| | the | -| | unlimited | -| | axis, | -| | meaning | -| | that it can | -| | be extended | -| | in length | -| | after the | -| | initial | -| | definition. | -| | There can | -| | be at most | -| | one | -| | unlimited | -| | axis | -| | associated | -| | with a | -| | ``CdmsFile` | -| | `. | -+----------+-------------+ - -Table 2.7 CoordinateAxis Internal Attributes - - -+------------------+------------------+--------------------------------------------+ -| Type | Name | Definition | -+==================+==================+============================================+ -| ``Dictionary`` | ``attributes`` | External attribute dictionary. | -+------------------+------------------+--------------------------------------------+ -| ``String`` | ``id`` | CoordinateAxis identifer. | -+------------------+------------------+--------------------------------------------+ -| ``Dataset`` | ``parent`` | The dataset which contains the variable. | -+------------------+------------------+--------------------------------------------+ -| ``Tuple`` | ``shape`` | The length of each axis. | -+------------------+------------------+--------------------------------------------+ - -Table 2.8 Axis Constructors - - -+---------------+---------------+ -| Constructor | Description | -+===============+===============+ -| ``cdms.create | Create an | -| Axis(data, bo | axis which is | -| unds=None)`` | not | -| | associated | -| | with a | -| | dataset or | -| | file. See | -| | Table 2.2 on | -| | page 33. | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``Dataset.cre | Create an | -| ateAxis(name, | ``Axis`` in a | -| ar)`` | ``Dataset``. | -| | (This | -| | function is | -| | not yet | -| | implemented. | -| | ) | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``CdmsFile.cr | Create an | -| eateAxis(name | Axis in a | -| ,ar,unlimited | ``CdmsFile``. | -| =0)`` | ``name`` is | -| | the string | -| | ``name`` of | -| | the ``Axis``. | -| | ``ar`` is a | -| | 1-D data | -| | array which | -| | defines the | -| | ``Axis`` | -| | values. It | -| | may have the | -| | value | -| | ``None`` if | -| | an unlimited | -| | axis is being | -| | defined. At | -| | most one | -| | ``Axis`` in a | -| | ``CdmsFile`` | -| | may be | -| | designated as | -| | being | -| | unlimited, | -| | meaning that | -| | it may be | -| | extended in | -| | length. To | -| | define an | -| | axis as | -| | unlimited, | -| | either: | -+---------------+---------------+ -| | A) set ``ar`` | -| | to ``None``, | -| | and leave | -| | ``unlimited`` | -| | undefined, or | -+---------------+---------------+ -| | B) set ``ar`` | -| | to the | -| | initial 1-D | -| | array, and | -| | set | -| | ``unlimited`` | -| | to | -| | ``cdms.Unlimi | -| | ted`` | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``cdms.create | See Table 2.2 | -| EqualAreaAxis | on page 33. | -| (nlat)`` | | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``cdms.create | See Table 2.2 | -| GaussianAxis( | on page 18. | -| nlat)`` | | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``cdms.create | See Table 2.2 | -| UniformLatitu | on page 18. | -| deAxis(startl | | -| at, nlat, del | | -| talat)`` | | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ -| ``cdms.create | See Table 2.2 | -| UniformLongit | on page 18. | -| udeAxis(start | | -| lon, nlon, de | | -| ltalon)`` | | -+---------------+---------------+ -| ----------- | ------------ | -+---------------+---------------+ - -Table 2.9 CoordinateAxis Methods - - -+-------+-------+-------+ -| Type | Metho | Defin | -| | d | ition | -+=======+=======+=======+ -| ``Arr | ``arr | Read | -| ay`` | ay = | a | -| | axis[ | slice | -| | i:j]` | of | -| | ` | data | -| | | from | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et. | -| | | Data | -| | | is | -| | | retur | -| | | ned | -| | | in | -| | | the | -| | | physi | -| | | cal | -| | | order | -| | | ing | -| | | defin | -| | | ed | -| | | in | -| | | the | -| | | datas | -| | | et. | -| | | See | -| | | Table | -| | | 2.11 | -| | | on | -| | | page | -| | | 51 | -| | | for a | -| | | descr | -| | | iptio | -| | | n | -| | | of | -| | | slice | -| | | opera | -| | | tors. | -+-------+-------+-------+ -| ``Non | ``axi | Write | -| e`` | s[i:j | a | -| | ] = a | slice | -| | rray` | of | -| | ` | data | -| | | to | -| | | the | -| | | exter | -| | | nal | -| | | file. | -| | | Datas | -| | | et | -| | | axes | -| | | are | -| | | read- | -| | | only. | -+-------+-------+-------+ -| ``Non | ``ass | Set | -| e`` | ignVa | the | -| | lue(a | entir | -| | rray) | e | -| | `` | value | -| | | of | -| | | the | -| | | axis. | -| | | ``arr | -| | | ay`` | -| | | is a | -| | | Numer | -| | | ic | -| | | array | -| | | , | -| | | of | -| | | the | -| | | same | -| | | dimen | -| | | siona | -| | | lity | -| | | as | -| | | the | -| | | axis. | -+-------+-------+-------+ -| ``Axi | ``clo | Retur | -| s`` | ne(co | n | -| | pyDat | a | -| | a=1)` | copy | -| | ` | of | -| | | the | -| | | axis, | -| | | as a | -| | | trans | -| | | ient | -| | | axis. | -| | | If | -| | | copyD | -| | | ata | -| | | is 1 | -| | | (the | -| | | defau | -| | | lt) | -| | | the | -| | | data | -| | | itsel | -| | | f | -| | | is | -| | | copie | -| | | d. | -+-------+-------+-------+ -| ``Non | ``des | Desig | -| e`` | ignat | nate | -| | eLati | the | -| | tude( | axis | -| | persi | to be | -| | stent | a | -| | =0)`` | latit | -| | | ude | -| | | axis. | -| | | If | -| | | persi | -| | | stent | -| | | is | -| | | true, | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et | -| | | (if | -| | | any) | -| | | is | -| | | modif | -| | | ied. | -| | | By | -| | | defau | -| | | lt, | -| | | the | -| | | desig | -| | | natio | -| | | n | -| | | is | -| | | tempo | -| | | rary. | -+-------+-------+-------+ -| ``Non | ``des | Desig | -| e`` | ignat | nate | -| | eLeve | the | -| | l(per | axis | -| | siste | to be | -| | nt=0) | a | -| | `` | verti | -| | | cal | -| | | level | -| | | axis. | -| | | If | -| | | persi | -| | | stent | -| | | is | -| | | true, | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et | -| | | (if | -| | | any) | -| | | is | -| | | modif | -| | | ied. | -| | | By | -| | | defau | -| | | lt, | -| | | the | -| | | desig | -| | | natio | -| | | n | -| | | is | -| | | tempo | -| | | rary. | -+-------+-------+-------+ -| ``Non | ``des | Desig | -| e`` | ignat | nate | -| | eLong | the | -| | itude | axis | -| | (pers | to be | -| | isten | a | -| | t=0, | longi | -| | modul | tude | -| | o=360 | axis. | -| | .0)`` | ``mod | -| | | ulo`` | -| | | is | -| | | the | -| | | modul | -| | | us | -| | | value | -| | | . | -| | | Any | -| | | given | -| | | axis | -| | | value | -| | | ``x`` | -| | | is | -| | | treat | -| | | ed | -| | | as | -| | | equiv | -| | | alent | -| | | to | -| | | ``x + | -| | | modu | -| | | lus`` | -| | | . | -| | | If | -| | | ``per | -| | | siste | -| | | nt`` | -| | | is | -| | | true, | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et | -| | | (if | -| | | any) | -| | | is | -| | | modif | -| | | ied. | -| | | By | -| | | defau | -| | | lt, | -| | | the | -| | | desig | -| | | natio | -| | | n | -| | | is | -| | | tempo | -| | | rary. | -+-------+-------+-------+ -| ``Non | ``des | Desig | -| e`` | ignat | nate | -| | eTime | the | -| | (pers | axis | -| | isten | to be | -| | t=0, | a | -| | calen | time | -| | dar = | axis. | -| | cdti | If | -| | me.Mi | ``per | -| | xedCa | siste | -| | lenda | nt`` | -| | r)`` | is | -| | | true, | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et | -| | | (if | -| | | any) | -| | | is | -| | | modif | -| | | ied. | -| | | By | -| | | defau | -| | | lt, | -| | | the | -| | | desig | -| | | natio | -| | | n | -| | | is | -| | | tempo | -| | | rary. | -| | | ``cal | -| | | endar | -| | | `` | -| | | is | -| | | defin | -| | | ed | -| | | as in | -| | | ``get | -| | | Calen | -| | | dar() | -| | | ``. | -+-------+-------+-------+ -| ``Arr | ``get | Get | -| ay`` | Bound | the | -| | s()`` | assoc | -| | | iated | -| | | bound | -| | | ary | -| | | array | -| | | . | -| | | The | -| | | shape | -| | | of | -| | | the | -| | | retur | -| | | n | -| | | array | -| | | depen | -| | | ds | -| | | on | -| | | the | -| | | type | -| | | of | -| | | axis: | -+-------+-------+-------+ -| | ``Axi | -| | s``: | -| | ``(n, | -| | 2)`` | -+-------+-------+-------+ -| | ``Axi | -| | s2D`` | -| | : | -| | ``(i, | -| | j,4)` | -| | ` | -+-------+-------+-------+ -| | ``Aux | -| | Axis1 | -| | D``: | -| | ``(nc | -| | ell, | -| | nvert | -| | )`` | -| | where | -| | nvert | -| | is | -| | the | -| | maxim | -| | um | -| | numbe | -| | r | -| | of | -| | verti | -| | ces | -| | of a | -| | cell. | -+-------+-------+-------+ -| | If | -| | the | -| | bound | -| | ary | -| | array | -| | of a | -| | latit | -| | ude | -| | or | -| | longi | -| | tude | -| | ``Axi | -| | s`` | -| | is | -| | not | -| | expli | -| | citly | -| | defin | -| | ed, | -| | and | -| | ``aut | -| | oBoun | -| | ds`` | -| | mode | -| | is | -| | on, a | -| | defau | -| | lt | -| | array | -| | is | -| | gener | -| | ated | -| | by | -| | calli | -| | ng | -| | ``gen | -| | Gener | -| | icBou | -| | nds`` | -| | . | -| | Other | -| | wise | -| | if | -| | auto- | -| | Bound | -| | s | -| | mode | -| | is | -| | off, | -| | the | -| | retur | -| | n | -| | value | -| | is | -| | ``Non | -| | e``. | -| | See | -| | ``set | -| | AutoB | -| | ounds | -| | ``. | -+-------+-------+-------+ -| ``Int | ``get | Retur | -| eger` | Calen | ns | -| ` | dar() | the | -| | `` | calen | -| | | dar | -| | | assoc | -| | | iated | -| | | with | -| | | the | -| | | ``(ti | -| | | me)`` | -| | | \ axi | -| | | s. | -| | | Possi | -| | | ble | -| | | retur | -| | | n | -| | | value | -| | | s, | -| | | as | -| | | defin | -| | | ed | -| | | in | -| | | the | -| | | ``cdt | -| | | ime`` | -| | | modul | -| | | e, | -| | | are: | -+-------+-------+-------+ -| | ``cdt | -| | ime.G | -| | regor | -| | ianCa | -| | lenda | -| | r``: | -| | the | -| | stand | -| | ard | -| | Grego | -| | rian | -| | calen | -| | dar | -+-------+-------+-------+ -| | ``cdt | -| | ime.M | -| | ixedC | -| | alend | -| | ar``: | -| | mixed | -| | Julia | -| | n/Gre | -| | goria | -| | n | -| | calen | -| | dar | -+-------+-------+-------+ -| | ``cdt | -| | ime.J | -| | ulian | -| | Calen | -| | dar`` | -| | : | -| | years | -| | divis | -| | ible | -| | by 4 | -| | are | -| | leap | -| | years | -+-------+-------+-------+ -| | ``cdt | -| | ime.N | -| | oLeap | -| | Calen | -| | dar`` | -| | : | -| | a | -| | year | -| | is | -| | 365 | -| | days | -+-------+-------+-------+ -| | ``cdt | -| | ime.C | -| | alend | -| | ar360 | -| | ``: | -| | a | -| | year | -| | is | -| | 360 | -| | days | -+-------+-------+-------+ -| | ``Non | -| | e``: | -| | no | -| | calen | -| | dar | -| | can | -| | be | -| | ident | -| | ified | -+-------+-------+-------+ -| | Note: | -| | If | -| | the | -| | axis | -| | is | -| | not a | -| | time | -| | axis, | -| | the | -| | globa | -| | l, | -| | file- | -| | relat | -| | ed | -| | calen | -| | dar | -| | is | -| | retur | -| | ned. | -+-------+-------+-------+ -| ``Arr | ``get | Get | -| ay`` | Value | the | -| | ()`` | entir | -| | | e | -| | | axis | -| | | vecto | -| | | r. | -+-------+-------+-------+ -| ``Int | ``isL | Retur | -| eger` | atitu | ns | -| ` | de()` | true | -| | ` | iff | -| | | the | -| | | axis | -| | | is a | -| | | latit | -| | | ude | -| | | axis. | -+-------+-------+-------+ -| ``Int | ``isL | Retur | -| eger` | evel( | ns | -| ` | )`` | true | -| | | iff | -| | | the | -| | | axis | -| | | is a | -| | | level | -| | | axis. | -+-------+-------+-------+ -| ``Int | ``isL | Retur | -| eger` | ongit | ns | -| ` | ude() | true | -| | `` | iff | -| | | the | -| | | axis | -| | | is a | -| | | longi | -| | | tude | -| | | axis. | -+-------+-------+-------+ -| ``Int | ``isT | Retur | -| eger` | ime() | ns | -| ` | `` | true | -| | | iff | -| | | the | -| | | axis | -| | | is a | -| | | time | -| | | axis. | -+-------+-------+-------+ -| ``Int | ``len | The | -| eger` | (axis | lengt | -| ` | )`` | h | -| | | of | -| | | the | -| | | axis | -| | | if | -| | | one-d | -| | | imens | -| | | ional | -| | | . | -| | | If | -| | | multi | -| | | dimen | -| | | siona | -| | | l, | -| | | the | -| | | lengt | -| | | h | -| | | of | -| | | the | -| | | first | -| | | dimen | -| | | sion. | -+-------+-------+-------+ -| ``Int | ``siz | The | -| eger` | e()`` | numbe | -| ` | | r | -| | | of | -| | | eleme | -| | | nts | -| | | in | -| | | the | -| | | axis. | -+-------+-------+-------+ -| ``Str | ``typ | The | -| ing`` | ecode | ``Num | -| | ()`` | eric` | -| | | ` | -| | | datat | -| | | ype | -| | | ident | -| | | ifier | -| | | . | -+-------+-------+-------+ - -Table 2.10 Axis Methods, additional to CoordinateAxis methods - - -+-------+-------+-------+ -| Type | Metho | Defin | -| | d | ition | -+=======+=======+=======+ -| ``Lis | ``asC | ``Arr | -| t`` | ompon | ay`` | -| of | entTi | versi | -| compo | me(ca | on | -| nent | lenda | of | -| times | r=Non | ``cdt | -| | e)`` | ime t | -| | | ocomp | -| | | ``. | -| | | Retur | -| | | ns | -| | | a | -| | | ``Lis | -| | | t`` | -| | | of | -| | | compo | -| | | nent | -| | | times | -| | | . | -+-------+-------+-------+ -| ``Lis | ``asR | ``Arr | -| t`` | elati | ay`` | -| of | veTim | versi | -| relat | e()`` | on | -| ive | | of | -| times | | ``cdt | -| | | ime t | -| | | orel` | -| | | `. | -| | | Retur | -| | | ns | -| | | a | -| | | ``Lis | -| | | t`` | -| | | of | -| | | relat | -| | | ive | -| | | times | -| | | . | -+-------+-------+-------+ -| ``Non | ``des | Desig | -| e`` | ignat | nate | -| | eCirc | the | -| | ular( | axis | -| | modul | to be | -| | o, pe | circu | -| | rsist | lar. | -| | ent=0 | ``mod | -| | )`` | ulo`` | -| | | is | -| | | the | -| | | modul | -| | | us | -| | | value | -| | | . | -| | | Any | -| | | given | -| | | axis | -| | | value | -| | | ``x`` | -| | | is | -| | | treat | -| | | ed | -| | | as | -| | | equiv | -| | | alent | -| | | to | -| | | ``x + | -| | | modu | -| | | lus`` | -| | | . | -| | | If | -| | | ``per | -| | | siste | -| | | nt`` | -| | | is | -| | | ``Tru | -| | | e``, | -| | | the | -| | | exter | -| | | nal | -| | | file | -| | | or | -| | | datas | -| | | et | -| | | (if | -| | | any) | -| | | is | -| | | modif | -| | | ied. | -| | | By | -| | | defau | -| | | lt, | -| | | the | -| | | desig | -| | | natio | -| | | n | -| | | is | -| | | tempo | -| | | rary. | -+-------+-------+-------+ -| ``Int | ``isC | Retur | -| eger` | ircul | ns | -| ` | ar()` | ``Tru | -| | ` | e`` | -| | | if | -| | | the | -| | | axis | -| | | has | -| | | circu | -| | | lar | -| | | topol | -| | | ogy. | -| | | An | -| | | axis | -| | | is | -| | | defin | -| | | ed | -| | | as | -| | | circu | -| | | lar | -| | | if: | -+-------+-------+-------+ -| | ``axi | -| | s.top | -| | ology | -| | == ' | -| | circu | -| | lar'` | -| | `, | -| | or | -+-------+-------+-------+ -| | ``axi | -| | s.top | -| | ology | -| | `` | -| | is | -| | undef | -| | ined, | -| | and | -| | the | -| | axis | -| | is a | -| | longi | -| | tude. | -| | The | -| | defau | -| | lt | -| | cycle | -| | for | -| | circu | -| | lar | -| | axes | -| | is | -| | 360.0 | -+-------+-------+-------+ -| ``Int | ``isL | Retur | -| eger` | inear | ns | -| ` | ()`` | ``Tru | -| | | e`` | -| | | if | -| | | the | -| | | axis | -| | | has a | -| | | linea | -| | | r | -| | | repre | -| | | senta | -| | | tion. | -+-------+-------+-------+ -| ``Tup | ``map | Same | -| le`` | Inter | as | -| | val(i | ``map | -| | nterv | Inter | -| | al)`` | valEx | -| | | t``, | -| | | but | -| | | retur | -| | | ns | -| | | only | -| | | the | -| | | tuple | -| | | ``(i, | -| | | j)``, | -| | | and | -| | | ``wra | -| | | parou | -| | | nd`` | -| | | is | -| | | restr | -| | | icted | -| | | to | -| | | one | -| | | cycle | -| | | . | -+-------+-------+-------+ -| ``(i, | ``map | Map a | -| j,k)` | Inter | coord | -| ` | valEx | inate | -| | t(int | inter | -| | erval | val | -| | )`` | to an | -| | | index | -| | | ``int | -| | | erval | -| | | ``. | -| | | ``int | -| | | erval | -| | | `` | -| | | is a | -| | | tuple | -| | | havin | -| | | g | -| | | one | -| | | of | -| | | the | -| | | forms | -| | | : | -+-------+-------+-------+ -| | ``(x, | -| | y)`` | -+-------+-------+-------+ -| | ``(x, | -| | y,ind | -| | icato | -| | r)`` | -+-------+-------+-------+ -| | ``(x, | -| | y,ind | -| | icato | -| | r,cyc | -| | le)`` | -+-------+-------+-------+ -| | ``Non | -| | e or | -| | ':'`` | -+-------+-------+-------+ -| | where | -| | ``x`` | -| | and | -| | ``y`` | -| | are | -| | coord | -| | inate | -| | s | -| | indic | -| | ating | -| | the | -| | inter | -| | val | -| | ``[x, | -| | y)``, | -| | and: | -+-------+-------+-------+ -| | ``ind | -| | icato | -| | r`` | -| | is a | -| | two | -| | or | -| | three | -| | -char | -| | acter | -| | strin | -| | g, | -| | where | -| | the | -| | first | -| | chara | -| | cter | -| | is | -| | ``'c' | -| | `` | -| | if | -| | the | -| | inter | -| | val | -| | is | -| | close | -| | d | -| | on | -| | the | -| | left, | -| | ``'o' | -| | `` | -| | if | -| | open, | -| | and | -| | the | -| | secon | -| | d | -| | chara | -| | cter | -| | has | -| | the | -| | same | -| | meani | -| | ng | -| | for | -| | the | -| | right | -| | -hand | -| | point | -| | . | -| | If | -| | prese | -| | nt, | -| | the | -| | third | -| | chara | -| | cter | -| | speci | -| | fies | -| | how | -| | the | -| | inter | -| | val | -| | shoul | -| | d | -| | be | -| | inter | -| | secte | -| | d | -| | with | -| | the | -| | axis: | -+-------+-------+-------+ -| | ``'n' | -| | `` | -| | - | -| | selec | -| | t | -| | node | -| | value | -| | s | -| | which | -| | are | -| | conta | -| | ined | -| | in | -| | the | -| | inter | -| | val | -+-------+-------+-------+ -| | ``'b' | -| | `` | -| | -sele | -| | ct | -| | axis | -| | eleme | -| | nts | -| | for | -| | which | -| | the | -| | corre | -| | spond | -| | ing | -| | cell | -| | bound | -| | ary | -| | inter | -| | sects | -| | the | -| | inter | -| | val | -+-------+-------+-------+ -| | ``'e' | -| | `` | -| | - | -| | same | -| | as n, | -| | but | -| | inclu | -| | de | -| | an | -| | extra | -| | node | -| | on | -| | eithe | -| | r | -| | side | -+-------+-------+-------+ -| | ``'s' | -| | `` | -| | - | -| | selec | -| | t | -| | axis | -| | eleme | -| | nts | -| | for | -| | which | -| | the | -| | cell | -| | bound | -| | ary | -| | is a | -| | subse | -| | t | -| | of | -| | the | -| | inter | -| | val | -+-------+-------+-------+ -| | The | -| | defau | -| | lt | -| | indic | -| | ator | -| | is | -| | 'ccn' | -| | , | -| | that | -| | is, | -| | the | -| | inter | -| | val | -| | is | -| | close | -| | d, | -| | and | -| | nodes | -| | in | -| | the | -| | inter | -| | val | -| | are | -| | selec | -| | ted. | -+-------+-------+-------+ -| | If | -| | ``cyc | -| | le`` | -| | is | -| | speci | -| | fied, | -| | the | -| | axis | -| | is | -| | treat | -| | ed | -| | as | -| | circu | -| | lar | -| | with | -| | the | -| | given | -| | cycle | -| | value | -| | . | -| | By | -| | defau | -| | lt, | -| | if | -| | ``axi | -| | s.isC | -| | ircul | -| | ar()` | -| | ` | -| | is | -| | true, | -| | the | -| | axis | -| | is | -| | treat | -| | ed | -| | as | -| | circu | -| | lar | -| | with | -| | a | -| | defau | -| | lt | -| | modul | -| | us | -| | of | -| | ``360 | -| | .0``. | -+-------+-------+-------+ -| | An | -| | inter | -| | val | -| | of | -| | ``Non | -| | e`` | -| | or | -| | ``':' | -| | `` | -| | retur | -| | ns | -| | the | -| | full | -| | index | -| | inter | -| | val | -| | of | -| | the | -| | axis. | -+-------+-------+-------+ -| | The | -| | metho | -| | d | -| | retur | -| | ns | -| | the | -| | corre | -| | spond | -| | ing | -| | index | -| | inter | -| | val | -| | as a | -| | 3tupl | -| | e | -| | ``(i, | -| | j,k)` | -| | `, | -| | where | -| | ``k`` | -| | is | -| | the | -| | integ | -| | er | -| | strid | -| | e, | -| | and | -| | ``[i. | -| | j)`` | -| | is | -| | the | -| | half- | -| | open | -| | index | -| | inter | -| | val | -| | ``i < | -| | = k < | -| | j`` | -| | ``(i | -| | >= k | -| | > j i | -| | f k < | -| | 0)`` | -| | , | -| | or | -| | ``non | -| | e`` | -| | if | -| | the | -| | inter | -| | secti | -| | on | -| | is | -| | empty | -| | . | -+-------+-------+-------+ -| | for | -| | an | -| | axis | -| | which | -| | is | -| | circu | -| | lar | -| | (``ax | -| | is.to | -| | polog | -| | y == | -| | 'circ | -| | ular' | -| | ``), | -| | ``[i, | -| | j)`` | -| | is | -| | inter | -| | prete | -| | d | -| | as | -| | follo | -| | ws, | -| | where | -| | ``n = | -| | len( | -| | axis) | -| | `` | -+-------+-------+-------+ -| | if | -| | ``0 < | -| | = i < | -| | n`` | -| | and | -| | ``0 < | -| | = j < | -| | = n`` | -| | , | -| | the | -| | inter | -| | val | -| | does | -| | not | -| | wrap | -| | aroun | -| | d | -| | the | -| | axis | -| | endpo | -| | int. | -+-------+-------+-------+ -| | other | -| | wise | -| | the | -| | inter | -| | val | -| | wraps | -| | aroun | -| | d | -| | the | -| | axis | -| | endpo | -| | int. | -+-------+-------+-------+ -| | see | -| | also: | -| | ``map | -| | inter | -| | val`` | -| | , | -| | ``var | -| | iable | -| | .subr | -| | egion | -| | ()`` | -+-------+-------+-------+ -| ``tra | ``sub | creat | -| nsien | axis( | e | -| taxis | i,j,k | an | -| `` | =1)`` | axis | -| | | assoc | -| | | iated | -| | | with | -| | | the | -| | | integ | -| | | er | -| | | range | -| | | ``[i: | -| | | j:k]` | -| | | `. | -| | | the | -| | | strid | -| | | e | -| | | ``k`` | -| | | can | -| | | be | -| | | posit | -| | | ive | -| | | or | -| | | negat | -| | | ive. | -| | | wrapa | -| | | round | -| | | is | -| | | suppo | -| | | rted | -| | | for | -| | | longi | -| | | tude | -| | | dimen | -| | | sions | -| | | or | -| | | those | -| | | with | -| | | a | -| | | modul | -| | | us | -| | | attri | -| | | bute. | -+-------+-------+-------+ - -table 2.11 axis slice operators - - -+---------------+-----------------------------------------------------------------------------+ -| slice | definition | -+===============+=============================================================================+ -| ``[i]`` | the ``ith`` element, starting with index ``0`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:]`` | the ``ith`` element through and including the end | -+---------------+-----------------------------------------------------------------------------+ -| ``[:j]`` | the beginning element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[:]`` | the entire array | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | -+---------------+-----------------------------------------------------------------------------+ - -**example:** - -a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length -``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index -interval(s), with wraparound. the result index interval ``-2 <= n < 3`` -wraps around, since ``-2 < 0``, and has a stride of ``1``. this is -equivalent to the two contiguous index intervals ``2 <= n < 0`` and -``0 <= n < 3`` - -{% highlight python %} >>> axis.isCircular() 1 >>> -axis.mapIntervalExt((-5.0,5.0,'co')) (-2,3,1) {% endhighlight %} - -2.6 CdmsFile -^^^^^^^^^^^^ - -A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` -interface. netCDF files are accessible in read-write mode. All other -formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. - -As of CDMS V3, the legacy cuDataset interface is also supported by -Cdms-Files. See "cu Module" on page 180. - -Table 2.12 CdmsFile Internal Attributes - - -+------------------+------------------+---------------------------------------+ -| Type | Name | Definition | -+==================+==================+=======================================+ -| ``Dictionary`` | ``attributes`` | Global, external file attributes | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``grids`` | Grids contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``String`` | ``id`` | File pathname. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``variables`` | Variables contained in the file. | -+------------------+------------------+---------------------------------------+ - -Table 2.13 CdmsFile Constructors - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| ``fi | Open | -| leob | the | -| j = | file | -| cdms | spec | -| .ope | ifie | -| n(pa | d | -| th, | by | -| mode | path | -| )`` | retu | -| | rnin | -| | g | -| | a | -| | Cdms | -| | File | -| | obje | -| | ct. | -| | ``pa | -| | th`` | -| | is | -| | the | -| | file | -| | path | -| | name | -| | , | -| | a | -| | stri | -| | ng. | -| | ``mo | -| | de`` | -| | is | -| | the | -| | open | -| | mode | -| | indi | -| | cato | -| | r, | -| | as | -| | list | -| | ed | -| | in | -| | Tabl | -| | e | -| | 2.24 | -| | on | -| | page | -| | 70. | -+------+------+ -| ``fi | Crea | -| leob | te | -| j = | the | -| cdms | file | -| .cre | spec | -| ateD | ifie | -| atas | d | -| et(p | by | -| ath) | path | -| `` | , | -| | a | -| | stri | -| | ng. | -+------+------+ - -Table 2.14 CdmsFile Methods - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -.. raw:: html - - - -.. raw:: html - -
TypeMethodDefinition
Transient-Variablefileobj(varname, selector)

Calling a CdmsFile object as a function reads the region of data specified by the selector. The result is a transient variable, unless raw = 1 is specified. See "Selectors" on page 103.

Example: The following reads data for variable 'prc', year 1980:

f = cdms.open('test.nc')
-
-x = f('prc', time=('1980-1','1981-1'))
-
-.. raw:: html
-
-   
- -.. raw:: html - -

Variable, Axis, or Grid

fileobj['id']

Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable.

Example: The following gets the persistent variable v, equivalent to v = f.variables['prc'].

-
f = cdms.open('sample.nc')
-
-v = f['prc']
-
-.. raw:: html
-
-   
- -.. raw:: html - -

- -Example: The following gets the axis named time, equivalent to t = -f.axes['time']. - -.. raw:: html - -

- -:: - -

t = f['time']

Noneclose()Close the file.
AxiscopyAxis(axis, newname=None)Copy axis values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. axis is the axis object to be copied. newname, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used.
GridcopyGrid(grid, newname=None)Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. grid is the grid object to be copied. newname, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used.
AxiscreateAxis(id, ar, unlimited=0)Create a new Axis. This is a persistent object which can be used to read or write axis data to the file. id is an alphanumeric string identifier, containing no blanks. ar is the one-dimensional axis array. Set unlimited to cdms.Unlimited to indicate that the axis is extensible.
RectGridcreateRectGrid(id, lat, lon, order, type="generic", mask=None)Create a RectGrid in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. lat is a latitude axis in the file. lon is a longitude axis in the file. order is a string with value "yx" (the first grid dimension is latitude) or "xy" (the first grid dimension is longitude). type is one of 'gaussian','uniform','equalarea', or 'generic'. If specified, mask is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid.
VariablecreateVariable(String id, String datatype,List axes, fill_value=None)Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. id is a String name which is unique with respect to all other objects in the file. datatype is an MA typecode, e.g., MA.Float, MA.Int. axes is a list of Axis and/or Grid objects. fill_value is the missing value (optional).
VariablecreateVariableCopy(var, newname=None)

Create a new Variable, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. var is the Variable to be copied. newname, if specified is the name of the new variable. If unspecified, the returned variable has the same name as var.

Note: Unlike copyAxis, the actual data is not copied to the new variable.

CurveGrid or Generic-GridreadScripGrid(self, whichGrid='destination', check-Grid=1)Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, whichGrid chooses the grid to read, either "source" or "destination". If checkGrid is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.
Nonesync()Writes any pending changes to the file.
Variable
write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)

Write a variable or array to the file. The return value is the associated file variable.

If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords extend and index, and the unlimited dimension values associated with var.

var is a Variable, masked array, or Numeric array. attributes is the attribute dictionary for the variable. The default is var.attributes. axes is the list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). extbounds is the unlimited dimension bounds. Defaults to var.getAxis(0).getBounds(). id is the variable name in the file. Default is var.id. extend = 1 causes the first dimension to be unlimited: iteratively writeable. The default is None, in which case the first dimension is extensible if it is time.Set to 0 to turn off this behaviour. fill_value is the missing value flag. index is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension.

-

Note: data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable.

-
- -Table 2.15 CDMS Datatypes - - -+-----------------+-----------------------------------+ -| CDMS Datatype | Definition | -+=================+===================================+ -| ``CdChar`` | character | -+-----------------+-----------------------------------+ -| ``CdDouble`` | double-precision floating-point | -+-----------------+-----------------------------------+ -| ``CdFloat`` | floating-point | -+-----------------+-----------------------------------+ -| ``CdInt`` | integer | -+-----------------+-----------------------------------+ -| ``CdLong`` | long integer | -+-----------------+-----------------------------------+ -| ``CdShort`` | short integer | -+-----------------+-----------------------------------+ - -2.7 Database -^^^^^^^^^^^^ - -A Database is a collection of datasets and other CDMS objects. It -consists of a hierarchical collection of objects, with the database -being at the root, or top of the hierarchy. A database is used to: - -- search for metadata -- access data -- provide authentication and access control for data and metadata - -The figure below illustrates several important points: - -- Each object in the database has a relative name of the form tag=id. - The id of an object is unique with respect to all objects contained - in the parent. - -- The name of the object consists of its relative name followed by the - relative name(s) of its antecedent objects, up to and including the - database name. In the figure below, one of the variables has name - ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. - -- Subordinate objects are thought of as being contained in the parent. - In this example, the database 'CDMS' contains two datasets, each of - which contain several variables. - -.. figure:: /images/diagram1.jpg - :alt: Diagram 1 - - Diagram 1 - -Figure 1 - - -2.7.1 Overview -'''''''''''''' - -To access a database: - -.. raw:: html - -
    - -.. raw:: html - -
  1. - -Open a connection. The connect method opens a database connection. -connect takes a database URI and returns a database object: db = -cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US") - -.. raw:: html - -
  2. - -.. raw:: html - -
  3. - -.. raw:: html - -

    - -Search the database, locating one or more datasets, variables, and/or -other objects. - -.. raw:: html - -

    - -.. raw:: html - -

    - -The database searchFilter method searches the database. A single -database connection may be used for an arbitrary number of searches. - -.. raw:: html - -

    - -.. raw:: html - -

    - -Example: Find all observed datasets - -.. raw:: html - -

    - -.. raw:: html - -

    - -result = db.searchFilter(category="observed",tag="dataset") - -.. raw:: html - -

    - -.. raw:: html - -

    - -Searches can be restricted to a subhierarchy of the database. - -.. raw:: html - -

    - -.. raw:: html - -

    - -Example: Search just the dataset 'ncep\_reanalysis\_mo': - -.. raw:: html - -

    - -.. raw:: html - -

    - -result = db.searchFilter(relbase="dataset=ncep\_reanalysis") - -.. raw:: html - -

    - -.. raw:: html - -
  4. - -.. raw:: html - -
  5. - -Refine the search results if necessary. The result of a search can be -narrowed with the searchPredicate method. - -.. raw:: html - -
  6. - -.. raw:: html - -
  7. - -.. raw:: html - -

    - -Process the results. A search result consists of a sequence of entries. -Each entry has a name, the name of the CDMS object, and an attribute -dictionary, consisting of the attributes located by the search: - -.. raw:: html - -

    - -.. raw:: html - -

    - - for entry in result: print entry.name, entry.attributes - -.. raw:: html - -

    - -.. raw:: html - -
  8. - -.. raw:: html - -
  9. - -.. raw:: html - -

    - -Access the data. The CDMS object associated with an entry is obtained -from the getObject method: - -.. raw:: html - -

    - -.. raw:: html - -

    - -obj = entry.getObject() - -.. raw:: html - -

    - -.. raw:: html - -

    - -If the id of a dataset is known, the dataset can be opened directly with -the open method: - -.. raw:: html - -

    - -.. raw:: html - -

    - -dset = db.open("ncep\_reanalysis\_mo") - -.. raw:: html - -

    - -.. raw:: html - -
  10. - -.. raw:: html - -
  11. - -.. raw:: html - -

    - -Close the database connection: - -.. raw:: html - -

    - -.. raw:: html - -

    - -db.close() - -.. raw:: html - -

    - -.. raw:: html - -
  12. - -.. raw:: html - -
- -Table 2.16 Database Internal Attributes - - -+------------------+------------------+----------------------------------------+ -| Type | Name | Summary | -+==================+==================+========================================+ -| ``Dictionary`` | ``attributes`` | Database attribute dictionary | -+------------------+------------------+----------------------------------------+ -| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``netloc`` | Hostname, for server-based databases | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``path`` | path name | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``uri`` | Uniform Resource Identifier | -+------------------+------------------+----------------------------------------+ - -Table 2.17 Database Constructors - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| ``db | Conn | -| = c | ect | -| dms. | to | -| conn | the | -| ect( | data | -| uri= | base | -| None | . | -| , us | ``ur | -| er=" | i`` | -| ", p | is | -| assw | the | -| ord= | Univ | -| "")` | ersa | -| ` | l | -| | Reso | -| | urce | -| | Inde | -| | ntif | -| | ier | -| | of | -| | the | -| | data | -| | base | -| | . | -| | The | -| | form | -| | of | -| | the | -| | URI | -| | depe | -| | nds | -| | on | -| | the | -| | impl | -| | emen | -| | tati | -| | on | -| | of | -| | the | -| | data | -| | base | -| | . | -| | For | -| | a | -| | Ligh | -| | twei | -| | ght | -| | Dire | -| | ctor | -| | y | -| | Acce | -| | ss | -| | Prot | -| | ocol | -| | (LDA | -| | P) | -| | data | -| | base | -| | , | -| | the | -| | form | -| | is: | -| | ``ld | -| | ap:/ | -| | /hos | -| | t[:p | -| | ort] | -| | /dbn | -| | ame` | -| | `. | -| | For | -| | exam | -| | ple, | -| | if | -| | the | -| | data | -| | base | -| | is | -| | loca | -| | ted | -| | on | -| | host | -| | dbho | -| | st.l | -| | lnl. | -| | gov, | -| | and | -| | is | -| | name | -| | d | -| | ``'d | -| | atab | -| | ase= | -| | CDMS | -| | ,ou= | -| | PCMD | -| | I,o= | -| | LLNL | -| | ,c=U | -| | S'`` | -| | , | -| | the | -| | URI | -| | is: | -| | ``ld | -| | ap:/ | -| | /dbh | -| | ost. | -| | llnl | -| | .gov | -| | /dat | -| | abas | -| | e=CD | -| | MS,o | -| | u=PC | -| | MDI, | -| | o=LL | -| | NL,c | -| | =US` | -| | `. | -| | If | -| | unsp | -| | ecif | -| | ied, | -| | the | -| | URI | -| | defa | -| | ults | -| | to | -| | the | -| | valu | -| | e | -| | of | -| | envi | -| | ronm | -| | ent | -| | vari | -| | able | -| | CDMS | -| | ROOT | -| | . | -| | ``us | -| | er`` | -| | is | -| | the | -| | user | -| | ID. | -| | If | -| | unsp | -| | ecif | -| | ied, | -| | an | -| | anon | -| | ymou | -| | s | -| | conn | -| | ecti | -| | on | -| | is | -| | made | -| | . | -| | ``pa | -| | sswo | -| | rd`` | -| | is | -| | the | -| | user | -| | pass | -| | word | -| | . | -| | A | -| | pass | -| | word | -| | is | -| | not | -| | requ | -| | ired | -| | for | -| | an | -| | anon | -| | ymou | -| | s | -| | conn | -| | ecti | -| | on | -+------+------+ - -Table 2.18 Database Methods - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
- -Type - -.. raw:: html - - - -Method - -.. raw:: html - - - -Definition - -.. raw:: html - -
- -None - -.. raw:: html - - - -close() - -.. raw:: html - - - -Close a database connection. - -.. raw:: html - -
- -List - -.. raw:: html - - - -listDatasets() - -.. raw:: html - - - -Return a list of the dataset IDs in this database. A dataset ID can be -passed to the open command. - -.. raw:: html - -
- -Dataset - -.. raw:: html - - - -open(dsetid, mode='r') - -.. raw:: html - - - -.. raw:: html - -

- -Open a dataset. - -.. raw:: html - -

- -.. raw:: html - -

- -dsetid is the string dataset identifier - -.. raw:: html - -

- -.. raw:: html - -

- -mode is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. - -.. raw:: html - -

- -.. raw:: html - -

- -openDataset is a synonym for open. - -.. raw:: html - -

- -.. raw:: html - -
- -SearchResult - -.. raw:: html - - - -.. raw:: html - -
-   searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)
-     
- -.. raw:: html - -
- -.. raw:: html - -

- -Search a CDMS database. - -.. raw:: html - -

- -.. raw:: html - -

- -filter is the string search filter. Simple filters have the form "tag = -value". Simple filters can be combined using logical operators '&', -'\|', '!' in prefix notation. - -.. raw:: html - -

- -.. raw:: html - -

- -Example: - -.. raw:: html - -

- -.. raw:: html - -

- -The filter '(&(objec)(id=cli))' finds all variables named "cli". - -.. raw:: html - -

- -.. raw:: html - -

- -A formal definition of search filters is provided in the following -section. - -.. raw:: html - -

- -.. raw:: html - -

- -tag restricts the search to objects with that tag ("dataset" \| -"variable" \| "database" \| "axis" \| "grid"). - -.. raw:: html - -

- -.. raw:: html - -

- -relbase is the relative name of the base object of the search. The -search is restricted to the base object and all objects below it in the -hierarchy. - -.. raw:: html - -

- -.. raw:: html - -

- -Example: - -.. raw:: html - -

- -.. raw:: html - -

- -To search only dataset 'ncep\_reanalysis\_mo', specify: - -.. raw:: html - -

- -.. raw:: html - -

- -relbase="dataset=ncep\_reanalysis\_mo" - -.. raw:: html - -

- -.. raw:: html - -

- -To search only variable 'ua' in 'ncep\_reanalysis\_mo', use: - -.. raw:: html - -

- -.. raw:: html - -

- -relbase="variable=ua,dataset=ncep\_reanalysis\_mo" - -.. raw:: html - -

- -.. raw:: html - -

- -If no base is specified, the entire database is searched. See the scope -argument also. - -.. raw:: html - -

- -.. raw:: html - -

- -scope is the search scope (Subtree \| Onelevel \| Base). - -.. raw:: html - -

- -.. raw:: html - -
    - -:: - -
  • Subtree searches the base object and its descendants.
  • -
  • Onelevel searches the base object and its immediate descendants.
  • -
  • Basesearches the base object alone.
  • - -.. raw:: html - -
- -.. raw:: html - -

- -The default is Subtree. - -.. raw:: html - -

- -.. raw:: html - -

- -attnames: list of attribute names. Restricts the attributes returned. If -None, all attributes are returned. Attributes 'id' and 'objectclass' are -always included in the list. - -.. raw:: html - -

- -.. raw:: html - -

- -timeout: integer number of seconds before timeout. The default is no -timeout. - -.. raw:: html - -

- -.. raw:: html - -
- -2.7.2 Searching a database -'''''''''''''''''''''''''' - -The ``searchFilter`` method is used to search a database. The result is -called a search result, and consists of a sequence of result entries. - -In its simplest form, ``searchFilter`` takes an argument consisting of a -string filter. The search returns a sequence of entries, corresponding -to those objects having an attribute which matches the filter. Simple -filters have the form (tag = value), where value can contain wildcards. -For example: - -{% highlight text %} (id = ncep\*) (project = AMIP2) {% endhighlight %} - -Simple filters can be combined with the logical operators '&', '\|', -'!'. For example, - -{% highlight text %} (&(id = bmrc\*)(project = AMIP2)) {% endhighlight -%} - -matches all objects with id starting with bmrc, and a project attribute -with value 'AMIP2'. - -Formally, search filters are strings defined as follows: - -{% highlight text %} filter ::= "(" filtercomp ")" - -filtercomp ::= "&" filterlist \| # and "\|" filterlist \| # or "!" -filterlist \| # not simple - -filterlist ::= filter \| filter filterlist simple ::= tag op value op -::= "=" \| # equality - -"~=" \| # approximate equality "<=" \| # lexicographically less than or -equal to ">=" # lexicographically greater than or equal to - -tag ::= string attribute name value ::= string attribute value, may -include '\*' as a wild card {% endhighlight %} - -Attribute names are defined in the chapter on "Climate Data Markup -Language (CDML)" on page 149. In addition, some special attributes are -defined for convenience: - -- ``category`` is either "experimental" or "observed" -- ``parentid`` is the ID of the parent dataset -- ``project`` is a project identifier, e.g., "AMIP2" -- ``objectclass`` is the list of tags associated with the object. - -The set of objects searched is called the search scope. The top object -in the hierarchy is the base object. By default, all objects in the -database are searched, that is, the database is the base object. If the -database is very large, this may result in an unnecessarily slow or -inefficient search. To remedy this the search scope can be limited in -several ways: - -- The base object can be changed. -- The scope can be limited to the base object and one level below, or - to just the base object. -- The search can be restricted to objects of a given class (dataset, - variable, etc.) -- The search can be restricted to return only a subset of the object - attributes -- The search can be restricted to the result of a previous search. -- A search result is accessed sequentially within a for loop: - -{% highlight python %} result = -db.searchFilter('(&(category=obs\ *)(id=ncep*))') for entry in result: -print entry.name {% endhighlight %} - -Search results can be narrowed using ``searchPredicate``. In the -following example, the result of one search is itself searched for all -variables defined on a 94x192 grid: - -{% highlight python %} >>> result = -db.searchFilter('parentid=ncep\*',tag="variable") >>> len(result) 65 >>> -result2 = result.searchPredicate(lambda x: - -x.getGrid().shape==(94,192)) >>> len(result2) 3 >>> for entry in -result2: print entry.name -variable=rluscs,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, - -:: - - o=LLNL, c=US - -variable=rlds,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, - -:: - - o=LLNL, c=US - -variable=rlus,dataset=ncep\_reanalysis\_mo,database=CDMS,ou=PCMDI, - -:: - - o=LLNL, c=US - -{% endhighlight %} - -Table 2.19 SearchResult Methods - - -+------+------+------+ -| Type | Meth | Defi | -| | od | niti | -| | | on | -+======+======+======+ -| Resu | ``[i | Retu | -| ltEn | ]`` | rn | -| try | | the | -| | | i-th | -| | | sear | -| | | ch | -| | | resu | -| | | lt. | -| | | Resu | -| | | lts | -| | | can | -| | | also | -| | | be | -| | | retu | -| | | rned | -| | | in a | -| | | for | -| | | loop | -| | | : | -| | | ``fo | -| | | r en | -| | | try | -| | | in d | -| | | b.se | -| | | arch | -| | | Resu | -| | | lt(t | -| | | ag=" | -| | | data | -| | | set" | -| | | ):`` | -+------+------+------+ -| Inte | ``le | Numb | -| ger | n()` | er | -| | ` | of | -| | | entr | -| | | ies | -| | | in | -| | | the | -| | | resu | -| | | lt. | -+------+------+------+ -| Sear | ``se | Refi | -| chRe | arch | ne | -| sult | Pred | a | -| | icat | sear | -| | e(pr | ch | -| | edic | resu | -| | ate, | lt, | -| | tag | with | -| | =Non | a | -| | e)`` | pred | -| | | icat | -| | | e | -| | | sear | -| | | ch. | -| | | ``pr | -| | | edic | -| | | ate` | -| | | ` | -| | | is a | -| | | func | -| | | tion | -| | | whic | -| | | h | -| | | take | -| | | s | -| | | a | -| | | sing | -| | | le | -| | | CDMS | -| | | obje | -| | | ct | -| | | and | -| | | retu | -| | | rns | -| | | true | -| | | (1) | -| | | if | -| | | the | -| | | obje | -| | | ct | -| | | sati | -| | | sfie | -| | | s | -| | | the | -| | | pred | -| | | icat | -| | | e, | -| | | 0 if | -| | | not. | -| | | ``ta | -| | | g`` | -| | | rest | -| | | rict | -| | | s | -| | | the | -| | | sear | -| | | ch | -| | | to | -| | | obje | -| | | cts | -| | | of | -| | | the | -| | | clas | -| | | s | -| | | deno | -| | | ted | -| | | by | -| | | the | -| | | tag. | -| | | **No | -| | | te** | -| | | : | -| | | In | -| | | the | -| | | curr | -| | | ent | -| | | impl | -| | | emen | -| | | tati | -| | | on, | -| | | ``se | -| | | arch | -| | | Pred | -| | | icat | -| | | e``\ | -| | | is | -| | | much | -| | | less | -| | | effi | -| | | cien | -| | | t | -| | | than | -| | | ``se | -| | | arch | -| | | Filt | -| | | er`` | -| | | . | -| | | For | -| | | best | -| | | perf | -| | | orma | -| | | nce, | -| | | use | -| | | ``se | -| | | arch | -| | | Filt | -| | | er`` | -| | | to | -| | | narr | -| | | ow | -| | | the | -| | | scop | -| | | e | -| | | of | -| | | the | -| | | sear | -| | | ch, | -| | | then | -| | | use | -| | | ``se | -| | | arch | -| | | Pred | -| | | icat | -| | | e`` | -| | | for | -| | | more | -| | | gene | -| | | ral | -| | | sear | -| | | ches | -| | | . | -+------+------+------+ - -A search result is a sequence of result entries. Each entry has a string -name, the name of the object in the database hierarchy, and an attribute -dictionary. An entry corresponds to an object found by the search, but -differs from the object, in that only the attributes requested are -associated with the entry. In general, there will be much more -information defined for the associated CDMS object, which is retrieved -with the ``getObject`` method. - -Table 2.20 ResultEntry Attributes - - -+------+------+------+ -| Type | Name | Desc | -| | | ript | -| | | ion | -+======+======+======+ -| Stri | ``na | The | -| ng | me`` | name | -| | | of | -| | | this | -| | | entr | -| | | y | -| | | in | -| | | the | -| | | data | -| | | base | -| | | . | -+------+------+------+ -| Dict | ``at | The | -| iona | trib | attr | -| ry | utes | ibut | -| | `` | es | -| | | retu | -| | | rned | -| | | from | -| | | the | -| | | sear | -| | | ch. | -| | | ``at | -| | | trib | -| | | utes | -| | | [key | -| | | ]`` | -| | | is a | -| | | list | -| | | of | -| | | all | -| | | stri | -| | | ng | -| | | valu | -| | | es | -| | | asso | -| | | ciat | -| | | ed | -| | | with | -| | | the | -| | | key | -+------+------+------+ - -Table 2.21 ResultEntry Methods - - -+------+------+------+ -| Type | Meth | Defi | -| | od | niti | -| | | on | -+======+======+======+ -| ``Cd | ``ge | Retu | -| msOb | tObj | rn | -| j`` | ect( | the | -| | )`` | CDMS | -| | | obje | -| | | ct | -| | | asso | -| | | ciat | -| | | ed | -| | | with | -| | | this | -| | | entr | -| | | y. | -| | | **No | -| | | te:* | -| | | * | -| | | For | -| | | many | -| | | sear | -| | | ch | -| | | appl | -| | | icat | -| | | ions | -| | | it | -| | | is | -| | | unne | -| | | cess | -| | | ary | -| | | to | -| | | acce | -| | | ss | -| | | the | -| | | asso | -| | | ciat | -| | | ed | -| | | CDMS | -| | | obje | -| | | ct. | -| | | For | -| | | best | -| | | perf | -| | | orma | -| | | nce | -| | | this | -| | | func | -| | | tion | -| | | shou | -| | | ld | -| | | be | -| | | used | -| | | only | -| | | when | -| | | nece | -| | | ssar | -| | | y, | -| | | for | -| | | exam | -| | | ple, | -| | | to | -| | | retr | -| | | ieve | -| | | data | -| | | asso | -| | | ciat | -| | | ed | -| | | with | -| | | a | -| | | vari | -| | | able | -| | | . | -+------+------+------+ - -2.7.3 Accessing data -'''''''''''''''''''' - -To access data via CDMS: - -1. Locate the dataset ID. This may involve searching the metadata. -2. Open the dataset, using the open method. -3. Reference the portion of the variable to be read. - -In the next example, a portion of variable 'ua' is read from dataset -'ncep\_reanalysis\_mo': - -{% highlight python %} dset = db.open('ncep\_reanalysis\_mo') ua = -dset.variables['ua'] data = ua[0,0] {% endhighlight %} - -2.7.4 Examples of database searches -''''''''''''''''''''''''''''''''''' - -In the following examples, db is the database opened with - -{% highlight python %} db = cdms.connect() {% endhighlight %} - -This defaults to the database defined in environment variable -``CDMSROOT``. - -**Example:** List all variables in dataset 'ncep\_reanalysis\_mo': - -{% highlight python %} for entry in db.searchFilter(filter = -"parentid=ncep\_reanalysis\_mo", tag = "variable"): print entry.name {% -endhighlight %} - -**Example:** Find all axes with bounds defined: - -{% highlight python %} for entry in -db.searchFilter(filter="bounds=\*",tag="axis"): print entry.name {% -endhighlight %} - -**Example:** Locate all GDT datasets: - -{% highlight python %} for entry in -db.searchFilter(filter="Conventions=GDT\*",tag="dataset"): print -entry.name {% endhighlight %} - -**Example:** Find all variables with missing time values, in observed -datasets: - -{% highlight python %} def missingTime(obj): time = obj.getTime() return -time.length != time.partition\_length - -result = db.searchFilter(filter="category=observed") for entry in -result.searchPredicate(missingTime): print entry.name {% endhighlight %} - -**Example:** Find all CMIP2 datasets having a variable with id "hfss": - -{% highlight python %} for entry in db.searchFilter(filter = -"(&(project=CMIP2)(id=hfss))", tag = "variable"): print -entry.getObject().parent.id {% endhighlight %} - -**Example:** Find all observed variables on 73x144 grids: - -{% highlight python %} result = db.searchFilter(category='obs\*') for -entry in result.searchPredicate(lambda x: -x.getGrid().shape==(73,144),tag="variable"): print entry.name {% -endhighlight %} - -**Example:** Find all observed variables with more than 1000 timepoints: - -{% highlight python %} result = db.searchFilter(category='obs\*') for -entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = -"variable"): print entry.name, len(entry.getObject().getTime()) {% -endhighlight %} - -**Example:** Find the total number of each type of object in the -database - -{% highlight python %} print -len(db.searchFilter(tag="database")),"database" print -len(db.searchFilter(tag="dataset")),"datasets" print -len(db.searchFilter(tag="variable")),"variables" print -len(db.searchFilter(tag="axis")),"axes" {% endhighlight %} - -2.8 Dataset -^^^^^^^^^^^ - -A Dataset is a virtual file. It consists of a metafile, in CDML/XML -representation, and one or more data files. - -As of CDMS V3, the legacy cuDataset interface is supported by Datasets. -See "cu Module" on page 180. - -Table 2.22 Dataset Internal Attributes - - -+------+------+------+ -| Type | Name | Desc | -| | | ript | -| | | ion | -+======+======+======+ -| Dict | ``at | Data | -| iona | trib | set | -| ry | utes | exte | -| | `` | rnal | -| | | attr | -| | | ibut | -| | | es. | -+------+------+------+ -| Dict | ``ax | Axes | -| iona | es`` | cont | -| ry | | aine | -| | | d | -| | | in | -| | | the | -| | | data | -| | | set. | -+------+------+------+ -| Stri | ``da | Path | -| ng | tapa | of | -| | th`` | data | -| | | file | -| | | s, | -| | | rela | -| | | tive | -| | | to | -| | | the | -| | | pare | -| | | nt | -| | | data | -| | | base | -| | | . | -| | | If | -| | | no | -| | | pare | -| | | nt, | -| | | the | -| | | data | -| | | path | -| | | is | -| | | abso | -| | | lute | -| | | . | -+------+------+------+ -| Dict | ``gr | Grid | -| iona | ids` | s | -| ry | ` | cont | -| | | aine | -| | | d | -| | | in | -| | | the | -| | | data | -| | | set. | -+------+------+------+ -| Stri | ``mo | Open | -| ng | de`` | mode | -| | | . | -+------+------+------+ -| Data | ``pa | Data | -| base | rent | base | -| | `` | whic | -| | | h | -| | | cont | -| | | ains | -| | | this | -| | | data | -| | | set. | -| | | If | -| | | the | -| | | data | -| | | set | -| | | is | -| | | not | -| | | part | -| | | of a | -| | | data | -| | | base | -| | | , | -| | | the | -| | | valu | -| | | e | -| | | is | -| | | ``No | -| | | ne`` | -| | | . | -+------+------+------+ -| Stri | ``ur | Unif | -| ng | i`` | orm | -| | | Reso | -| | | urce | -| | | Iden | -| | | tifi | -| | | er | -| | | of | -| | | this | -| | | data | -| | | set. | -+------+------+------+ -| Dict | ``va | Vari | -| iona | riab | able | -| ry | les` | s | -| | ` | cont | -| | | aine | -| | | d | -| | | in | -| | | the | -| | | data | -| | | set. | -+------+------+------+ -| Dict | ``xl | Exte | -| iona | inks | rnal | -| ry | `` | link | -| | | s | -| | | cont | -| | | aine | -| | | d | -| | | in | -| | | the | -| | | data | -| | | set. | -+------+------+------+ - -Table 2.23 Dataset Constructors - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| ``da | Open | -| tase | the | -| tobj | data | -| = c | set | -| dms. | spec | -| open | ifie | -| (Str | d | -| ing | by | -| uri, | the | -| Str | Univ | -| ing | ersa | -| mode | l | -| ='r' | Reso | -| )`` | urce | -| | Indi | -| | cato | -| | r, | -| | a | -| | CDML | -| | file | -| | . | -| | Retu | -| | rns | -| | a | -| | Data | -| | set | -| | obje | -| | ct. | -| | mode | -| | is | -| | one | -| | of | -| | the | -| | indi | -| | cato | -| | rs | -| | list | -| | ed | -| | in | -| | Tabl | -| | e | -| | 2.24 | -| | on | -| | page | -| | 70. | -| | ``op | -| | enDa | -| | tase | -| | t`` | -| | is a | -| | syno | -| | nym | -| | for | -| | ``op | -| | en`` | -+------+------+ - -Table 2.24 Open Modes - - -+--------+-----------------------------------------------------------------------+ -| Mode | Definition | -+========+=======================================================================+ -| 'r' | read-only | -+--------+-----------------------------------------------------------------------+ -| 'r+' | read-write | -+--------+-----------------------------------------------------------------------+ -| 'a' | read-write. Open the file if it exists, otherwise create a new file | -+--------+-----------------------------------------------------------------------+ -| 'w' | Create a new file, read-write | -+--------+-----------------------------------------------------------------------+ - -Table 2.25 Dataset Methods - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -.. raw:: html - - - -.. raw:: html - -
TypeMethodDefinition
Transient-Variabledatasetobj(varname, selector) - Calling a Dataset object as a function reads the region of data defined by the - selector. The result is a transient variable, unless raw = 1 is - specified. See "Selectors" on page 103. - -

Example: The following reads data for variable 'prc', year 1980:

-
-
-f = cdms.open('test.xml') x = f('prc', time=('1980-1','1981-1'))
-
-.. raw:: html
-
-   
- -:: - -
Variable, Axis, or Griddatasetobj['id'] -

The square bracket operator applied to a dataset gets the persistent - variable, axis or grid object having the string identifier. This does not read - the data for a variable. Returns None if not found.

- -

Example:

-
-
-f = cdms.open('sample.xml') v = f['prc']
-
-.. raw:: html
-
-   
- -:: - -

gets the persistent variable v, equivalent to v = - f.variables['prc'].

- -

Example:

- -

t = f['time']
- gets the axis named 'time', equivalent to t = f.axes['time']

-
None
-
close()Close the dataset.
-

RectGrid

-
-

createRectGrid(id, lat, lon, order, type="generic", - mask=None)

-
-

Create a RectGrid in the dataset. This is not a persistent object: the - order, type, and mask are not written to the dataset. However, the grid may be - used for regridding operations.

- -

lat is a latitude axis in the dataset.

- -

lon is a longitude axis in the dataset.

- -

order is a string with value "yx" (the first grid dimension is - latitude) or "xy" (the first grid dimension is longitude).

- -

type is one of 'gaussian','uniform','equalarea',or - 'generic'

- -

If specified, mask is a two-dimensional, logical Numeric array - (all values are zero or one) with the same shape as the grid.

-
-

Axis

-
-

getAxis(id)

-
-

Get an axis object from the file or dataset.

- -

id is the string axis identifier.

-
-

Grid

-
-

getGrid(id)

-
-

Get a grid object from a file or dataset.

- -

id is the string grid identifier.

-
-

List

-
-

getPaths()

-
-

Get a sorted list of pathnames of datafiles which comprise the dataset. This - does not include the XML metafile path, which is stored in the .uri - attribute.

-
-

Variable

-
-

getVariable(id)

-
-

Get a variable object from a file or dataset.

- -

id is the string variable identifier.

-
CurveGrid or GenericGridreadScripGrid(self, whichGrid='destination', check-or Generic-Grid=1) -

Read a curvilinear or generic grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remapping file.

- -

If a mapping file, whichGrid chooses the grid to read, either "source" or "destination".

- -

If checkGrid is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.

-
None

sync()Write any pending changes to the dataset.
- -2.9 MV module -^^^^^^^^^^^^^ - -The fundamental CDMS data object is the variable. A variable is -comprised of: - -- a masked data array, as defined in the NumPy MA module. -- a domain: an ordered list of axes and/or grids. -- an attribute dictionary. - -The MV module is a work-alike replacement for the MA module, that -carries along the domain and attribute information where appropriate. MV -provides the same set of functions as MA. However, MV functions generate -transient variables as results. Often this simplifies scripts that -perform computation. MA is part of the Python Numeric package, -documented at http://www.numpy.org. - -MV can be imported with the command: - -{% highlight text %} import MV {% endhighlight %} - -The command - -{% highlight text %} from MV import \* {% endhighlight %} - -allows use of MV commands without any prefix. - -Table 2.26 on page 75 lists the constructors in MV. All functions return -a transient variable. In most cases the keywords axes, attributes, and -id are available. axes is a list of axis objects which specifies the -domain of the variable. attributes is a dictionary. id is a special -attribute string that serves as the identifier of the variable, and -should not contain blanks or non-printing characters. It is used when -the variable is plotted or written to a file. Since the id is just an -attribute, it can also be set like any attribute: - -{% highlight text %} var.id = 'temperature' {% endhighlight %} - -For completeness MV provides access to all the MA functions. The -functions not listed in the following tables are identical to the -corresponding MA function: ``allclose``, ``allequal``, -``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, -``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, -``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, -``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, -``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, -``putmask``, ``rank``, ``ravel``, ``set_fill_value``, -``set_print_limit``, ``shape``, ``size``. See the documentation at -http://numpy.sourceforge.net for a description of these functions. - -Table 2.26 Variable Constructors in module MV - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| ``ar | Just | -| rayr | like | -| ange | ``MA | -| (sta | .ara | -| rt, | nge( | -| stop | )`` | -| =Non | exce | -| e, s | pt | -| tep= | it | -| 1, t | retu | -| ypec | rns | -| ode= | a | -| None | vari | -| , ax | able | -| is=N | whos | -| one, | e | -| att | type | -| ribu | can | -| tes= | be | -| None | spec | -| , id | fied | -| =Non | by | -| e)`` | the | -| | keyw | -| | ord | -| | argu | -| | ment | -| | type | -| | code | -| | . | -| | The | -| | axis | -| | , | -| | attr | -| | ibut | -| | e | -| | dict | -| | iona | -| | ry, | -| | and | -| | stri | -| | ng | -| | iden | -| | tifi | -| | er | -| | of | -| | the | -| | resu | -| | lt | -| | vari | -| | able | -| | may | -| | be | -| | spec | -| | ifie | -| | d. | -| | *Syn | -| | onym | -| | :* | -| | ``ar | -| | ange | -| | `` | -+------+------+ -| ``ma | Same | -| sked | as | -| _arr | MA.m | -| ay(a | aske | -| , ma | d\_a | -| sk=N | rray | -| one, | but | -| fil | crea | -| l_va | tes | -| lue= | a | -| None | vari | -| , ax | able | -| es=N | inst | -| one, | ead. | -| att | If | -| ribu | no | -| tes= | axes | -| None | are | -| , id | spec | -| =Non | ifie | -| e)`` | d, | -| | the | -| | resu | -| | lt | -| | has | -| | defa | -| | ult | -| | axes | -| | , | -| | othe | -| | rwis | -| | e | -| | axes | -| | is a | -| | list | -| | of | -| | axis | -| | obje | -| | cts | -| | matc | -| | hing | -| | a.sh | -| | ape. | -+------+------+ -| ``ma | Crea | -| sked | te | -| _obj | vari | -| ect( | able | -| data | mask | -| , va | ed | -| lue, | wher | -| cop | e | -| y=1, | exac | -| sav | tly | -| espa | data | -| ce=0 | equa | -| , ax | l | -| es=N | to | -| one, | valu | -| att | e. | -| ribu | Crea | -| tes= | te | -| None | the | -| , id | vari | -| =Non | able | -| e)`` | with | -| | the | -| | give | -| | n | -| | list | -| | of | -| | axis | -| | obje | -| | cts, | -| | attr | -| | ibut | -| | e | -| | dict | -| | iona | -| | ry, | -| | and | -| | stri | -| | ng | -| | id. | -+------+------+ -| ``ma | Cons | -| sked | truc | -| _val | ts | -| ues( | a | -| data | vari | -| , va | able | -| lue, | with | -| rto | the | -| l=1e | give | -| -05, | n | -| ato | list | -| l=1e | of | -| -08, | axes | -| cop | and | -| y=1, | attr | -| sav | ibut | -| espa | e | -| ce=0 | dict | -| , ax | iona | -| es=N | ry, | -| one, | whos | -| att | e | -| ribu | mask | -| tes= | is | -| None | set | -| , id | at | -| =Non | thos | -| e)`` | e | -| | plac | -| | es | -| | wher | -| | e | -| | ``ab | -| | s(da | -| | ta - | -| | val | -| | ue) | -| | < | -| | ato | -| | l + | -| | rtol | -| | * a | -| | bs(d | -| | ata) | -| | ``. | -| | This | -| | is a | -| | care | -| | ful | -| | way | -| | of | -| | sayi | -| | ng | -| | that | -| | thos | -| | e | -| | elem | -| | ents | -| | of | -| | the | -| | data | -| | that | -| | have | -| | valu | -| | e | -| | = | -| | valu | -| | e | -| | (to | -| | with | -| | in | -| | a | -| | tole | -| | ranc | -| | e) | -| | are | -| | to | -| | be | -| | trea | -| | ted | -| | as | -| | inva | -| | lid. | -| | If | -| | data | -| | is | -| | not | -| | of a | -| | floa | -| | ting | -| | poin | -| | t | -| | type | -| | , | -| | call | -| | s | -| | mask | -| | ed\_ | -| | obje | -| | ct | -| | inst | -| | ead. | -+------+------+ -| ``on | retu | -| es(s | rn | -| hape | an | -| , ty | arra | -| peco | y | -| de=' | of | -| l', | all | -| save | ones | -| spac | of | -| e=0, | the | -| axe | give | -| s=no | n | -| ne, | leng | -| attr | th | -| ibut | or | -| es=n | shap | -| one, | e. | -| id= | | -| none | | -| )`` | | -+------+------+ -| ``re | copy | -| shap | of a | -| e(a, | with | -| new | a | -| shap | new | -| e, a | shap | -| xes= | e. | -| none | | -| , at | | -| trib | | -| utes | | -| =non | | -| e, i | | -| d=no | | -| ne)` | | -| ` | | -+------+------+ -| ``re | retu | -| size | rn | -| (a, | a | -| new_ | new | -| shap | arra | -| e, a | y | -| xes= | with | -| none | the | -| , at | spec | -| trib | ifie | -| utes | d | -| =non | shap | -| e, i | e. | -| d=no | the | -| ne)` | orig | -| ` | inal | -| | arra | -| | ys | -| | tota | -| | l | -| | size | -| | can | -| | be | -| | any | -| | size | -| | . | -+------+------+ -| ``ze | an | -| ros( | arra | -| shap | y | -| e, t | of | -| ypec | all | -| ode= | zero | -| 'l', | s | -| sav | of | -| espa | the | -| ce=0 | give | -| , ax | n | -| es=n | leng | -| one, | th | -| att | or | -| ribu | shap | -| tes= | e | -| none | | -| , id | | -| =non | | -| e)`` | | -+------+------+ - -The following table describes the MV non-constructor functions. with the -exception of argsort, all functions return a transient variable. - -Table 2.27 MV functions - - -+------+------+ -| Func | Desc | -| tion | ript | -| | ion | -+======+======+ -| ``ar | Retu | -| gsor | rn | -| t(x, | a | -| axi | Nume | -| s=-1 | ric | -| , fi | arra | -| ll_v | y | -| alue | of | -| =Non | indi | -| e)`` | ces | -| | for | -| | sort | -| | ing | -| | alon | -| | g | -| | a | -| | give | -| | n | -| | axis | -| | . | -+------+------+ -| ``as | Same | -| arra | as | -| y(da | ``cd | -| ta, | ms.c | -| type | reat | -| code | eVar | -| =Non | iabl | -| e)`` | e(da | -| | ta, | -| | type | -| | code | -| | , co | -| | py=0 | -| | )``. | -| | This | -| | is a | -| | shor | -| | t | -| | way | -| | of | -| | ensu | -| | ring | -| | that | -| | some | -| | thin | -| | g | -| | is | -| | an | -| | inst | -| | ance | -| | of a | -| | vari | -| | able | -| | of a | -| | give | -| | n | -| | type | -| | befo | -| | re | -| | proc | -| | eedi | -| | ng, | -| | as | -| | in | -| | ``da | -| | ta = | -| | asa | -| | rray | -| | (dat | -| | a)`` | -| | . | -| | Also | -| | see | -| | the | -| | vari | -| | able | -| | ``as | -| | type | -| | ()`` | -| | func | -| | tion | -| | . | -+------+------+ -| ``av | Comp | -| erag | utes | -| e(a, | the | -| axi | aver | -| s=0, | age | -| wei | valu | -| ghts | e | -| =Non | of | -| e)`` | the | -| | non- | -| | mask | -| | ed | -| | elem | -| | ents | -| | of x | -| | alon | -| | g | -| | the | -| | sele | -| | cted | -| | axis | -| | . | -| | If | -| | weig | -| | hts | -| | is | -| | give | -| | n, | -| | it | -| | must | -| | matc | -| | h | -| | the | -| | size | -| | and | -| | shap | -| | e | -| | of | -| | x, | -| | and | -| | the | -| | valu | -| | e | -| | retu | -| | rned | -| | is: | -| | ``su | -| | m(a* | -| | weig | -| | hts) | -| | /sum | -| | (wei | -| | ghts | -| | )`` | -| | In | -| | comp | -| | utin | -| | g | -| | thes | -| | e | -| | sums | -| | , | -| | elem | -| | ents | -| | that | -| | corr | -| | espo | -| | nd | -| | to | -| | thos | -| | e | -| | that | -| | are | -| | mask | -| | ed | -| | in x | -| | or | -| | weig | -| | hts | -| | are | -| | igno | -| | red. | -+------+------+ -| ``ch | Has | -| oose | a | -| (con | resu | -| diti | lt | -| on, | shap | -| t)`` | ed | -| | like | -| | arra | -| | y | -| | cond | -| | itio | -| | n. | -| | ``t` | -| | ` | -| | must | -| | be a | -| | tupl | -| | e | -| | of | -| | two | -| | arra | -| | ys | -| | ``t1 | -| | `` | -| | and | -| | ``t2 | -| | ``. | -| | Each | -| | elem | -| | ent | -| | of | -| | the | -| | resu | -| | lt | -| | is | -| | the | -| | corr | -| | espo | -| | ndin | -| | g | -| | elem | -| | ent | -| | of | -| | ``t1 | -| | ``\ | -| | wher | -| | e | -| | ``co | -| | ndit | -| | ion` | -| | ` | -| | is | -| | true | -| | , | -| | and | -| | the | -| | corr | -| | espo | -| | ndin | -| | g | -| | elem | -| | ent | -| | of | -| | ``t2 | -| | `` | -| | wher | -| | e | -| | ``co | -| | ndit | -| | ion` | -| | ` | -| | is | -| | fals | -| | e. | -| | The | -| | resu | -| | lt | -| | is | -| | mask | -| | ed | -| | wher | -| | e | -| | ``co | -| | ndit | -| | ion` | -| | ` | -| | is | -| | mask | -| | ed | -| | or | -| | wher | -| | e | -| | the | -| | sele | -| | cted | -| | elem | -| | ent | -| | is | -| | mask | -| | ed. | -+------+------+ -| ``co | Conc | -| ncat | aten | -| enat | ate | -| e(ar | the | -| rays | arra | -| , ax | ys | -| is=0 | alon | -| , ax | g | -| isid | the | -| =Non | give | -| e, a | n | -| xisa | axis | -| ttri | . | -| bute | Give | -| s=No | the | -| ne)` | exte | -| ` | nded | -| | axis | -| | the | -| | id | -| | and | -| | attr | -| | ibut | -| | es | -| | prov | -| | ided | -| | - by | -| | defa | -| | ult, | -| | thos | -| | e | -| | of | -| | the | -| | firs | -| | t | -| | arra | -| | y. | -+------+------+ -| ``co | Coun | -| unt( | t | -| a, a | of | -| xis= | the | -| None | non- | -| )`` | mask | -| | ed | -| | elem | -| | ents | -| | in | -| | ``a` | -| | `, | -| | or | -| | alon | -| | g | -| | a | -| | cert | -| | ain | -| | axis | -| | . | -+------+------+ -| ``is | Retu | -| Mask | rn | -| edVa | true | -| riab | if | -| le(x | ``x` | -| )`` | ` | -| | is | -| | an | -| | inst | -| | ance | -| | of a | -| | vari | -| | able | -| | . | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _equ | mask | -| al(x | ed | -| , va | wher | -| lue) | e | -| `` | ``x` | -| | ` | -| | equa | -| | ls | -| | the | -| | scal | -| | ar | -| | valu | -| | e. | -| | For | -| | floa | -| | ting | -| | poin | -| | t | -| | valu | -| | es | -| | cons | -| | ider | -| | ``ma | -| | sked | -| | _val | -| | ues( | -| | x, v | -| | alue | -| | )`` | -| | inst | -| | ead. | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _gre | mask | -| ater | ed | -| (x, | wher | -| valu | e | -| e)`` | ``x | -| | > va | -| | lue` | -| | ` | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _gre | mask | -| ater | ed | -| _equ | wher | -| al(x | e | -| , va | ``x | -| lue) | >= v | -| `` | alue | -| | `` | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _les | mask | -| s(x, | ed | -| val | wher | -| ue)` | e | -| ` | ``x | -| | < | -| | val | -| | ue`` | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _les | mask | -| s_eq | ed | -| ual( | wher | -| x, v | e | -| alue | ``x | -| )`` | ≤ | -| | val | -| | ue`` | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _not | mask | -| _equ | ed | -| al(x | wher | -| , va | e | -| lue) | ``x | -| `` | != v | -| | alue | -| | `` | -+------+------+ -| ``ma | ``x` | -| sked | ` | -| _out | with | -| side | mask | -| (x, | of | -| v1, | all | -| v2)` | valu | -| ` | es | -| | of | -| | ``x` | -| | ` | -| | that | -| | are | -| | outs | -| | ide | -| | ``[v | -| | 1,v2 | -| | ]`` | -+------+------+ -| ``ma | Retu | -| sked | rn | -| _whe | ``x` | -| re(c | ` | -| ondi | as a | -| tion | vari | -| , x, | able | -| cop | mask | -| y=1) | ed | -| `` | wher | -| | e | -| | cond | -| | itio | -| | n | -| | is | -| | true | -| | . | -| | Also | -| | mask | -| | ed | -| | wher | -| | e | -| | ``x` | -| | ` | -| | or | -| | ``co | -| | ndit | -| | ion` | -| | ` | -| | mask | -| | ed. | -| | ``co | -| | ndit | -| | ion` | -| | ` | -| | is a | -| | mask | -| | ed | -| | arra | -| | y | -| | havi | -| | ng | -| | the | -| | same | -| | shap | -| | e | -| | as | -| | ``x` | -| | `. | -+------+------+ -| ``ma | Comp | -| ximu | ute | -| m(a, | the | -| b=N | maxi | -| one) | mum | -| `` | vali | -| | d | -| | valu | -| | es | -| | of | -| | ``x` | -| | ` | -| | if | -| | ``y` | -| | ` | -| | is | -| | ``No | -| | ne`` | -| | ; | -| | with | -| | two | -| | argu | -| | ment | -| | s, | -| | retu | -| | rn | -| | the | -| | elem | -| | ent- | -| | wise | -| | larg | -| | er | -| | of | -| | vali | -| | d | -| | valu | -| | es, | -| | and | -| | mask | -| | the | -| | resu | -| | lt | -| | wher | -| | e | -| | eith | -| | er | -| | ``x` | -| | ` | -| | or | -| | ``y` | -| | ` | -| | is | -| | mask | -| | ed. | -+------+------+ -| ``mi | Comp | -| nimu | ute | -| m(a, | the | -| b=N | mini | -| one) | mum | -| `` | vali | -| | d | -| | valu | -| | es | -| | of | -| | ``x` | -| | ` | -| | if | -| | ``y` | -| | ` | -| | is | -| | None | -| | ; | -| | with | -| | two | -| | argu | -| | ment | -| | s, | -| | retu | -| | rn | -| | the | -| | elem | -| | ent- | -| | wise | -| | smal | -| | ler | -| | of | -| | vali | -| | d | -| | valu | -| | es, | -| | and | -| | mask | -| | the | -| | resu | -| | lt | -| | wher | -| | e | -| | eith | -| | er | -| | ``x` | -| | ` | -| | or | -| | ``y` | -| | ` | -| | is | -| | mask | -| | ed. | -+------+------+ -| ``ou | Retu | -| terp | rn | -| rodu | a | -| ct(a | vari | -| , b) | able | -| `` | such | -| | that | -| | ``re | -| | sult | -| | [i, | -| | j] = | -| | a[i | -| | ] * | -| | b[j] | -| | ``. | -| | The | -| | resu | -| | lt | -| | will | -| | be | -| | mask | -| | ed | -| | wher | -| | e | -| | ``a[ | -| | i]`` | -| | or | -| | ``b[ | -| | j]`` | -| | is | -| | mask | -| | ed. | -+------+------+ -| ``po | ``a* | -| wer( | *b`` | -| a, b | | -| )`` | | -+------+------+ -| ``pr | Prod | -| oduc | uct | -| t(a, | of | -| axi | elem | -| s=0, | ents | -| fil | alon | -| l_va | g | -| lue= | axis | -| 1)`` | usin | -| | g | -| | ``fi | -| | ll_v | -| | alue | -| | `` | -| | for | -| | miss | -| | ing | -| | elem | -| | ents | -| | . | -+------+------+ -| ``re | Retu | -| peat | rn | -| (ar, | ``ar | -| rep | `` | -| eats | repe | -| , ax | ated | -| is=0 | ``re | -| )`` | peat | -| | s`` | -| | time | -| | s | -| | alon | -| | g | -| | ``ax | -| | is`` | -| | . | -| | ``re | -| | peat | -| | s`` | -| | is a | -| | sequ | -| | ence | -| | of | -| | leng | -| | th | -| | ``ar | -| | .sha | -| | pe[a | -| | xis] | -| | `` | -| | tell | -| | ing | -| | how | -| | many | -| | time | -| | s | -| | to | -| | repe | -| | at | -| | each | -| | elem | -| | ent. | -+------+------+ -| ``se | Set | -| t_de | the | -| faul | defa | -| t_fi | ult | -| ll_v | fill | -| alue | valu | -| (val | e | -| ue_t | for | -| ype, | ``va | -| val | lue_ | -| ue)` | type | -| ` | `` | -| | to | -| | ``va | -| | lue` | -| | `. | -| | ``va | -| | lue_ | -| | type | -| | `` | -| | is a | -| | stri | -| | ng: | -| | 'rea | -| | l',' | -| | comp | -| | lex' | -| | ,'ch | -| | arac | -| | ter' | -| | ,'in | -| | tege | -| | r',o | -| | r | -| | 'obj | -| | ect' | -| | . | -| | ``va | -| | lue` | -| | ` | -| | shou | -| | ld | -| | be a | -| | scal | -| | ar | -| | or | -| | sing | -| | le-e | -| | leme | -| | nt | -| | arra | -| | y. | -+------+------+ -| ``so | Sort | -| rt(a | arra | -| r, a | y | -| xis= | ``ar | -| -1)` | `` | -| ` | elem | -| | entw | -| | ise | -| | alon | -| | g | -| | the | -| | spec | -| | ifie | -| | d | -| | axis | -| | . | -| | The | -| | corr | -| | espo | -| | ndin | -| | g | -| | axis | -| | in | -| | the | -| | resu | -| | lt | -| | has | -| | dumm | -| | y | -| | valu | -| | es. | -+------+------+ -| ``su | Sum | -| m(a, | of | -| axi | elem | -| s=0, | ents | -| fil | alon | -| l_va | g | -| lue= | a | -| 0)`` | cert | -| | ain | -| | axis | -| | usin | -| | g | -| | ``fi | -| | ll_v | -| | alue | -| | `` | -| | for | -| | miss | -| | ing. | -+------+------+ -| ``ta | Retu | -| ke(a | rn | -| , in | a | -| dice | sele | -| s, a | ctio | -| xis= | n | -| 0)`` | of | -| | item | -| | s | -| | from | -| | ``a` | -| | `. | -| | See | -| | the | -| | docu | -| | ment | -| | atio | -| | n | -| | in | -| | the | -| | Nume | -| | ric | -| | manu | -| | al. | -+------+------+ -| ``tr | Perf | -| ansp | orm | -| ose( | a | -| ar, | reor | -| axes | deri | -| =Non | ng | -| e)`` | of | -| | the | -| | axes | -| | of | -| | arra | -| | y | -| | ar | -| | depe | -| | ndin | -| | g | -| | on | -| | the | -| | tupl | -| | e | -| | of | -| | indi | -| | ces | -| | axes | -| | ; | -| | the | -| | defa | -| | ult | -| | is | -| | to | -| | reve | -| | rse | -| | the | -| | orde | -| | r | -| | of | -| | the | -| | axes | -| | . | -+------+------+ -| ``wh | ``x` | -| ere( | ` | -| cond | wher | -| itio | e | -| n, x | ``co | -| , y) | ndit | -| `` | ion` | -| | ` | -| | is | -| | true | -| | , | -| | ``y` | -| | ` | -| | othe | -| | rwis | -| | e | -+------+------+ - -2.10 HorizontalGrid -^^^^^^^^^^^^^^^^^^^ - -A HorizontalGrid represents a latitude-longitude coordinate system. In -addition, it optionally describes how lat-lon space is partitioned into -cells. Specifically, a HorizontalGrid: - -- consists of a latitude and longitude coordinate axis. -- may have associated boundary arrays describing the grid cell - boundaries, -- may optionally have an associated logical mask. - -CDMS supports several types of HorizontalGrids: - -Table 2.28 - - -+------+------+ -| Grid | Defi | -| Type | niti | -| | on | -+======+======+ -| ``Re | Asso | -| ctGr | ciat | -| id`` | ed | -| | lati | -| | tude | -| | an | -| | long | -| | itud | -| | e | -| | are | -| | 1-D | -| | axes | -| | , | -| | with | -| | stri | -| | ctly | -| | mono | -| | toni | -| | c | -| | valu | -| | es. | -+------+------+ -| ``Cu | Lati | -| rveG | tude | -| rid` | and | -| ` | long | -| | itud | -| | e | -| | are | -| | 2-D | -| | coor | -| | dina | -| | te | -| | axes | -| | (Axi | -| | s2D) | -| | . | -+------+------+ -| ``Ge | Lati | -| neri | tude | -| cGri | and | -| d`` | long | -| | itud | -| | e | -| | are | -| | 1-D | -| | auxi | -| | liar | -| | y | -| | coor | -| | dina | -| | te | -| | axis | -| | (Aux | -| | Axis | -| | 1D) | -+------+------+ - -Table 2.29 HorizontalGrid Internal Attribute - - -+-----------------------+------------------+------------------------------------------------+ -| Type | Name | Definition | -+=======================+==================+================================================+ -| Dictionary | ``attributes`` | External attribute dictionary. | -+-----------------------+------------------+------------------------------------------------+ -| String | ``id`` | The grid identifier. | -+-----------------------+------------------+------------------------------------------------+ -| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | -+-----------------------+------------------+------------------------------------------------+ -| Tuple | ``shape`` | The shape of the grid, a 2-tuple | -+-----------------------+------------------+------------------------------------------------+ - -Table 2.31 on page 82 describes the methods that apply to all types of -HorizontalGrids. Table 2.32 on page 86 describes the additional methods -that are unique to RectGrids. - -Table 2.30 RectGrid Constructors - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| ``cd | Crea | -| ms.c | te | -| reat | a | -| eRec | grid | -| tGri | not | -| d(la | asso | -| t, l | ciat | -| on, | ed | -| orde | with | -| r, t | a | -| ype= | file | -| "gen | or | -| eric | data | -| ", m | set. | -| ask= | See | -| None | Tabl | -| )`` | e | -| | 2.2 | -| | on | -| | page | -| | 33. | -+------+------+ -| ``Cd | Crea | -| msFi | te | -| le.c | a | -| reat | grid | -| eRec | asso | -| tGri | ciat | -| d(id | ed | -| , la | with | -| t, l | a | -| on, | file | -| orde | . | -| r, t | See | -| ype= | Tabl | -| "gen | e | -| eric | 2.14 | -| ", m | on | -| ask= | page | -| None | 53. | -| )`` | | -+------+------+ -| ``Da | Crea | -| tase | te | -| t.cr | a | -| eate | grid | -| Rect | asso | -| Grid | ciat | -| (id, | ed | -| lat | with | -| , lo | a | -| n, o | data | -| rder | set. | -| , ty | See | -| pe=" | Tabl | -| gene | e | -| ric" | 2.25 | -| , ma | on | -| sk=N | page | -| one) | 71. | -| `` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eGau | 2.2 | -| ssia | on | -| nGri | page | -| d(nl | 33. | -| ats, | | -| xor | | -| igin | | -| =0.0 | | -| , or | | -| der= | | -| "yx" | | -| )`` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eGen | 2.2 | -| eric | on | -| Grid | page | -| (lat | 18. | -| Arra | | -| y, l | | -| onAr | | -| ray, | | -| lat | | -| Boun | | -| ds=N | | -| one, | | -| lon | | -| Boun | | -| ds=N | | -| one, | | -| ord | | -| er=" | | -| yx", | | -| mas | | -| k=No | | -| ne)` | | -| ` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eGlo | 2.2 | -| balM | on | -| eanG | page | -| rid( | 18. | -| grid | | -| )`` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eRec | 2.2 | -| tGri | on | -| d(la | page | -| t, l | 18. | -| on, | | -| orde | | -| r, t | | -| ype= | | -| "gen | | -| eric | | -| ", m | | -| ask= | | -| None | | -| )`` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eUni | 2.2 | -| form | on | -| Grid | page | -| (sta | 18. | -| rtLa | | -| t, n | | -| lat, | | -| del | | -| taLa | | -| t, s | | -| tart | | -| Lon, | | -| nlo | | -| n, d | | -| elta | | -| Lon, | | -| ord | | -| er=" | | -| yx", | | -| mas | | -| k=No | | -| ne)` | | -| ` | | -+------+------+ -| ``cd | See | -| ms.c | Tabl | -| reat | e | -| eZon | 2.2 | -| alGr | on | -| id(g | page | -| rid) | 18 | -| `` | | -+------+------+ - -Table 2.31 HorizontalGrid Methods - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- search for metadata +- access data +- provide authentication and access control for data and metadata - - +The figure below illustrates several important points: - - +- Each object in the database has a relative name of the form tag=id. + The id of an object is unique with respect to all objects contained + in the parent. - +- The name of the object consists of its relative name followed by the + relative name(s) of its antecedent objects, up to and including the + database name. In the figure below, one of the variables has name + ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. - - +- Subordinate objects are thought of as being contained in the parent. + In this example, the database ‘CDMS’ contains two datasets, each of + which contain several variables. - - +|Diagram 1| - +Figure 1 - - + ``result = db.searchFilter(relbase="dataset=ncep_reanalysis")`` - - +#. Refine the search results if necessary. The result of a search can be + narrowed with the searchPredicate method. +#. Process the results. A search result consists of a sequence of + entries. Each entry has a name, the name of the CDMS object, and an + attribute dictionary, consisting of the attributes located by the + search: - + `` for entry in result: print entry.name, entry.attributes`` - - +#. Access the data. The CDMS object associated with an entry is obtained + from the getObject method: - - + ``obj = entry.getObject()`` - + If the id of a dataset is known, the dataset can be opened directly + with the open method: - - + ``dset = db.open("ncep_reanalysis_mo")`` -.. raw:: html +#. Close the database connection: - + ``db.close()`` -.. raw:: html -
TypeMethodDescription
-

Horizontal-Grid

-
clone() -

Return a transient copy of the grid.

-
AxisgetAxis(Integer n) -

Get the n-th axis.n is either 0 or 1.

-
TuplegetBounds() -

Get the grid boundary arrays.

- -

Returns a tuple (latitudeArray, longitudeArray), where - latitudeArray is a Numeric array of latitude bounds, and similarly for - longitudeArray.The shape of latitudeArray and longitudeArray depend on the type - of grid:

- -
    -
  • for rectangular grids with shape (nlat, nlon), the boundary arrays have - shape (nlat,2) and (nlon,2).
  • - -
  • for curvilinear grids with shape (nx, ny), the boundary arrays each have - shape (nx, ny, 4).
  • - -
  • for generic grids with shape (ncell,), the boundary arrays each have - shape (ncell, nvert) where nvert is the maximum number of vertices per - cell.
  • -
- -

For rectilinear grids: If no boundary arrays are explicitly defined (in the - file or dataset), the result depends on the auto- Bounds mode (see - cdms.setAutoBounds) and the grid classification mode (see - cdms.setClassifyGrids). By default, autoBounds mode is enabled, in - which case the boundary arrays are generated based on the type of grid. If - disabled, the return value is (None,None).For rectilinear grids: The grid - classification mode specifies how the grid type is to be determined. By - default, the grid type (Gaussian, uniform, etc.) is determined by calling - grid.classifyInFamily. If the mode is 'off' - grid.getType is used instead.

-
AxisgetLatitude() -

Get the latitude axis of this grid.

-
AxisgetLongitude() -

Get the latitude axis of this grid.

-
AxisgetMask() -

Get the mask array of this grid, if any.Returns a 2-D Numeric array, having - the same shape as the grid. If the mask is not explicitly defined, the return - value is None.

-
AxisgetMesh(self, transpose=None) -

Generate a mesh array for the meshfill graphics method.If transpose is - defined to a tuple, say (1,0), first transpose latbounds and lonbounds - according to the tuple, in this case (1,0,2).

-
NonesetBounds(latBounds, lonBounds, persistent=0) -

Set the grid boundaries.latBounds is a NumPy array of shape - (n,2), such that the boundaries of the kth axis value are - [latBounds[k,0],latBounds[k,1] ]. lonBounds is - defined similarly for the longitude array. Note: By default, the - boundaries are not written to the file or dataset containing the grid (if any). - This allows bounds to be set on read-only files, for regridding. If the - optional argument persistent is set to 1, the boundary array is - written to the file.

-
NonesetMask(mask, persistent=0) -

Set the grid mask. If persistent == 1, the mask values are - written to the associated file, if any. Otherwise, the mask is associated with - the grid, but no I/O is generated. mask is a two-dimensional, - Boolean-valued Numeric array, having the same shape as the grid.

-
Horizontal-GridsubGridRegion(latInterval, lonInterval) -

Create a new grid corresponding to the coordinate region defined by - latInterval, lonInterval.

- -

latInterval and lonInterval are the coordinate - intervals for latitude and longitude, respectively.

-

Each interval is a tuple having one of the forms:

- -
    -
  • (x,y)
  • +2.7.1 Overview -
  • (x,y,indicator)
  • +To access a database: -
  • (x,y,indicator,cycle)
  • +#. Open a connection. The connect method opens a database connection. + connect takes a database URI and returns a database object: + ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` +#. Search the database, locating one or more datasets, variables, and/or + other objects. -
  • None
  • -
+ The database searchFilter method searches the database. A single + database connection may be used for an arbitrary number of searches. -

where x and y are coordinates indicating the - interval [x,y), and:

+ **Example**: Find all observed datasets -

indicator is a two-character string, where the - first character is 'c' if the interval is closed on the left, 'o' if open, and - the second character has the same meaning for the right-hand point. (Default: - 'co').

+ ``result = db.searchFilter(category="observed",tag="dataset")`` -

If cycle is specified, the axis is treated as circular - with the given cycle value. By default, if grid.isCircular() is - true, the axis is treated as circular with a default value of 360.0.

+ Searches can be restricted to a subhierarchy of the database. -

An interval of None returns the full index interval of the - axis.

+ **Example:** Search just the dataset ``'ncep_reanalysis_mo'``: -

If a mask is defined, the subgrid also has a mask corresponding to the index - ranges.Note: The result grid is not associated with any file or dataset.

-
-

Transient-CurveGrid

-
toCurveGrid(gridid=None) -

Convert to a curvilinear grid. If the grid is already curvilinear, a copy of - the grid object is returned. gridid is the string identifier of - the resulting curvilinear grid object. If unspecified, the grid ID is copied. - Note: This method does not apply to generic grids.

-
-

Transient-GenericGrid

-
toGenericGrid(gridid=None) -

Convert to a generic grid. If the grid is already generic, a copy of the - grid is returned. gridid is the string identifier of the resulting - curvilinear grid object. If unspecified, the grid ID is copied.

-
+Table 2.16 Database Internal Attributes -Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods - ++------------------+------------------+----------------------------------------+ +| Type | Name | Summary | ++==================+==================+========================================+ +| ``Dictionary`` | ``attributes`` | Database attribute dictionary | ++------------------+------------------+----------------------------------------+ +| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``netloc`` | Hostname, for server-based databases | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``path`` | path name | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``uri`` | Uniform Resource Identifier | ++------------------+------------------+----------------------------------------+ -.. raw:: html - +Table 2.17 Database Constructors -.. raw:: html ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================+==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``db = cdms.connect(uri=None, user="", password="")`` | Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection | ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -:: +Table 2.18 Database Methods - ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| None | ``close()`` | Close a database | +| | | connection. | ++--------------------------+--------------------------+--------------------------+ +| List | ``listDatasets()`` | Return a list of the | +| | | dataset IDs in this | +| | | database. A dataset ID | +| | | can be passed to the | +| | | ``open`` command. | ++--------------------------+--------------------------+--------------------------+ +| Dataset | ``open(dsetid, mode='r') | Open a dataset. | +| | `` | | +| | | ``dsetid`` is the string | +| | | dataset identifier | +| | | | +| | | ``mode`` is the open | +| | | mode, 'r' - read-only, | +| | | 'r+' - read-write, 'w' - | +| | | create. | +| | | | +| | | ``openDataset`` is a | +| | | synonym for ``open``. | ++--------------------------+--------------------------+--------------------------+ +| SearchResult | :: | Search a CDMS database. | +| | | | +| | searchFilter(filter= | ``filter`` is the string | +| | None, tag=None, relbase= | search filter. Simple | +| | None, scope=Subtree, att | filters have the form | +| | names=None, timeout=None | "tag = value". Simple | +| | ) | filters can be combined | +| | | using logical operators | +| | | '&', '\|', '!' in prefix | +| | | notation. | +| | | | +| | | **Example:** | +| | | | +| | | The filter | +| | | ``'(&(objec)(id=cli))'`` | +| | | finds all variables | +| | | named "cli". | +| | | | +| | | A formal definition of | +| | | search filters is | +| | | provided in the | +| | | following section. | +| | | | +| | | ``tag`` restricts the | +| | | search to objects with | +| | | that tag ("dataset" \| | +| | | "variable" \| "database" | +| | | \| "axis" \| "grid"). | +| | | | +| | | ``relbase`` is the | +| | | relative name of the | +| | | base object of the | +| | | search. The search is | +| | | restricted to the base | +| | | object and all objects | +| | | below it in the | +| | | hierarchy. | +| | | | +| | | **Example:** | +| | | | +| | | To search only dataset | +| | | 'ncep\_reanalysis\_mo', | +| | | specify: | +| | | | +| | | ``relbase="dataset=ncep_ | +| | | reanalysis_mo" `` | +| | | | +| | | To search only variable | +| | | 'ua' in | +| | | 'ncep\_reanalysis\_mo', | +| | | use: | +| | | | +| | | ``relbase="variable=ua,d | +| | | ataset=ncep_reanalysis_m | +| | | o"`` | +| | | | +| | | If no base is specified, | +| | | the entire database is | +| | | searched. See the | +| | | ``scope`` argument also. | +| | | | +| | | ``scope`` is the search | +| | | scope (**Subtree** \| | +| | | **Onelevel** \| | +| | | **Base**). | +| | | | +| | | - **Subtree** searches | +| | | the base object and | +| | | its descendants. | +| | | - **Onelevel** searches | +| | | the base object and | +| | | its immediate | +| | | descendants. | +| | | - **Base**\ searches | +| | | the base object | +| | | alone. | +| | | | +| | | The default is | +| | | **Subtree**. | +| | | | +| | | ``attnames``: list of | +| | | attribute names. | +| | | Restricts the attributes | +| | | returned. If ``None``, | +| | | all attributes are | +| | | returned. Attributes | +| | | 'id' and 'objectclass' | +| | | are always included in | +| | | the list. | +| | | | +| | | ``timeout``: integer | +| | | number of seconds before | +| | | timeout. The default is | +| | | no timeout. | ++--------------------------+--------------------------+--------------------------+ - - +2.7.2 Searching a database -.. raw:: html +The ``searchFilter`` method is used to search a database. The result is +called a search result, and consists of a sequence of result entries. - +In its simplest form, ``searchFilter`` takes an argument consisting of a +string filter. The search returns a sequence of entries, corresponding +to those objects having an attribute which matches the filter. Simple +filters have the form (tag = value), where value can contain wildcards. +For example: .. raw:: html - +
:: -
- - - - + (id = ncep*) + (project = AMIP2) .. raw:: html - + + ++--------------------------------------------------------------------+------------------------+ +| Simple filters can be combined with the logical operators ‘&’, ‘ | ’, ‘!’. For example, | ++--------------------------------------------------------------------+------------------------+ .. raw:: html - +
:: -
+ (&(id = bmrc*)(project = AMIP2)) - +.. raw:: html - + -.. raw:: html +matches all objects with id starting with bmrc, and a project attribute +with value ‘AMIP2’. - +Formally, search filters are strings defined as follows: .. raw:: html - +
:: -
+ filter ::= "(" filtercomp ")" - + filtercomp ::= "&" filterlist | # and + "|" filterlist | # or + "!" filterlist | # not + simple - + result = db.searchFilter('(&(category=obs*)(id=ncep*))') + for entry in result: + print entry.name .. raw:: html - + + +Search results can be narrowed using ``searchPredicate``. In the +following example, the result of one search is itself searched for all +variables defined on a 94x192 grid: .. raw:: html - +
:: -
+ >>> result = db.searchFilter('parentid=ncep*',tag="variable") + >>> len(result) + 65 + >>> result2 = result.searchPredicate(lambda x: - + x.getGrid().shape==(94,192)) + >>> len(result2) + 3 + >>> for entry in result2: print entry.name + variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - + o=LLNL, c=US + variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, -.. raw:: html + o=LLNL, c=US + variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - + o=LLNL, c=US .. raw:: html - - -:: - - - - - - +A search result is a sequence of result entries. Each entry has a string +name, the name of the object in the database hierarchy, and an attribute +dictionary. An entry corresponds to an object found by the search, but +differs from the object, in that only the attributes requested are +associated with the entry. In general, there will be much more +information defined for the associated CDMS object, which is retrieved +with the ``getObject`` method. -.. raw:: html - +Table 2.20 ResultEntry Attributes -.. raw:: html ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+=======================================================================================================================+ +| String | ``name`` | The name of this entry in the database. | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Dictionary | ``attributes`` | The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ - -:: +Table 2.21 ResultEntry Methods - ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+===================+======================================================================================================================================================================================================================================================================================+ +| ``CdmsObj`` | ``getObject()`` | Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. | ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - +To access data via CDMS: -.. raw:: html +#. Locate the dataset ID. This may involve searching the metadata. +#. Open the dataset, using the open method. +#. Reference the portion of the variable to be read. - +In the next example, a portion of variable ‘ua’ is read from dataset +‘ncep\_reanalysis\_mo’: .. raw:: html -
TypeMethodDescription
StringgetOrder()Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if - longitude is the first axis.
StringgetType()Get the grid type, either "gaussian", "uniform", "equalarea", or - "generic".
(Array,Array)getWeights() -

Get the normalized area weight arrays, as a tuple (latWeights, - lonWeights). It is assumed that the latitude and longitude axes are - defined in degrees.

+ filterlist ::= filter | filter filterlist + simple ::= tag op value + op ::= "=" | # equality -

The latitude weights are defined as:

+ "~=" | # approximate equality + "<=" | # lexicographically less than or equal to + ">=" # lexicographically greater than or equal to -

latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - - sin(latBounds[i]))

+ tag ::= string attribute name + value ::= string attribute value, may include '*' as a wild card -

The longitude weights are defined as:

+.. raw:: html -

lonWeights[i] = abs(lonBounds[i+1] - lonBounds[i])/360.0

+ -

For a global grid, the weight arrays are normalized such that the sum of the - weights is 1.0

+Attribute names are defined in the chapter on “Climate Data Markup +Language (CDML)” on page 149. In addition, some special attributes are +defined for convenience: -

Example:

+- ``category`` is either “experimental” or “observed” +- ``parentid`` is the ID of the parent dataset +- ``project`` is a project identifier, e.g., “AMIP2” +- ``objectclass`` is the list of tags associated with the object. -

Generate the 2-D weights array, such that weights[i.j] is the - fractional area of grid zone [i,j].

-
+The set of objects searched is called the search scope. The top object
+in the hierarchy is the base object. By default, all objects in the
+database are searched, that is, the database is the base object. If the
+database is very large, this may result in an unnecessarily slow or
+inefficient search. To remedy this the search scope can be limited in
+several ways:
 
-from cdms import MV latwts, lonwts = grid.getWeights() weights =
-MV.outerproduct(latwts, lonwts)
+-  The base object can be changed.
+-  The scope can be limited to the base object and one level below, or
+   to just the base object.
+-  The search can be restricted to objects of a given class (dataset,
+   variable, etc.)
+-  The search can be restricted to return only a subset of the object
+   attributes
+-  The search can be restricted to the result of a previous search.
+-  A search result is accessed sequentially within a for loop:
 
 .. raw:: html
 
-   
+
:: -

Also see the function area_weights in module - pcmdi.weighting.

-
NonesetType(gridtype)Set the grid type. gridtype is one of "gaussian", "uniform", - "equalarea", or "generic".
RectGridsubGrid((latStart,latStop),(lonStart,lonStop)) -

Create a new grid, with latitude index range [latStart : latStop] and - longitude index range [lonStart : lonStop]. Either index range can also be - specified as None, indicating that the entire range of the latitude or longitude - is used.

+ -

Example:

-

This creates newgrid corresponding to all latitudes and index range - [lonStart:lonStop] of oldgrid.

- -

newgrid = oldgrid.subGrid(None, (lonStart, lonStop))

+Table 2.19 SearchResult Methods -

If a mask is defined, the subgrid also has a mask corresponding to the index - ranges.

++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++================+============================================+==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ResultEntry | ``[i]`` | Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):`` | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``len()`` | Number of entries in the result. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| SearchResult | ``searchPredicate(predicate, tag=None)`` | Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag. **Note**: In the current implementation, ``searchPredicate``\ is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -

Note: The result grid is not associated with any file or dataset.

-
RectGridtranspose() -

Create a new grid, with axis order reversed. The grid mask is also - transposed.

+2.7.3 Accessing data -

Note: The result grid is not associated with any file or dataset.

-
- -2.11 Variable -^^^^^^^^^^^^^ +
-A Variable is a multidimensional data object, consisting of: +:: -- a multidimensional data array, possibly masked, -- a collection of attributes -- a domain, an ordered tuple of CoordinateAxis objects. + dset = db.open('ncep_reanalysis_mo') + ua = dset.variables['ua'] + data = ua[0,0] -A Variable which is contained in a Dataset or CdmsFile is called a -persistent variable. Setting a slice of a persistent Variable writes -data to the Dataset or file, and referencing a Variable slice reads data -from the Dataset. Variables may also be transient, not associated with a -Dataset or CdmsFile. +.. raw:: html -Variables support arithmetic operations, including the basic Python -operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations -defined in the MV module. The result of an arithmetic operation is a -transient variable, that is, the axis information is transferred to the -result. +
-The methods subRegion and subSlice return transient variables. In -addition, a transient variable may be created with the -cdms.createVariable method. The vcs and regrid module methods take -advantage of the attribute, domain, and mask information in a transient -variable. -Table 2.33 Variable Internal Attributes - - -+------+------+------+ -| Type | Name | Defi | -| | | niti | -| | | on | -+======+======+======+ -| Dict | ``at | Exte | -| iona | trib | rnal | -| ry | utes | attr | -| | `` | ibut | -| | | e | -| | | dict | -| | | iona | -| | | ry. | -+------+------+------+ -| Stri | ``id | Vari | -| ng | `` | able | -| | | iden | -| | | tifi | -| | | er. | -+------+------+------+ -| Stri | ``na | The | -| ng | me\_ | name | -| | in\_ | of | -| | file | the | -| | `` | vari | -| | | able | -| | | in | -| | | the | -| | | file | -| | | or | -| | | file | -| | | s | -| | | whic | -| | | h | -| | | repr | -| | | esen | -| | | t | -| | | the | -| | | data | -| | | set. | -| | | If | -| | | diff | -| | | eren | -| | | t | -| | | from | -| | | id, | -| | | the | -| | | vari | -| | | able | -| | | is | -| | | alia | -| | | sed. | -+------+------+------+ -| Data | ``pa | The | -| set | rent | data | -| or | `` | set | -| Cdms | | or | -| File | | file | -| | | whic | -| | | h | -| | | cont | -| | | ains | -| | | the | -| | | vari | -| | | able | -| | | . | -+------+------+------+ -| Tupl | ``sh | The | -| e | ape` | leng | -| | ` | th | -| | | of | -| | | each | -| | | axis | -| | | of | -| | | the | -| | | vari | -| | | able | -+------+------+------+ +2.7.4 Examples of database searches -Table 2.34 Variable Constructors - +In the following examples, db is the database opened with .. raw:: html - +
:: -
- - - - - - - - - - - - - - - - - - - - - - + db = cdms.connect() .. raw:: html -
ConstructorDescription
Dataset.createVariable(String id, String datatype, List axes)Create a Variable in a Dataset. This function is not yet implemented.
CdmsFile.createVariable(String id, String datatype, List - axesOr-Grids)Create a Variable in a CdmsFile. id is the name of the variable. - datatype is the MA or Numeric typecode, for example, MA.Float. - axesOrGrids is a list of Axis and/or Grid objects, on which the - variable is defined. Specifying a rectilinear grid is equivalent to listing the - grid latitude and longitude axes, in the order defined for the grid. **Note:** this - argument can either be a list or a tuple. If the tuple form is used, and there is - only one element, it must have a following comma, e.g.: - (axisobj,).
cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)
Create a transient variable, not associated with a file or dataset. - array is the data values: a Variable, masked array, or Numeric array. - typecode is the MA typecode of the array. Defaults to the typecode of - array. copy is an integer flag: if 1, the variable is created with a - copy of the array, if 0 the variable data is shared with array. - savespace is an integer flag: if set to 1, internal Numeric operations - will attempt to avoid silent upcasting. mask is an array of integers - with value 0 or 1, having the same shape as array. array elements with a - corresponding mask value of 1 are considered invalid, and are not used for - subsequent Numeric operations. The default mask is obtained from array if present, - otherwise is None. fill_value is the missing value flag. The default - is obtained from array if possible, otherwise is set to 1.0e20 for floating point - variables, 0 for integer-valued variables. grid is a rectilinear grid - object. axes is a tuple of axis objects. By default the axes are - obtained from array if present. Otherwise for a dimension of length n, the default - axis has values [0., 1., ..., double(n)]. attributes is a dictionary - of attribute values. The dictionary keys must be strings. By default the dictionary - is obtained from array if present, otherwise is empty. id is the - string identifier of the variable. By default the id is obtained from array if - possible, otherwise is set to 'variable_n' for some integer n.
+ -Table 2.35 Variable Methods - +This defaults to the database defined in environment variable +``CDMSROOT``. + +**Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: .. raw:: html - +
:: -
- - - - - - - - - - - - - - - - - - - + for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", + tag = "variable"): + print entry.name - - - - - - - +.. raw:: html - - + - - +**Example:** Find all axes with bounds defined: - +.. raw:: html - - +
-
- +:: - + for entry in db.searchFilter(filter="bounds=*",tag="axis"): + print entry.name - - +.. raw:: html - - + - +**Example:** Locate all GDT datasets: - - +
-
- +:: - + for entry in + db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + print entry.name - - + def missingTime(obj): + time = obj.getTime() + return time.length != time.partition_length - - + result = db.searchFilter(filter="category=observed") + for entry in result.searchPredicate(missingTime): + print entry.name - +.. raw:: html - - +**Example:** Find all CMIP2 datasets having a variable with id “hfss”: - - +.. raw:: html - +
-
- +:: - - + for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): + print entry.getObject().parent.id - +.. raw:: html - - +**Example:** Find all observed variables on 73x144 grids: - - +.. raw:: html - +
-
- +.. raw:: html - - + - +**Example:** Find the total number of each type of object in the +database - - +.. raw:: html - - +
-
+:: - - + print len(db.searchFilter(tag="database")),"database" + print len(db.searchFilter(tag="dataset")),"datasets" + print len(db.searchFilter(tag="variable")),"variables" + print len(db.searchFilter(tag="axis")),"axes" - - +.. raw:: html - + - - - - +2.8 Dataset +^^^^^^^^^^^ +A Dataset is a virtual file. It consists of a metafile, in CDML/XML +representation, and one or more data files. - +As of CDMS V3, the legacy cuDataset interface is supported by Datasets. +See “cu Module” on page 180. - - - - +Table 2.22 Dataset Internal Attributes - ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+==========================================================================================================+ +| Dictionary | ``attributes`` | Dataset external attributes. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``axes`` | Axes contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``datapath`` | Path of data files, relative to the parent database. If no parent, the datapath is absolute. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``grids`` | Grids contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``mode`` | Open mode. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Database | ``parent`` | Database which contains this dataset. If the dataset is not part of a database, the value is ``None``. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``uri`` | Uniform Resource Identifier of this dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``variables`` | Variables contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``xlinks`` | External links contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ - - - - +Table 2.23 Dataset Constructors - ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++===========================================================+===================================================================================================================================================================================================================+ +| ``datasetobj = cdms.open(String uri, String mode='r')`` | Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open`` | ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - - - +Table 2.24 Open Modes - ++--------+-----------------------------------------------------------------------+ +| Mode | Definition | ++========+=======================================================================+ +| ‘r’ | read-only | ++--------+-----------------------------------------------------------------------+ +| ‘r+’ | read-write | ++--------+-----------------------------------------------------------------------+ +| ‘a’ | read-write. Open the file if it exists, otherwise create a new file | ++--------+-----------------------------------------------------------------------+ +| ‘w’ | Create a new file, read-write | ++--------+-----------------------------------------------------------------------+ - - - - +Table 2.25 Dataset Methods - ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Transient-Variable | ``datasetobj(varname, se | Calling a Dataset object | +| | lector)`` | as a function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless | +| | | ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | xml') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| Variable, Axis, or Grid | ``datasetobj['id']`` | The square bracket | +| | | operator applied to a | +| | | dataset gets the | +| | | persistent variable, | +| | | axis or grid object | +| | | having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. Returns | +| | | ``None`` if not found. | +| | | | +| | | **Example:** | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.xml') | +| | | v = f['prc'] | +| | | | +| | | gets the persistent | +| | | variable v, equivalent | +| | | to | +| | | ``v = f.variab | +| | | les['prc']``. | +| | | | +| | | **Example:** | +| | | | +| | | | ``t = f['time']`` | +| | | | gets the axis named | +| | | 'time', equivalent to | +| | | ``t = f.axes['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the dataset. | + ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | +| | , lon, order, type="gene | dataset. This is not a | +| | ric", mask=Non | persistent object: the | +| | e)`` | order, type, and mask | +| | | are not written to the | +| | | dataset. However, the | +| | | grid may be used for | +| | | regridding operations. | +| | | | +| | | ``lat`` is a latitude | +| | | axis in the dataset. | +| | | | +| | | ``lon`` is a longitude | +| | | axis in the dataset. | +| | | | +| | | ``order`` is a string | +| | | with value "yx" (the | +| | | first grid dimension is | +| | | latitude) or "xy" (the | +| | | first grid dimension is | +| | | longitude). | +| | | | +| | | ``type`` is one of | +| | | 'gaussian','uniform','eq | +| | | ualarea',or | +| | | 'generic' | +| | | | +| | | If specified, ``mask`` | +| | | is a two-dimensional, | +| | | logical Numeric array | +| | | (all values are zero or | +| | | one) with the same shape | +| | | as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(id)`` | Get an axis object from | +| | | the file or dataset. | +| | | | +| | | ``id`` is the string | +| | | axis identifier. | ++--------------------------+--------------------------+--------------------------+ +| Grid | ``getGrid(id)`` | Get a grid object from a | +| | | file or dataset. | +| | | | +| | | ``id`` is the string | +| | | grid identifier. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths()`` | Get a sorted list of | +| | | pathnames of datafiles | +| | | which comprise the | +| | | dataset. This does not | +| | | include the XML metafile | +| | | path, which is stored in | +| | | the .uri attribute. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``getVariable(id)`` | Get a variable object | +| | | from a file or dataset. | +| | | | +| | | ``id`` is the string | +| | | variable identifier. | ++--------------------------+--------------------------+--------------------------+ +| CurveGrid or GenericGrid | ``readScripGrid(self, wh | Read a curvilinear or | +| | ichGrid='destination', c | generic grid from a | +| | heck-or Generic-Grid=1)` | SCRIP dataset. The | +| | ` | dataset can be a SCRIP | +| | | grid file or remapping | +| | | file. | +| | | | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. | +| | | | +| | | If ``checkGrid`` is 1 | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| None | ``sync()`` | Write any pending | +| | | changes to the dataset. | ++--------------------------+--------------------------+--------------------------+ - - +:: - - + import MV - +.. raw:: html - - +
-
- +:: - + from MV import * - - +.. raw:: html - - + - +allows use of MV commands without any prefix. - - +.. raw:: html - - +
-
+:: - - +Table 2.26 Variable Constructors in module MV - - ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MA.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MA.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | return an array of all ones of the given length or shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``reshape(a, newshape, axes=none, attributes=none, id=none)`` | copy of a with a new shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``resize(a, new_shape, axes=none, attributes=none, id=none)`` | return a new array with the specified shape. the original arrays total size can be any size. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | an array of all zeros of the given length or shape | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - +The following table describes the MV non-constructor functions. with the +exception of argsort, all functions return a transient variable. - - - - +Table 2.27 MV functions - +CDMS supports several types of HorizontalGrids: - - +Table 2.29 HorizontalGrid Internal Attribute - - ++-----------------------+------------------+------------------------------------------------+ +| Type | Name | Definition | ++=======================+==================+================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+------------------+------------------------------------------------+ +| String | ``id`` | The grid identifier. | ++-----------------------+------------------+------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | ++-----------------------+------------------+------------------------------------------------+ +| Tuple | ``shape`` | The shape of the grid, a 2-tuple | ++-----------------------+------------------+------------------------------------------------+ - +Table 2.31 on page 82 describes the methods that apply to all types of +HorizontalGrids. Table 2.32 on page 86 describes the additional methods +that are unique to RectGrids. - - - - +Table 2.30 RectGrid Constructors - ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================================================================+==================================================================================+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | Create a grid not associated with a file or dataset. See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``CdmsFile.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a file. See Table 2.14 on page 53. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``Dataset.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a dataset. See Table 2.25 on page 71. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGaussianGrid(nlats, xorigin=0.0, order="yx")`` | See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGlobalMeanGrid(grid)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createZonalGrid(grid)`` | See Table 2.2 on page 18 | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ - - - - +Table 2.31 HorizontalGrid Methods - ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| Horizontal-Grid | ``clone()`` | Return a transient copy | +| | | of the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(Integer n)`` | Get the n-th axis.n is | +| | | either 0 or 1. | ++--------------------------+--------------------------+--------------------------+ +| Tuple | ``getBounds()`` | Get the grid boundary | +| | | arrays. | +| | | | +| | | Returns a tuple | +| | | ``(latitudeArray, longit | +| | | udeArray)``, | +| | | where latitudeArray is a | +| | | Numeric array of | +| | | latitude bounds, and | +| | | similarly for | +| | | longitudeArray.The shape | +| | | of latitudeArray and | +| | | longitudeArray depend on | +| | | the type of grid: | +| | | | +| | | - for rectangular grids | +| | | with shape (nlat, | +| | | nlon), the boundary | +| | | arrays have shape | +| | | (nlat,2) and | +| | | (nlon,2). | +| | | - for curvilinear grids | +| | | with shape (nx, ny), | +| | | the boundary arrays | +| | | each have shape (nx, | +| | | ny, 4). | +| | | - for generic grids | +| | | with shape (ncell,), | +| | | the boundary arrays | +| | | each have shape | +| | | (ncell, nvert) where | +| | | nvert is the maximum | +| | | number of vertices | +| | | per cell. | +| | | | +| | | For rectilinear grids: | +| | | If no boundary arrays | +| | | are explicitly defined | +| | | (in the file or | +| | | dataset), the result | +| | | depends on the auto- | +| | | Bounds mode (see | +| | | ``cdms.setAutoBounds``) | +| | | and the grid | +| | | classification mode (see | +| | | ``cdms.setClassifyGrids` | +| | | `). | +| | | By default, autoBounds | +| | | mode is enabled, in | +| | | which case the boundary | +| | | arrays are generated | +| | | based on the type of | +| | | grid. If disabled, the | +| | | return value is | +| | | (None,None).For | +| | | rectilinear grids: The | +| | | grid classification mode | +| | | specifies how the grid | +| | | type is to be | +| | | determined. By default, | +| | | the grid type (Gaussian, | +| | | uniform, etc.) is | +| | | determined by calling | +| | | grid.classifyInFamily. | +| | | If the mode is 'off' | +| | | grid.getType is used | +| | | instead. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMask()`` | Get the mask array of | +| | | this grid, if | +| | | any.Returns a 2-D | +| | | Numeric array, having | +| | | the same shape as the | +| | | grid. If the mask is not | +| | | explicitly defined, the | +| | | return value is | +| | | ``None``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMesh(self, transpos | Generate a mesh array | +| | e=None)`` | for the meshfill | +| | | graphics method.If | +| | | transpose is defined to | +| | | a tuple, say (1,0), | +| | | first transpose | +| | | latbounds and lonbounds | +| | | according to the tuple, | +| | | in this case (1,0,2). | ++--------------------------+--------------------------+--------------------------+ +| None | ``setBounds(latBounds, l | Set the grid | +| | onBounds, persistent=0)` | boundaries.\ ``latBounds | +| | ` | `` | +| | | is a NumPy array of | +| | | shape (n,2), such that | +| | | the boundaries of the | +| | | kth axis value are | +| | | ``[latBounds[k,0],latBou | +| | | nds[k,1] ]``. | +| | | ``lonBounds`` is defined | +| | | similarly for the | +| | | longitude array. | +| | | **Note:** By default, | +| | | the boundaries are not | +| | | written to the file or | +| | | dataset containing the | +| | | grid (if any). This | +| | | allows bounds to be set | +| | | on read-only files, for | +| | | regridding. If the | +| | | optional argument | +| | | ``persistent`` is set to | +| | | 1, the boundary array is | +| | | written to the file. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setMask(mask, persiste | Set the grid mask. If | +| | nt=0)`` | ``persistent == 1``, the | +| | | mask values are written | +| | | to the associated file, | +| | | if any. Otherwise, the | +| | | mask is associated with | +| | | the grid, but no I/O is | +| | | generated. ``mask`` is a | +| | | two-dimensional, | +| | | Boolean-valued Numeric | +| | | array, having the same | +| | | shape as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``subGridRegion(latInter | Create a new grid | +| | val, lonInterval)`` | corresponding to the | +| | | coordinate region | +| | | defined by | +| | | ``latInterval, lonInterv | +| | | al.`` | +| | | | +| | | ``latInterval`` and | +| | | ``lonInterval`` are the | +| | | coordinate intervals for | +| | | latitude and longitude, | +| | | respectively. | +| | | | +| | | Each interval is a tuple | +| | | having one of the forms: | +| | | | +| | | - ``(x,y)`` | +| | | - ``(x,y,indicator)`` | +| | | - ``(x,y,indicator,cycl | +| | | e)`` | +| | | - ``None`` | +| | | | +| | | where ``x`` and ``y`` | +| | | are coordinates | +| | | indicating the interval | +| | | ``[x,y)``, and: | +| | | | +| | | ``indicator`` is a | +| | | two-character string, | +| | | where the first | +| | | character is 'c' if the | +| | | interval is closed on | +| | | the left, 'o' if open, | +| | | and the second character | +| | | has the same meaning for | +| | | the right-hand point. | +| | | (Default: 'co'). | +| | | | +| | | If ``cycle`` is | +| | | specified, the axis is | +| | | treated as circular with | +| | | the given cycle value. | +| | | By default, if | +| | | ``grid.isCircular()`` is | +| | | true, the axis is | +| | | treated as circular with | +| | | a default value of | +| | | 360.0. | +| | | | +| | | An interval of ``None`` | +| | | returns the full index | +| | | interval of the axis. | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges.Note: | +| | | The result grid is not | +| | | associated with any file | +| | | or dataset. | ++--------------------------+--------------------------+--------------------------+ +| Transient-CurveGrid | ``toCurveGrid(gridid=Non | Convert to a curvilinear | +| | e)`` | grid. If the grid is | +| | | already curvilinear, a | +| | | copy of the grid object | +| | | is returned. ``gridid`` | +| | | is the string identifier | +| | | of the resulting | +| | | curvilinear grid object. | +| | | If unspecified, the grid | +| | | ID is copied. **Note:** | +| | | This method does not | +| | | apply to generic grids. | ++--------------------------+--------------------------+--------------------------+ +| Transient-GenericGrid | ``toGenericGrid(gridid=N | Convert to a generic | +| | one)`` | grid. If the grid is | +| | | already generic, a copy | +| | | of the grid is returned. | +| | | ``gridid`` is the string | +| | | identifier of the | +| | | resulting curvilinear | +| | | grid object. If | +| | | unspecified, the grid ID | +| | | is copied. | ++--------------------------+--------------------------+--------------------------+ + + +Table 2.32 RectGrid Methods, additional to HorizontalGrid + Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| String | ``getOrder()`` | Get the grid ordering, | +| | | either "yx" if latitude | +| | | is the first axis, or | +| | | "xy" if longitude is the | +| | | first axis. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getType()`` | Get the grid type, | +| | | either "gaussian", | +| | | "uniform", "equalarea", | +| | | or "generic". | ++--------------------------+--------------------------+--------------------------+ +| (Array,Array) | ``getWeights()`` | Get the normalized area | +| | | weight arrays, as a | +| | | tuple | +| | | ``(latWeights, lon | +| | | Weights)``. | +| | | It is assumed that the | +| | | latitude and longitude | +| | | axes are defined in | +| | | degrees. | +| | | | +| | | The latitude weights are | +| | | defined as: | +| | | | +| | | ``latWeights[i] = 0.5 * | +| | | abs(sin(latBounds[i+1]) | +| | | - sin(latBounds[i] | +| | | ))`` | +| | | | +| | | The longitude weights | +| | | are defined as: | +| | | | +| | | ``lonWeights[i] = abs(lo | +| | | nBounds[i+1] - lonBounds | +| | | [i])/360.0`` | +| | | | +| | | For a global grid, the | +| | | weight arrays are | +| | | normalized such that the | +| | | sum of the weights is | +| | | 1.0 | +| | | | +| | | **Example:** | +| | | | +| | | Generate the 2-D weights | +| | | array, such that | +| | | ``weights[i.j]`` is the | +| | | fractional area of grid | +| | | zone ``[i,j]``. | +| | | | +| | | :: | +| | | | +| | | from cdms import MV | +| | | latwts, lonwts = gri | +| | | d.getWeights() | +| | | weights = MV.outerpr | +| | | oduct(latwts, lonwts) | +| | | | +| | | Also see the function | +| | | ``area_weights`` in | +| | | module | +| | | ``pcmdi.weighting``. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setType(gridtype)`` | Set the grid type. | +| | | ``gridtype`` is one of | +| | | "gaussian", "uniform", | +| | | "equalarea", or | +| | | "generic". | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``subGrid((latStart,latS | Create a new grid, with | +| | top),(lonStart,lonStop)) | latitude index range | +| | `` | [latStart : latStop] and | +| | | longitude index range | +| | | [lonStart : lonStop]. | +| | | Either index range can | +| | | also be specified as | +| | | None, indicating that | +| | | the entire range of the | +| | | latitude or longitude is | +| | | used. | +| | | | +| | | **Example:** | +| | | | +| | | This creates newgrid | +| | | corresponding to all | +| | | latitudes and index | +| | | range [lonStart:lonStop] | +| | | of oldgrid. | +| | | | +| | | ``newgrid = oldgrid.subG | +| | | rid(None, (lonStart, lon | +| | | Stop))`` | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``transpose()`` | Create a new grid, with | +| | | axis order reversed. The | +| | | grid mask is also | +| | | transposed. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ - - - - +2.11 Variable +^^^^^^^^^^^^^ - +A Variable is a multidimensional data object, consisting of: - - +- a multidimensional data array, possibly masked, +- a collection of attributes +- a domain, an ordered tuple of CoordinateAxis objects. - - +A Variable which is contained in a Dataset or CdmsFile is called a +persistent variable. Setting a slice of a persistent Variable writes +data to the Dataset or file, and referencing a Variable slice reads data +from the Dataset. Variables may also be transient, not associated with a +Dataset or CdmsFile. - - - +Table 2.35 Variable Methods - - ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Variable | ``tvar = var[ i:j, m:n]` | Read a slice of data | +| | ` | from the file or | +| | | dataset, resulting in a | +| | | transient variable. | +| | | Singleton dimensions are | +| | | 'squeezed' out. Data is | +| | | returned in the physical | +| | | ordering defined in the | +| | | dataset. The forms of | +| | | the slice operator are | +| | | listed in Table 2.36 on | +| | | page 102. | ++--------------------------+--------------------------+--------------------------+ +| None | ``var[ i:j, m:n] = array | Write a slice of data to | +| | `` | the external dataset. | +| | | The forms of the slice | +| | | operator are listed in | +| | | Table 2.21 on page 32. | +| | | (Variables in CdmsFiles | +| | | only) | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``tvar = var(selector)`` | Calling a variable as a | +| | | function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless raw=1 | +| | | keyword is specified. | +| | | See "Selectors" on page | +| | | 103. | ++--------------------------+--------------------------+--------------------------+ +| None | ``assignValue(Array ar)` | Write the entire data | +| | ` | array. Equivalent to | +| | | ``var[:] = ar``. | +| | | (Variables in CdmsFiles | +| | | only). | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``astype(typecode)`` | Cast the variable to a | +| | | new datatype. Typecodes | +| | | are as for MV, MA, and | +| | | Numeric modules. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``clone(copyData=1)`` | Return a copy of a | +| | | transient variable. | +| | | | +| | | If copyData is 1 (the | +| | | default) the variable | +| | | data is copied as well. | +| | | If copyData is 0, the | +| | | result transient | +| | | variable shares the | +| | | original transient | +| | | variables data array. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | :: | Return a lat/level | +| | | vertical cross-section | +| | crossSectionRegrid(n | regridded to a new set | +| | ewLevel, newLatitude, me | of latitudes newLatitude | +| | thod="log", missing=None | and levels newLevel. The | +| | , order=None) | variable should be a | +| | | function of latitude, | +| | | level, and (optionally) | +| | | time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``newLatitude`` is an | +| | | axis of the result | +| | | latitudes. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzy" or | +| | | "zy". The default is | +| | | ``var.getOrder()``. | +| | | | +| | | *See also:* ``regrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(n)`` | Get the n-th axis. | +| | | | +| | | ``n`` is an integer. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisIds()`` | Get a list of axis | +| | | identifiers. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``getAxisIndex(axis_spec | Return the index of the | +| | )`` | axis specificed by | +| | | axis\_spec. Return -1 if | +| | | no match. | +| | | | +| | | ``axis_spec`` is a | +| | | specification as defined | +| | | for getAxisList | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisList(axes=None, | Get an ordered list of | +| | omit=None, order=None)` | axis objects in the | +| | ` | domain of the variable. | +| | | | +| | | If ``axes`` is not | +| | | ``None``, include only | +| | | certain axes. Otherwise | +| | | axes is a list of | +| | | specifications as | +| | | described below. Axes | +| | | are returned in the | +| | | order specified unless | +| | | the order keyword is | +| | | given. | +| | | | +| | | If ``omit`` is not | +| | | ``None``, omit those | +| | | specified by an integer | +| | | dimension number. | +| | | Otherwise omit is a list | +| | | of specifications as | +| | | described below. | +| | | | +| | | ``order`` is an optional | +| | | string determining the | +| | | output order. | +| | | | +| | | Specifications for the | +| | | axes or omit keywords | +| | | are a list, each element | +| | | having one of the | +| | | following forms: | +| | | | +| | | - an integer dimension | +| | | index, starting at 0. | +| | | - a string representing | +| | | an axis id or one of | +| | | the strings 'time', | +| | | 'latitude', 'lat', | +| | | 'longitude', 'lon', | +| | | 'lev' or 'level'. | +| | | - a function that takes | +| | | an axis as an | +| | | argument and returns | +| | | a value. If the value | +| | | returned is true, the | +| | | axis matches. | +| | | - an axis object; will | +| | | match if it is the | +| | | same object as axis. | +| | | | +| | | ``order`` can be a | +| | | string containing the | +| | | characters t,x,y,z, or | +| | | -. If a dash ('-') is | +| | | given, any elements of | +| | | the result not chosen | +| | | otherwise are filled in | +| | | from left to right with | +| | | remaining candidates. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisListIndex(axes= | Return a list of indices | +| | None, omit=None, order=N | of axis objects. | +| | one)`` | Arguments are as for | +| | | getAxisList. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getDomain()`` | Get the domain. Each | +| | | element of the list is | +| | | itself a tuple of the | +| | | form | +| | | ``(axis,start,length,tru | +| | | e_length)`` | +| | | where axis is an axis | +| | | object, start is the | +| | | start index of the | +| | | domain relative to the | +| | | axis object, length is | +| | | the length of the axis, | +| | | and true\_length is the | +| | | actual number of | +| | | (defined) points in the | +| | | domain. *See also:* | +| | | ``getAxisList``. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``getGrid()`` | Return the associated | +| | | grid, or ``None`` if the | +| | | variable is not gridded. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLevel()`` | Get the vertical level | +| | | axis, or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the longitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Various | ``getMissing()`` | Get the missing data | +| | | value, or ``None`` if | +| | | not found. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getOrder()`` | Get the order string of | +| | | a spatio-temporal | +| | | variable. The order | +| | | string specifies the | +| | | physical ordering of the | +| | | data. It is a string of | +| | | characters with length | +| | | equal to the rank of the | +| | | variable, indicating the | +| | | order of the variable's | +| | | time, level, latitude, | +| | | and/or longitude axes. | +| | | Each character is one | +| | | of: | +| | | | +| | | - 't': time | +| | | - 'z': vertical level | +| | | - 'y': latitude | +| | | - 'x': longitude | +| | | - '-': the axis is not | +| | | spatio-temporal. | +| | | | +| | | **Example:** | +| | | | +| | | A variable with ordering | +| | | "tzyx" is 4-dimensional, | +| | | where the ordering of | +| | | axes is (time, level, | +| | | latitude, longitude). | +| | | | +| | | **Note:** The order | +| | | string is of the form | +| | | required for the order | +| | | argument of a regridder | +| | | function. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths(*intervals)`` | Get the file paths | +| | | associated with the | +| | | index region specified | +| | | by intervals. | +| | | | +| | | ``intervals`` is a list | +| | | of scalars, 2-tuples | +| | | representing [i,j), | +| | | slices, and/or Ellipses. | +| | | If no ``argument(s)`` | +| | | are present, all file | +| | | paths associated with | +| | | the variable are | +| | | returned. | +| | | | +| | | Returns a list of tuples | +| | | of the form | +| | | (path,slicetuple), where | +| | | path is the path of a | +| | | file, and slicetuple is | +| | | itself a tuple of | +| | | slices, of the same | +| | | length as the rank of | +| | | the variable, | +| | | representing the portion | +| | | of the variable in the | +| | | file corresponding to | +| | | intervals. | +| | | | +| | | **Note:** This function | +| | | is not defined for | +| | | transient variables. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getTime()`` | Get the time axis, or | +| | | ``None`` if not found. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``len(var)`` | The length of the first | +| | | dimension of the | +| | | variable. If the | +| | | variable is | +| | | zero-dimensional | +| | | (scalar), a length of 0 | +| | | is returned. | +| | | | +| | | **Note:** ``size()`` | +| | | returns the total number | +| | | of elements. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | ``pressureRegrid (newLev | Return the variable | +| | el, method="log", missin | regridded to a new set | +| | g=None, order=None | of pressure levels | +| | )`` | newLevel. The variable | +| | | must be a function of | +| | | latitude, longitude, | +| | | pressure level, and | +| | | (optionally) time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzyx" or | +| | | "zyx". The default is | +| | | ``var.getOrder()`` | +| | | | +| | | See also: ``regrid``, | +| | | ``crossSectionRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``rank()`` | The number of dimensions | +| | | of the variable. | ++--------------------------+--------------------------+--------------------------+ +| Transient | :: | Return the variable | +| | | regridded to the | +| | regrid (togrid, miss | horizontal grid togrid. | +| | ing=None, order=None, Va | | +| | riable mask=None) | ``missing`` is a Float | +| | | specifying the missing | +| | | data value. The default | +| | | is 1.0e20. | +| | | | +| | | ``order`` is a string | +| | | indicating the order of | +| | | dimensions of the array. | +| | | It has the form returned | +| | | from | +| | | ``variable.getOrder()``. | +| | | For example, the string | +| | | "tzyx" indicates that | +| | | the dimension order of | +| | | array is (time, level, | +| | | latitude, longitude). If | +| | | unspecified, the | +| | | function assumes that | +| | | the last two dimensions | +| | | of array match the input | +| | | grid. | +| | | | +| | | ``mask`` is a Numeric | +| | | array, of datatype | +| | | Integer or Float, | +| | | consisting of ones and | +| | | zeros. A value of 0 or | +| | | 0.0 indicates that the | +| | | corresponding data value | +| | | is to be ignored for | +| | | purposes of regridding. | +| | | If mask is | +| | | two-dimensional of the | +| | | same shape as the input | +| | | grid, it overrides the | +| | | mask of the input grid. | +| | | If the mask has more | +| | | than two dimensions, it | +| | | must have the same shape | +| | | as array. In this case, | +| | | the missing data value | +| | | is also ignored. Such an | +| | | n-dimensional mask is | +| | | useful if the pattern of | +| | | missing data varies with | +| | | level (e.g., ocean data) | +| | | or time. Note: If | +| | | neither missing or mask | +| | | is set, the default mask | +| | | is obtained from the | +| | | mask of the array if | +| | | any. | +| | | | +| | | See also: | +| | | ``crossSectionRegrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxis(n, axis)`` | Set the n-th axis | +| | | (0-origin index) of to a | +| | | copy of axis. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxisList(axislist)` | Set all axes of the | +| | ` | variable. axislist is a | +| | | list of axis objects. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setMissing(value)`` | Set the missing value. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``size()`` | Number of elements of | +| | | the variable. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a coordinate region | +| | | of data, returning a | +| | subRegion(*region, t | transient variable. A | +| | ime=None, level=None, la | region is a | +| | titude=None, longitude=N | hyperrectangle in | +| | one, squeeze=0, raw=0) | coordinate space. | +| | | | +| | | ``region`` is an | +| | | argument list, each item | +| | | of which specifies an | +| | | interval of a coordinate | +| | | axis. The intervals are | +| | | listed in the order of | +| | | the variable axes. If | +| | | trailing dimensions are | +| | | omitted, all values of | +| | | those dimensions are | +| | | retrieved. If an axis is | +| | | circular | +| | | (axis.isCircular() is | +| | | true) or cycle is | +| | | specified (see below), | +| | | then data will be read | +| | | with wraparound in that | +| | | dimension. Only one axis | +| | | may be read with | +| | | wraparound. A coordinate | +| | | interval has one of the | +| | | forms listed in Table | +| | | 2.37 on page 102. Also | +| | | see | +| | | ``axis.mapIntervalExt``. | +| | | | +| | | The optional keyword | +| | | arguments ``time``, | +| | | ``level``, ``latitude``, | +| | | and ``longitude`` may | +| | | also be used to specify | +| | | the dimension for which | +| | | the interval applies. | +| | | This is particularly | +| | | useful if the order of | +| | | dimensions is not known | +| | | in advance. An exception | +| | | is raised if a keyword | +| | | argument conflicts with | +| | | a positional region | +| | | argument. | +| | | | +| | | The optional keyword | +| | | argument ``squeeze`` | +| | | determines whether or | +| | | not the shape of the | +| | | returned array contains | +| | | dimensions whose length | +| | | is 1; by default this | +| | | argument is 0, and such | +| | | dimensions are not | +| | | 'squeezed out'. | +| | | | +| | | The optional keyword | +| | | argument ``raw`` | +| | | specifies whether the | +| | | return object is a | +| | | variable or a masked | +| | | array. By default, a | +| | | transient variable is | +| | | returned, having the | +| | | axes and attributes | +| | | corresponding to2,3 the | +| | | region read. If raw=1, | +| | | an MA masked array is | +| | | returned, equivalent to | +| | | the transient variable | +| | | without the axis and | +| | | attribute information. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a slice of data, | +| | | returning a transient | +| | subSlice(*specs, tim | variable. This is a | +| | e=None, level=None, lati | functional form of the | +| | tude=None, longitude=Non | slice operator [] with | +| | e, squeeze=0, raw=0) | the squeeze option | +| | | turned off. | +| | | | +| | | ``specs`` is an argument | +| | | list, each element of | +| | | which specifies a slice | +| | | of the corresponding | +| | | dimension. There can be | +| | | zero or more positional | +| | | arguments, each of the | +| | | form: | +| | | | +| | | - a single integer n, | +| | | meaning | +| | | ``slice(n, n+1)`` | +| | | - an instance of the | +| | | slice class | +| | | - a tuple, which will | +| | | be used as arguments | +| | | to create a slice | +| | | - ':', which means a | +| | | slice covering that | +| | | entire dimension | +| | | - Ellipsis (...), which | +| | | means to fill the | +| | | slice list with ':' | +| | | leaving only enough | +| | | room at the end for | +| | | the remaining | +| | | positional arguments | +| | | - a Python slice | +| | | object, of the form | +| | | ``slice(i,j,k)`` | +| | | | +| | | If there are fewer | +| | | slices than | +| | | corresponding | +| | | dimensions, all values | +| | | of the trailing | +| | | dimensions are read. | +| | | | +| | | The keyword arguments | +| | | are defined as in | +| | | subRegion. | +| | | | +| | | There must be no | +| | | conflict between the | +| | | positional arguments and | +| | | the keywords. | +| | | | +| | | In ``(a)-(c)`` and (f), | +| | | negative numbers are | +| | | treated as offsets from | +| | | the end of that | +| | | dimension, as in normal | +| | | Python indexing. | ++--------------------------+--------------------------+--------------------------+ +| String | ``typecode()`` | The Numeric datatype | +| | | identifier. | ++--------------------------+--------------------------+--------------------------+ - - - - + data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, + 180.0) - - +.. raw:: html - + - - +Read all data for March, 1980: .. raw:: html -
TypeMethodDefinition
Variabletvar = var[ i:j, m:n]Read a slice of data from the file or dataset, resulting in a transient - variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical - ordering defined in the dataset. The forms of the slice operator are listed in - Table 2.36 on page 102.
Nonevar[ i:j, m:n] = arrayWrite a slice of data to the external dataset. The forms of the slice operator - are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)
Variabletvar = var(selector)Calling a variable as a function reads the region of data defined by the - selector. The result is a transient variable, unless raw=1 keyword is specified. - See "Selectors" on page 103.
NoneassignValue(Array ar)Write the entire data array. Equivalent to var[:] = ar. (Variables - in CdmsFiles only).
Variableastype(typecode)Cast the variable to a new datatype. Typecodes are as for MV, MA, and Numeric - modules.
Variableclone(copyData=1) -

Return a copy of a transient variable.

+.. raw:: html -

If copyData is 1 (the default) the variable data is copied as well. If - copyData is 0, the result transient variable shares the original transient - variables data array.

-
Transient Variable
crossSectionRegrid(newLevel, newLatitude, method="log", missing=None, order=None)
-

Return a lat/level vertical cross-section regridded to a new set of latitudes - newLatitude and levels newLevel. The variable should be a function of latitude, - level, and (optionally) time.

+.. raw:: html -

newLevel is an axis of the result pressure levels.

+ -

newLatitude is an axis of the result latitudes.

+**Example:** Find all variables with missing time values, in observed +datasets: -

method is optional, either "log" to interpolate in the log of - pressure (default), or "linear" for linear interpolation.

+.. raw:: html -

missing is a missing data value. The default is - var.getMissing()

+
-

order is an order string such as "tzy" or "zy". The default is - var.getOrder().

+:: -

See also: regrid, pressureRegrid.

-
AxisgetAxis(n) -

Get the n-th axis.

+ -

n is an integer.

-
ListgetAxisIds()Get a list of axis identifiers.
IntegergetAxisIndex(axis_spec) -

Return the index of the axis specificed by axis_spec. Return -1 if no - match.

+ -

axis_spec is a specification as defined for getAxisList

-
ListgetAxisList(axes=None, omit=None, order=None) -

Get an ordered list of axis objects in the domain of the variable.

+:: -

If axes is not None, include only certain axes. - Otherwise axes is a list of specifications as described below. Axes are returned - in the order specified unless the order keyword is given.

+ result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): + print entry.name -

If omit is not None, omit those specified by an - integer dimension number. Otherwise omit is a list of specifications as described - below.

+.. raw:: html -

order is an optional string determining the output order.

+ -

Specifications for the axes or omit keywords are a list, each element having - one of the following forms:

+**Example:** Find all observed variables with more than 1000 timepoints: -
    -
  • an integer dimension index, starting at 0.
  • +.. raw:: html -
  • a string representing an axis id or one of the strings 'time', 'latitude', - 'lat', 'longitude', 'lon', 'lev' or 'level'.
  • +
    -
  • a function that takes an axis as an argument and returns a value. If the - value returned is true, the axis matches.
  • +:: -
  • an axis object; will match if it is the same object as axis.
  • -
+ result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): + print entry.name, len(entry.getObject().getTime()) -

order can be a string containing the characters t,x,y,z, or -. If - a dash ('-') is given, any elements of the result not chosen otherwise are filled - in from left to right with remaining candidates.

-
ListgetAxisListIndex(axes=None, omit=None, order=None)Return a list of indices of axis objects. Arguments are as for - getAxisList.
ListgetDomain()Get the domain. Each element of the list is itself a tuple of the form - (axis,start,length,true_length) where axis is an axis object, start is - the start index of the domain relative to the axis object, length is the length of - the axis, and true_length is the actual number of (defined) points in the domain. - See also: getAxisList.
Horizontal-GridgetGrid()Return the associated grid, or None if the variable is not - gridded.
AxisgetLatitude()Get the latitude axis, or None if not found.
AxisgetLevel()Get the vertical level axis, or None if not found.
AxisgetLongitude()Get the longitude axis, or None if not found.
VariousgetMissing()Get the missing data value, or None if not found.
StringgetOrder() -

Get the order string of a spatio-temporal variable. The order string specifies - the physical ordering of the data. It is a string of characters with length equal - to the rank of the variable, indicating the order of the variable's time, level, - latitude, and/or longitude axes. Each character is one of:

-
    -
  • 't': time
  • +2.9 MV module +^^^^^^^^^^^^^ -
  • 'z': vertical level
  • +The fundamental CDMS data object is the variable. A variable is +comprised of: -
  • 'y': latitude
  • +- a masked data array, as defined in the NumPy MA module. +- a domain: an ordered list of axes and/or grids. +- an attribute dictionary. -
  • 'x': longitude
  • +The MV module is a work-alike replacement for the MA module, that +carries along the domain and attribute information where appropriate. MV +provides the same set of functions as MA. However, MV functions generate +transient variables as results. Often this simplifies scripts that +perform computation. MA is part of the Python Numeric package, +documented at http://www.numpy.org. -
  • '-': the axis is not spatio-temporal.
  • -
+MV can be imported with the command: -

Example:

+.. raw:: html -

A variable with ordering "tzyx" is 4-dimensional, where the ordering of axes - is (time, level, latitude, longitude).

+
-

Note: The order string is of the form required for the order argument - of a regridder function.

-
ListgetPaths(*intervals) -

Get the file paths associated with the index region specified by - intervals.

+ -

intervals is a list of scalars, 2-tuples representing [i,j), - slices, and/or Ellipses. If no argument(s) are present, all file - paths associated with the variable are returned.

+The command -

Returns a list of tuples of the form (path,slicetuple), where path is the path - of a file, and slicetuple is itself a tuple of slices, of the same length as the - rank of the variable, representing the portion of the variable in the file - corresponding to intervals.

+.. raw:: html -

Note: This function is not defined for transient variables.

-
AxisgetTime()Get the time axis, or None if not found.
Integerlen(var) -

The length of the first dimension of the variable. If the variable is - zero-dimensional (scalar), a length of 0 is returned.

+Table 2.26 on page 75 lists the constructors in MV. All functions return +a transient variable. In most cases the keywords axes, attributes, and +id are available. axes is a list of axis objects which specifies the +domain of the variable. attributes is a dictionary. id is a special +attribute string that serves as the identifier of the variable, and +should not contain blanks or non-printing characters. It is used when +the variable is plotted or written to a file. Since the id is just an +attribute, it can also be set like any attribute: -

Note: size() returns the total number of elements.

-
Transient VariablepressureRegrid (newLevel, method="log", missing=None, - order=None) -

Return the variable regridded to a new set of pressure levels newLevel. The - variable must be a function of latitude, longitude, pressure level, and - (optionally) time.

+ var.id = 'temperature' -

newLevel is an axis of the result pressure levels.

+.. raw:: html -

method is optional, either "log" to interpolate in the log of - pressure (default), or "linear" for linear interpolation.

+ -

missing is a missing data value. The default is - var.getMissing()

+For completeness MV provides access to all the MA functions. The +functions not listed in the following tables are identical to the +corresponding MA function: ``allclose``, ``allequal``, +``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, +``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, +``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, +``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, +``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, +``putmask``, ``rank``, ``ravel``, ``set_fill_value``, +``set_print_limit``, ``shape``, ``size``. See the documentation at +http://numpy.sourceforge.net for a description of these functions. -

order is an order string such as "tzyx" or "zyx". The default is - var.getOrder()

-

See also: regrid, crossSectionRegrid.

-
Integerrank()The number of dimensions of the variable.
Transient -
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| Function                                                            | Description                                                                                                                                                                                                                                                                                                                                                          |
++=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+
+| ``argsort(x, axis=-1, fill_value=None)``                            | Return a Numeric array of indices for sorting along a given axis.                                                                                                                                                                                                                                                                                                    |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``asarray(data, typecode=None)``                                    | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function.                                                                                                                 |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``average(a, axis=0, weights=None)``                                | Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored.                                                   |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``choose(condition, t)``                                            | Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked.   |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``concatenate(arrays, axis=0, axisid=None, axisattributes=None)``   | Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array.                                                                                                                                                                                                                           |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``count(a, axis=None)``                                             | Count of the non-masked elements in ``a``, or along a certain axis.                                                                                                                                                                                                                                                                                                  |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``isMaskedVariable(x)``                                             | Return true if ``x`` is an instance of a variable.                                                                                                                                                                                                                                                                                                                   |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_equal(x, value)``                                          | ``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead.                                                                                                                                                                                                                                            |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_greater(x, value)``                                        | ``x`` masked where ``x > value``                                                                                                                                                                                                                                                                                                                                     |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_greater_equal(x, value)``                                  | ``x`` masked where ``x >= value``                                                                                                                                                                                                                                                                                                                                    |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_less(x, value)``                                           | ``x`` masked where ``x < value``                                                                                                                                                                                                                                                                                                                                  |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_less_equal(x, value)``                                     | ``x`` masked where ``x ≤ value``                                                                                                                                                                                                                                                                                                                                  |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_not_equal(x, value)``                                      | ``x`` masked where ``x != value``                                                                                                                                                                                                                                                                                                                                    |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_outside(x, v1, v2)``                                       | ``x`` with mask of all values of ``x`` that are outside ``[v1,v2]``                                                                                                                                                                                                                                                                                                  |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``masked_where(condition, x, copy=1)``                              | Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``.                                                                                                                                                                                          |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``maximum(a, b=None)``                                              | Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked.                                                                                                                                                                       |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``minimum(a, b=None)``                                              | Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked.                                                                                                                                                                          |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``outerproduct(a, b)``                                              | Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked.                                                                                                                                                                                                                                          |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``power(a, b)``                                                     | ``a**b``                                                                                                                                                                                                                                                                                                                                                             |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``product(a, axis=0, fill_value=1)``                                | Product of elements along axis using ``fill_value`` for missing elements.                                                                                                                                                                                                                                                                                            |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``repeat(ar, repeats, axis=0)``                                     | Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element.                                                                                                                                                                                                       |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``set_default_fill_value(value_type, value)``                       | Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array.                                                                                                                                                                    |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``sort(ar, axis=-1)``                                               | Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values.                                                                                                                                                                                                                                                       |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``sum(a, axis=0, fill_value=0)``                                    | Sum of elements along a certain axis using ``fill_value`` for missing.                                                                                                                                                                                                                                                                                               |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``take(a, indices, axis=0)``                                        | Return a selection of items from ``a``. See the documentation in the Numeric manual.                                                                                                                                                                                                                                                                                 |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``transpose(ar, axes=None)``                                        | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes.                                                                                                                                                                                                                                |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``where(condition, x, y)``                                          | ``x`` where ``condition`` is true, ``y`` otherwise                                                                                                                                                                                                                                                                                                                   |
++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
-regrid (togrid, missing=None, order=None, Variable mask=None)
 
-.. raw:: html
+2.10 HorizontalGrid
+^^^^^^^^^^^^^^^^^^^
 
-   
+A HorizontalGrid represents a latitude-longitude coordinate system. In +addition, it optionally describes how lat-lon space is partitioned into +cells. Specifically, a HorizontalGrid: -:: +- consists of a latitude and longitude coordinate axis. +- may have associated boundary arrays describing the grid cell + boundaries, +- may optionally have an associated logical mask. -
-

Return the variable regridded to the horizontal grid togrid.

-

missing is a Float specifying the missing data value. The default - is 1.0e20.

+Table 2.28 -

order is a string indicating the order of dimensions of the - array. It has the form returned from variable.getOrder(). For - example, the string "tzyx" indicates that the dimension order of array is (time, - level, latitude, longitude). If unspecified, the function assumes that the last - two dimensions of array match the input grid.

++-------------------+----------------------------------------------------------------------------------+ +| Grid Type | Definition | ++===================+==================================================================================+ +| ``RectGrid`` | Associated latitude an longitude are 1-D axes, with strictly monotonic values. | ++-------------------+----------------------------------------------------------------------------------+ +| ``CurveGrid`` | Latitude and longitude are 2-D coordinate axes (Axis2D). | ++-------------------+----------------------------------------------------------------------------------+ +| ``GenericGrid`` | Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D) | ++-------------------+----------------------------------------------------------------------------------+ -

mask is a Numeric array, of datatype Integer or Float, consisting - of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data - value is to be ignored for purposes of regridding. If mask is two-dimensional of - the same shape as the input grid, it overrides the mask of the input grid. If the - mask has more than two dimensions, it must have the same shape as array. In this - case, the missing data value is also ignored. Such an n-dimensional mask is - useful if the pattern of missing data varies with level (e.g., ocean data) or - time. Note: If neither missing or mask is set, the default mask is obtained from - the mask of the array if any.

-

See also: crossSectionRegrid, pressureRegrid.

-
NonesetAxis(n, axis)Set the n-th axis (0-origin index) of to a copy of axis.
NonesetAxisList(axislist)Set all axes of the variable. axislist is a list of axis objects.
NonesetMissing(value)Set the missing value.
Integersize()Number of elements of the variable.
Variable -
+Variables support arithmetic operations, including the basic Python
+operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations
+defined in the MV module. The result of an arithmetic operation is a
+transient variable, that is, the axis information is transferred to the
+result.
 
-subRegion(\*region, time=None, level=None, latitude=None,
-longitude=None, squeeze=0, raw=0)
+The methods subRegion and subSlice return transient variables. In
+addition, a transient variable may be created with the
+cdms.createVariable method. The vcs and regrid module methods take
+advantage of the attribute, domain, and mask information in a transient
+variable.
 
-.. raw:: html
 
-   
+Table 2.33 Variable Internal Attributes -:: ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Definition | ++=======================+======================+=============================================================================================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``id`` | Variable identifier. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``name\_in\_file`` | The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the variable. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Tuple | ``shape`` | The length of each axis of the variable | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -
-

Read a coordinate region of data, returning a transient variable. A region is - a hyperrectangle in coordinate space.

+Table 2.34 Variable Constructors -

region is an argument list, each item of which specifies an - interval of a coordinate axis. The intervals are listed in the order of the - variable axes. If trailing dimensions are omitted, all values of those dimensions - are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is - specified (see below), then data will be read with wraparound in that dimension. - Only one axis may be read with wraparound. A coordinate interval has one of the - forms listed in Table 2.37 on page 102. Also see - axis.mapIntervalExt.

++--------------------------------------+--------------------------------------+ +| Constructor | Description | ++======================================+======================================+ +| ``Dataset.createVariable(String id, | Create a Variable in a Dataset. This | +| String datatype, List axes)`` | function is not yet implemented. | ++--------------------------------------+--------------------------------------+ +| ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | +| String datatype, List axesOr- | ``id`` is the name of the variable. | +| Grids)`` | ``datatype`` is the MA or Numeric | +| | typecode, for example, MA.Float. | +| | ``axesOrGrids`` is a list of Axis | +| | and/or Grid objects, on which the | +| | variable is defined. Specifying a | +| | rectilinear grid is equivalent to | +| | listing the grid latitude and | +| | longitude axes, in the order defined | +| | for the grid. \*\*Note:\*\* this | +| | argument can either be a list or a | +| | tuple. If the tuple form is used, | +| | and there is only one element, it | +| | must have a following comma, e.g.: | +| | ``(axisobj,)``. | ++--------------------------------------+--------------------------------------+ +| :: | Create a transient variable, not | +| | associated with a file or dataset. | +| cdms.createVariable(array, typec | ``array`` is the data values: a | +| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numeric | +| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MA | +| s=None,attributes=None, id=None) | typecode of the array. Defaults to | +| | the typecode of array. ``copy`` is | +| | an integer flag: if 1, the variable | +| | is created with a copy of the array, | +| | if 0 the variable data is shared | +| | with array. ``savespace`` is an | +| | integer flag: if set to 1, internal | +| | Numeric operations will attempt to | +| | avoid silent upcasting. ``mask`` is | +| | an array of integers with value 0 or | +| | 1, having the same shape as array. | +| | array elements with a corresponding | +| | mask value of 1 are considered | +| | invalid, and are not used for | +| | subsequent Numeric operations. The | +| | default mask is obtained from array | +| | if present, otherwise is None. | +| | ``fill_value`` is the missing value | +| | flag. The default is obtained from | +| | array if possible, otherwise is set | +| | to 1.0e20 for floating point | +| | variables, 0 for integer-valued | +| | variables. ``grid`` is a rectilinear | +| | grid object. ``axes`` is a tuple of | +| | axis objects. By default the axes | +| | are obtained from array if present. | +| | Otherwise for a dimension of length | +| | n, the default axis has values [0., | +| | 1., ..., double(n)]. ``attributes`` | +| | is a dictionary of attribute values. | +| | The dictionary keys must be strings. | +| | By default the dictionary is | +| | obtained from array if present, | +| | otherwise is empty. ``id`` is the | +| | string identifier of the variable. | +| | By default the id is obtained from | +| | array if possible, otherwise is set | +| | to 'variable\_n' for some integer n. | ++--------------------------------------+--------------------------------------+ -

The optional keyword arguments time, level, - latitude, and longitude may also be used to specify the - dimension for which the interval applies. This is particularly useful if the - order of dimensions is not known in advance. An exception is raised if a keyword - argument conflicts with a positional region argument.

-

The optional keyword argument squeeze determines whether or not - the shape of the returned array contains dimensions whose length is 1; by default - this argument is 0, and such dimensions are not 'squeezed out'.

-

The optional keyword argument raw specifies whether the return - object is a variable or a masked array. By default, a transient variable is - returned, having the axes and attributes corresponding to2,3 the region read. If - raw=1, an MA masked array is returned, equivalent to the transient variable - without the axis and attribute information.

-
Variable -
+**Example:** Get a region of data.
 
-subSlice(\*specs, time=None, level=None, latitude=None, longitude=None,
-squeeze=0, raw=0)
+Variable ta is a function of (time, latitude, longitude). Read data
+corresponding to all times, latitudes -45.0 up to but not
+including+45.0, longitudes 0.0 through and including longitude 180.0:
 
 .. raw:: html
 
-   
+
:: -
-

Read a slice of data, returning a transient variable. This is a functional - form of the slice operator [] with the squeeze option turned off.

- -

specs is an argument list, each element of which specifies a - slice of the corresponding dimension. There can be zero or more positional - arguments, each of the form:

- -
    -
  • a single integer n, meaning slice(n, n+1)
  • - -
  • an instance of the slice class
  • + data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) -
  • a tuple, which will be used as arguments to create a slice
  • - -
  • ':', which means a slice covering that entire dimension
  • +.. raw:: html -
  • Ellipsis (...), which means to fill the slice list with ':' leaving only - enough room at the end for the remaining positional arguments
  • + -
  • a Python slice object, of the form slice(i,j,k)
  • -
+or equivalently: -

If there are fewer slices than corresponding dimensions, all values of the - trailing dimensions are read.

+.. raw:: html -

The keyword arguments are defined as in subRegion.

+
-

There must be no conflict between the positional arguments and the - keywords.

+:: -

In (a)-(c) and (f), negative numbers are treated as offsets from - the end of that dimension, as in normal Python indexing.

-
Stringtypecode()The Numeric datatype identifier.
- -**Example:** Get a region of data. +
-Variable ta is a function of (time, latitude, longitude). Read data -corresponding to all times, latitudes -45.0 up to but not -including+45.0, longitudes 0.0 through and including longitude 180.0: +:: -{% highlight python %} data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, -180.0)) {% endhighlight %} + data = ta.subRegion(time=('1980-3','1980-4','co')) -or equivalently: +.. raw:: html -{% highlight python %} data = ta.subRegion(latitude=(-45.0,45.0,'co'), -longitude=(0.0, 180.0) {% endhighlight %} +
-Read all data for March, 1980: -{% highlight python %} data = -ta.subRegion(time=('1980-3','1980-4','co')) {% endhighlight %} Table 2.36 Variable Slice Operators - +-------------------+---------------------------------------------------------------+ | Operator | Description | @@ -7902,303 +3200,119 @@ Table 2.36 Variable Slice Operators +-------------------+---------------------------------------------------------------+ | ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | +-------------------+---------------------------------------------------------------+ -| ``[-1]`` | Negative indices 'wrap around'. -1 is the last element | +| ``[-1]`` | Negative indices ‘wrap around’. -1 is the last element | +-------------------+---------------------------------------------------------------+ + + Table 2.37 Index and Coordinate Intervals - - -+------+------+------+ -| Inte | Exam | Exam | -| rval | ple | ple | -| Defi | Inte | | -| niti | rval | | -| on | Defi | | -| | niti | | -| | on | | -+======+======+======+ -| ``x` | sing | ``18 | -| ` | le | 0.0` | -| | poin | `\ \ | -| | t, | ``c | -| | such | dtim | -| | that | e.re | -| | axis | ltim | -| | [i]= | e(48 | -| | =x | ,"ho | -| | In | ur s | -| | gene | sin | -| | ral | ce 1 | -| | x is | 980- | -| | a | 1")` | -| | scal | `\ \ | -| | ar. | ``' | -| | If | 1980 | -| | the | -1-3 | -| | axis | '`` | -| | is a | | -| | time | | -| | axis | | -| | , | | -| | x | | -| | may | | -| | also | | -| | be a | | -| | cdti | | -| | me | | -| | rela | | -| | tive | | -| | time | | -| | type | | -| | , | | -| | comp | | -| | onen | | -| | t | | -| | time | | -| | type | | -| | , | | -| | or | | -| | stri | | -| | ng | | -| | of | | -| | the | | -| | form | | -| | 'yyy | | -| | y-mm | | -| | -dd | | -| | hh:m | | -| | i:ss | | -| | ' | | -| | (whe | | -| | re | | -| | trai | | -| | ling | | -| | fiel | | -| | ds | | -| | of | | -| | the | | -| | stri | | -| | ng | | -| | may | | -| | be | | -| | omit | | -| | ted. | | -+------+------+------+ -| ``(x | indi | ``(- | -| ,y)` | ces | 180, | -| ` | i | 180) | -| | such | `` | -| | that | | -| | x ≤ | | -| | axis | | -| | [i] | | -| | ≤ y | | -+------+------+------+ -| ``(x | ``x | ``(- | -| ,y,' | ≤ ax | 90,9 | -| co') | is[i | 0,'c | -| `` | ] < | c')` | -| | y``. | ` | -| | The | | -| | thir | | -| | d | | -| | item | | -| | is | | -| | defi | | -| | ned | | -| | as | | -| | in | | -| | mapI | | -| | nter | | -| | val. | | -+------+------+------+ -| ``(x | ``x | ``( | -| ,y,' | ≤ ax | 180, | -| co', | is[i | 180 | -| cycl | ]< y | , 'c | -| e)`` | ``, | o', | -| | with | 360. | -| | wrap | 0)`` | -| | arou | | -| | nd | | -| | **No | | -| | te:* | | -| | * | | -| | It | | -| | is | | -| | not | | -| | nece | | -| | sary | | -| | to | | -| | spec | | -| | ify | | -| | the | | -| | cycl | | -| | e | | -| | of a | | -| | circ | | -| | ular | | -| | long | | -| | itud | | -| | e | | -| | axis | | -| | , | | -| | that | | -| | is, | | -| | for | | -| | whic | | -| | h | | -| | ``ax | | -| | is.i | | -| | sCir | | -| | cula | | -| | r()` | | -| | ` | | -| | is | | -| | true | | -| | . | | -+------+------+------+ -| ``sl | slic | ``sl | -| ice( | e | ice( | -| i,j, | obje | 1,10 | -| k)`` | ct, | )``\ | -| | equi | \ ` | -| | vale | `sli | -| | nt | ce(, | -| | to | ,-1) | -| | i:j: | `` | -| | k | reve | -| | in a | rses | -| | slic | the | -| | e | dire | -| | oper | ctio | -| | ator | n | -| | . | of | -| | Refe | the | -| | rs | axis | -| | to | . | -| | the | | -| | indi | | -| | ces | | -| | i, | | -| | i+k, | | -| | i+2k | | -| | , | | -| | ... | | -| | up | | -| | to | | -| | but | | -| | not | | -| | incl | | -| | udin | | -| | g | | -| | inde | | -| | x | | -| | j. | | -| | If i | | -| | is | | -| | not | | -| | spec | | -| | ifie | | -| | d | | -| | or | | -| | is | | -| | None | | -| | it | | -| | defa | | -| | ults | | -| | to | | -| | 0. | | -| | If j | | -| | is | | -| | not | | -| | spec | | -| | ifie | | -| | d | | -| | or | | -| | is | | -| | None | | -| | it | | -| | defa | | -| | ults | | -| | to | | -| | the | | -| | leng | | -| | th | | -| | of | | -| | the | | -| | axis | | -| | . | | -| | The | | -| | stri | | -| | de | | -| | k | | -| | defa | | -| | ults | | -| | to | | -| | 1. k | | -| | may | | -| | be | | -| | nega | | -| | tive | | -| | . | | -+------+------+------+ -| ``': | all | | -| '`` | axis | | -| | valu | | -| | es | | -| | of | | -| | one | | -| | dime | | -| | nsio | | -| | n | | -+------+------+------+ -| ``El | all | | -| lips | valu | | -| is`` | es | | -| | of | | -| | all | | -| | inte | | -| | rmed | | -| | iate | | -| | axes | | -+------+------+------+ + ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| Interval Definition | Example Interval Definition | Example | ++========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ +| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | +| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | +| | | ``'1980-1-3'`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | +| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | +| | | ``slice(,,-1)`` reverses the direction of the axis. | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``':'`` | all axis values of one dimension |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``Ellipsis`` | all values of all intermediate axes |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ + + 2.11.1 Selectors -'''''''''''''''' A selector is a specification of a region of data to be selected from a variable. For example, the statement -{% highlight python %} x = v(time='1979-1-1', level=(1000.0,100.0)) {% -endhighlight %} +.. raw:: html + +
+ +:: + + x = v(time='1979-1-1', level=(1000.0,100.0)) + +.. raw:: html -means 'select the values of variable v for time '1979-1-1' and levels -1000.0 to 100.0 inclusive, setting x to the result.' Selectors are +
+ +means ‘select the values of variable v for time ‘1979-1-1’ and levels +1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are generally used to represent regions of space and time. The form for using a selector is -{% highlight python %} result = v(s) {% endhighlight %} +.. raw:: html + +
+ +:: + + result = v(s) + +.. raw:: html + +
where v is a variable and s is the selector. An equivalent form is -{% highlight python %} result = f('varid', s) {% endhighlight %} +.. raw:: html + +
+ +:: + + result = f('varid', s) + +.. raw:: html -where f is a file or dataset, and 'varid' is the string ID of a +
+ +where f is a file or dataset, and ‘varid’ is the string ID of a variable. A selector consists of a list of selector components. For example, the selector -{% highlight python %} time='1979-1-1', level=(1000.0,100.0) {% -endhighlight %} +.. raw:: html + +
+ +:: + + time='1979-1-1', level=(1000.0,100.0) + +.. raw:: html -has two components: time='1979-1-1', and level=(1000.0,100.0). This +
+ +has two components: time=’1979-1-1’, and level=(1000.0,100.0). This illustrates that selector components can be defined with keywords, using the form: -{% highlight python %} keyword=value {% endhighlight %} +.. raw:: html + +
+ +:: + + keyword=value + +.. raw:: html + +
Note that for the keywords time, level, latitude, and longitude, the selector can be used with any variable. If the corresponding axis is not @@ -8211,180 +3325,51 @@ The following keywords are available: Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example: + + Table 2.38 Selector keywords - - -+------+------+------+ -| Keyw | Desc | Valu | -| ord | ript | e | -| | ion | | -+======+======+======+ -| ``ax | Rest | See | -| isid | rict | Tabl | -| `` | the | e | -| | axis | 2.37 | -| | with | on | -| | ID | page | -| | axis | 102 | -| | id | | -| | to a | | -| | valu | | -| | e | | -| | or | | -| | rang | | -| | e | | -| | of | | -| | valu | | -| | es. | | -+------+------+------+ -| ``gr | Regr | Grid | -| id`` | id | obje | -| | the | ct | -| | resu | | -| | lt | | -| | to | | -| | the | | -| | grid | | -| | . | | -+------+------+------+ -| ``la | Rest | See | -| titu | rict | Tabl | -| de`` | lati | e | -| | tude | 2.37 | -| | valu | on | -| | es | page | -| | to a | 102 | -| | valu | | -| | e | | -| | or | | -| | rang | | -| | e. | | -| | Shor | | -| | t | | -| | form | | -| | : | | -| | lat | | -+------+------+------+ -| ``le | Rest | See | -| vel` | rict | Tabl | -| ` | vert | e | -| | ical | 2.37 | -| | leve | on | -| | ls | page | -| | to a | 102 | -| | valu | | -| | e | | -| | or | | -| | rang | | -| | e. | | -| | Shor | | -| | t | | -| | form | | -| | : | | -| | lev | | -+------+------+------+ -| ``lo | Rest | See | -| ngit | rict | Tabl | -| ude` | long | e | -| ` | itud | 2.37 | -| | e | on | -| | valu | page | -| | es | 102 | -| | to a | | -| | valu | | -| | e | | -| | or | | -| | rang | | -| | e. | | -| | Shor | | -| | t | | -| | form | | -| | : | | -| | lon | | -+------+------+------+ -| ``or | Reor | Orde | -| der` | der | r | -| ` | the | stri | -| | resu | ng, | -| | lt. | e.g. | -| | | , | -| | | "tzy | -| | | x" | -+------+------+------+ -| ``ra | Retu | 0: | -| w`` | rn | retu | -| | a | rn | -| | mask | a | -| | ed | tran | -| | arra | sien | -| | y | t | -| | (MA. | vari | -| | arra | able | -| | y) | (def | -| | rath | ault | -| | er | ); | -| | than | =1: | -| | a | retu | -| | tran | rn | -| | sien | a | -| | t | mask | -| | vari | ed | -| | able | arra | -| | . | y. | -+------+------+------+ -| ``re | Requ | List | -| quir | ire | of | -| ed`` | that | axis | -| | the | iden | -| | axis | tifi | -| | IDs | ers. | -| | be | | -| | pres | | -| | ent. | | -+------+------+------+ -| ``sq | Remo | 0: | -| ueez | ve | leav | -| e`` | sing | e | -| | leto | sing | -| | n | leto | -| | dime | n | -| | nsio | dime | -| | ns | nsio | -| | from | ns | -| | the | (def | -| | resu | ault | -| | lt. | ); | -| | | 1: | -| | | remo | -| | | ve | -| | | sing | -| | | leto | -| | | n | -| | | dime | -| | | nsio | -| | | ns. | -+------+------+------+ -| ``ti | Rest | See | -| me`` | rict | Tabl | -| | time | e | -| | valu | 2.37 | -| | es | on | -| | to a | page | -| | valu | 10 | -| | e | | -| | or | | -| | rang | | -| | e. | | -+------+------+------+ + ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| Keyword | Description | Value | ++=================+======================================================================+============================================================================+ +| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``grid`` | Regrid the result to the grid. | Grid object | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``raw`` | Return a masked array (MA.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example: -{% highlight python %} x9 = hus(('1979-1-1','1979-2-1'),1000.0) {% -endhighlight %} +.. raw:: html + +
+ +:: + + x9 = hus(('1979-1-1','1979-2-1'),1000.0) + +.. raw:: html + +
-reads data for the range ('1979-1-1','1979-2-1') of the first axis, and +reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the form(s) listed in Table 2.37 on page 102 are treated as positional. Such selectors are more concise, but not as general or flexible as the other @@ -8395,129 +3380,191 @@ be defined and reused, independent of a particular variable. Selectors are constructed using the cdms.selectors.Selector class. The constructor takes an argument list of selector components. For example: -{% highlight python %} from cdms.selectors import Selector sel = -Selector(time=('1979-1-1','1979-2-1'), level=1000.) x1 = v1(sel) x2 = -v2(sel) {% endhighlight %} +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x1 = v1(sel) + x2 = v2(sel) + +.. raw:: html + +
For convenience CDMS provides several predefined selectors, which can be used directly or can be combined into more complex selectors. The selectors time, level, latitude, longitude, and required are equivalent to their keyword counterparts. For example: -{% highlight python %} from cdms import time, level x = -hus(time('1979-1-1','1979-2-1'), level(1000.)) {% endhighlight %} +.. raw:: html + +
+ +:: + + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + +.. raw:: html + +
and -{% highlight python %} x = hus(time=('1979-1-1','1979-2-1'), -level=1000.) {% endhighlight %} +.. raw:: html + +
+ +:: + + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + +.. raw:: html + +
are equivalent. Additionally, the predefined selectors ``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` take arguments ``(startindex, stopindex[, stride])``: -{% highlight python %} from cdms import timeslice, levelslice x = -v(timeslice(0,2), levelslice(16,17)) {% endhighlight %} +.. raw:: html + +
+ +:: + + from cdms import timeslice, levelslice + x = v(timeslice(0,2), levelslice(16,17)) + +.. raw:: html + +
Finally, a collection of selectors is defined in module cdutil.region: -{% highlight python %} from cdutil.region import \* -NH=NorthernHemisphere=domain(latitude=(0.,90.) -SH=SouthernHemisphere=domain(latitude=(-90.,0.)) -Tropics=domain(latitude=(-23.4,23.4)) -NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) -SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) {% endhighlight %} +.. raw:: html + +
+ +:: + + from cdutil.region import * + NH=NorthernHemisphere=domain(latitude=(0.,90.) + SH=SouthernHemisphere=domain(latitude=(-90.,0.)) + Tropics=domain(latitude=(-23.4,23.4)) + NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) + SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) + +.. raw:: html + +
Selectors can be combined using the & operator, or by refining them in the call: -{% highlight python %} from cdms.selectors import Selector from cdms -import level sel2 = Selector(time=('1979-1-1','1979-2-1')) sel3 = sel2 & -level(1000.0) x1 = hus(sel3) x2 = hus(sel2, level=1000.0) {% -endhighlight %} +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + from cdms import level + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x1 = hus(sel3) + x2 = hus(sel2, level=1000.0) + +.. raw:: html + +
+ + 2.11.2 Selector examples -'''''''''''''''''''''''' CDMS provides a variety of ways to select or slice data. In the following examples, variable hus is contained in file sample.nc, and is a function of (time, level, latitude, longitude). Time values are monthly starting at 1979-1-1. There are 17 levels, the last level being -1000.0. The name of the vertical level axis is 'plev'. All the examples +1000.0. The name of the vertical level axis is ‘plev’. All the examples select the first two times and the last level. The last two examples remove the singleton level dimension from the result array. -{% highlight python %} import cdms f = cdms.open('sample.nc') hus = -f.variables['hus'] - -Keyword selection -================= - -x = hus(time=('1979-1-1','1979-2-1'), level=1000.) +.. raw:: html -Interval indicator (see mapIntervalExt) -======================================= +
-x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) +:: -Axis ID (plev) as a keyword -=========================== + import cdms + f = cdms.open('sample.nc') + hus = f.variables['hus'] -x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + # Keyword selection + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) -Positional -========== + # Interval indicator (see mapIntervalExt) + x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) -x9 = hus(('1979-1-1','1979-2-1'),1000.0) + # Axis ID (plev) as a keyword + x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) -Predefined selectors -==================== + # Positional + x9 = hus(('1979-1-1','1979-2-1'),1000.0) -from cdms import time, level x = hus(time('1979-1-1','1979-2-1'), -level(1000.)) + # Predefined selectors + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) -from cdms import timeslice, levelslice x = hus(timeslice(0,2), -levelslice(16,17)) + from cdms import timeslice, levelslice + x = hus(timeslice(0,2), levelslice(16,17)) -Call file as a function -======================= + # Call file as a function + x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) -x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + # Python slices + x = hus(time=slice(0,2), level=slice(16,17)) -Python slices -============= + # Selector objects + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x = hus(sel) -x = hus(time=slice(0,2), level=slice(16,17)) + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x = hus(sel3) + x = hus(sel2, level=1000.0) -Selector objects -================ + # Squeeze singleton dimension (level) + x = hus[0:2,16] + x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) -from cdms.selectors import Selector sel = -Selector(time=('1979-1-1','1979-2-1'), level=1000.) x = hus(sel) + f.close() -sel2 = Selector(time=('1979-1-1','1979-2-1')) sel3 = sel2 & -level(1000.0) x = hus(sel3) x = hus(sel2, level=1000.0) +.. raw:: html -Squeeze singleton dimension (level) -=================================== +
-x = hus[0:2,16] x = hus(time=('1979-1-1','1979-2-1'), level=1000., -squeeze=1) -f.close() {% endhighlight %} 2.12 Examples ^^^^^^^^^^^^^ + 2.12.1 Example 1 -'''''''''''''''' +---------------- In this example, two datasets are opened, containing surface air -temperature ('tas') and upper-air temperature ('ta') respectively. +temperature (‘tas’) and upper-air temperature (‘ta’) respectively. Surface air temperature is a function of (time, latitude, longitude). Upper-air temperature is a function of (time, level, latitude, longitude). Time is assumed to have a relative representation in the -datasets (e.g., with units 'months since basetime'). +datasets (e.g., with units ‘months since basetime’). Data is extracted from both datasets for January of the first input year through December of the second input year. For each time and level, @@ -8525,210 +3572,357 @@ three quantities are calculated: slope, variance, and correlation. The results are written to a netCDF file. For brevity, the functions ``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. -{% highlight python %} 1. import cdms import MV - -:: +.. raw:: html - # Calculate variance, slope, and correlation of - # surface air temperature with upper air temperature - # by level, and save to a netCDF file. 'pathTa' is the location of - # the file containing 'ta', 'pathTas' is the file with contains 'tas'. - # Data is extracted from January of year1 through December of year2. - def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): +
- # Open the files for ta and tas - fta = cdms.open(pathTa) - ftas = cdms.open(pathTas) +:: -2. :: + 1. import cdms + import MV - #Get upper air temperature - taObj = fta['ta'] - levs = taObj.getLevel() + # Calculate variance, slope, and correlation of + # surface air temperature with upper air temperature + # by level, and save to a netCDF file. 'pathTa' is the location of + # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + # Data is extracted from January of year1 through December of year2. + def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): - #Get the surface temperature for the closed interval [time1,time2] - tas = ftas('tas', time=(month1,month2,'cc')) + # Open the files for ta and tas + fta = cdms.open(pathTa) + ftas = cdms.open(pathTas) - # Allocate result arrays - newaxes = taObj.getAxisList(omit='time') - newshape = tuple([len(a) for a in newaxes]) - cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') - b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') - v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + 2. #Get upper air temperature + taObj = fta['ta'] + levs = taObj.getLevel() - # Remove seasonal cycle from surface air temperature - tas = removeSeasonalCycle(tas) + #Get the surface temperature for the closed interval [time1,time2] + tas = ftas('tas', time=(month1,month2,'cc')) - # For each level of air temperature, remove seasonal cycle - # from upper air temperature, and calculate statistics + # Allocate result arrays + newaxes = taObj.getAxisList(omit='time') + newshape = tuple([len(a) for a in newaxes]) + cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') -3. :: + # Remove seasonal cycle from surface air temperature + tas = removeSeasonalCycle(tas) - for ilev in range(len(levs)): + # For each level of air temperature, remove seasonal cycle + # from upper air temperature, and calculate statistics + 5. for ilev in range(len(levs)): - ta = taObj(time=(month1,month2,'cc'), \ - level=slice(ilev, ilev+1), squeeze=1) - ta = removeSeasonalCycle(ta) - cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) - v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + ta = taObj(time=(month1,month2,'cc'), \ + level=slice(ilev, ilev+1), squeeze=1) + ta = removeSeasonalCycle(ta) + cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) - # Write slope, correlation, and variance variables + # Write slope, correlation, and variance variables + 6. f = cdms.open('CC_B_V_ALL.nc','w') + f.title = filtered + f.write(b) + f.write(cc) + f.write(v) + f.close() -4. :: + 7. if __name__=='__main__': + pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' + pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' + # Process Jan80 through Dec81 + ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') - f = cdms.open('CC_B_V_ALL.nc','w') - f.title = filtered - f.write(b) - f.write(cc) - f.write(v) - f.close() +.. raw:: html -5. if **name**\ =='**main**': pathTa = - '/pcmdi/cdms/sample/ccmSample\_ta.xml' pathTas = - '/pcmdi/cdms/sample/ccmSample\_tas.xml' - # Process Jan80 through Dec81 - ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') {% - endhighlight %} +
**Notes:** -1. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements +#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements arithmetic functions. -2. ``taObj`` is a file (persistent) variable. At this point, no data has +#. ``taObj`` is a file (persistent) variable. At this point, no data has actually been read. This happens when the file variable is sliced, or when the subRegion function is called. levs is an axis. -3. Calling the file like a function reads data for the given variable +#. Calling the file like a function reads data for the given variable and time range. Note that month1 and month2 are time strings. -4. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are +#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are transient variables, not associated with a file. The assigned names are used when the variables are written. -5. Another way to read data is to call the variable as a function. The +#. Another way to read data is to call the variable as a function. The squeeze option removes singleton axes, in this case the level axis. -6. Write the data. Axis information is written automatically. -7. This is the main routine of the script. ``pathTa`` and ``pathTas`` +#. Write the data. Axis information is written automatically. +#. This is the main routine of the script. ``pathTa`` and ``pathTas`` pathnames. Data is processed from January 1980 through December 1981. + + 2.12.2 Example 2 -'''''''''''''''' +---------------- In the next example, the pointwise variance of a variable over time is calculated, for all times in a dataset. The name of the dataset and variable are entered, then the variance is calculated and plotted via the vcs module. -{% highlight python %} #!/usr/bin/env python # # Calculates gridpoint -total variance # from an array of interest # +.. raw:: html + +
:: - import cdms - from MV import * + #!/usr/bin/env python + # + # Calculates gridpoint total variance + # from an array of interest + # + + import cdms + from MV import * + + # Wait for return in an interactive window + + def pause(): + print Hit return to continue: , + line = sys.stdin.readline() + + 1. # Calculate pointwise variance of variable over time + # Returns the variance and the number of points + # for which the data is defined, for each grid point + def calcVar(x): + # Check that the first axis is a time axis + firstaxis = x.getAxis(0) + if not firstaxis.isTime(): + raise 'First axis is not time, variable:', x.id + + n = count(x,0) + sumxx = sum(x*x) + sumx = sum(x) + variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + + return variance, n + + if __name__=='__main__': + import vcs, sys + + print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + path = string.strip(sys.stdin.readline()) + if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + + 2. # Open the dataset + dataset = cdms.open(path) + + # Select a variable from the dataset + print 'Variables in file:',path + varnames = dataset.variables.keys() + varnames.sort() + for varname in varnames: + + var = dataset.variables[varname] + if hasattr(var,'long_name'): + long_name = var.long_name + elif hasattr(var,'title'): + long_name = var.title + else: + long_name = '?' + + print '%-10s: %s'%(varname,long_name) + print 'Select a variable: ', + 3. varname = string.strip(sys.stdin.readline()) + var = dataset(varname) + dataset.close() + + # Calculate variance, count, and set attributes + variance,n = calcVar(var) + variance.id = 'variance_%s'%var.id + n.id = 'count_%s'%var.id + if hasattr(var,'units'): + variance.units = '(%s)^2'%var.units + + # Plot variance + w=vcs.init() + 4. w.plot(variance) + pause() + w.clear() + w.plot(n) + pause() + w.clear() + +.. raw:: html + +
- # Wait for return in an interactive window +The result of running this script is as follows: - def pause(): - print Hit return to continue: , - line = sys.stdin.readline() +.. raw:: html -1. :: +
- # Calculate pointwise variance of variable over time - # Returns the variance and the number of points - # for which the data is defined, for each grid point - def calcVar(x): - # Check that the first axis is a time axis - firstaxis = x.getAxis(0) - if not firstaxis.isTime(): - raise 'First axis is not time, variable:', x.id +:: - n = count(x,0) - sumxx = sum(x*x) - sumx = sum(x) - variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + % calcVar.py + Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: - return variance, n + Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml + albt : Albedo TOA [%] + albtcs : Albedo TOA clear sky [%] + rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] + rlut : LW radiation TOA (OLR) [W/m^2] + rlutcs : LW radiation upward TOA clear sky [W/m^2] + rscrft : SW Cloud Radiation Forcing TOA [W/m^2] + rsdt : SW radiation downward TOA [W/m^2] + rsut : SW radiation upward TOA [W/m^2] + rsutcs : SW radiation upward TOA clear sky [W/m^2] + Select a variable: albt - if __name__=='__main__': - import vcs, sys + - print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', - path = string.strip(sys.stdin.readline()) - if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + Hit return to continue: -2. :: + - # Open the dataset - dataset = cdms.open(path) +.. raw:: html - # Select a variable from the dataset - print 'Variables in file:',path - varnames = dataset.variables.keys() - varnames.sort() - for varname in varnames: +
- var = dataset.variables[varname] - if hasattr(var,'long_name'): - long_name = var.long_name - elif hasattr(var,'title'): - long_name = var.title - else: - long_name = '?' +**Notes:** - print '%-10s: %s'%(varname,long_name) - print 'Select a variable: ', +#. n = count(x, 0) returns the pointwise number of valid values, summing + across axis 0, the first axis. count is an MV function. +#. dataset is a Dataset or CdmsFile object, depending on whether a .xml + or .nc pathname is entered. dataset.variables is a dictionary mapping + variable name to file variable. +#. var is a transient variable. +#. Plot the variance and count variables. Spatial longitude and latitude + information are carried with the computations, so the continents are + plotted correctly. -3. :: +.. raw:: html - varname = string.strip(sys.stdin.readline()) - var = dataset(varname) - dataset.close() +
- # Calculate variance, count, and set attributes - variance,n = calcVar(var) - variance.id = 'variance_%s'%var.id - n.id = 'count_%s'%var.id - if hasattr(var,'units'): - variance.units = '(%s)^2'%var.units +`Previous `__ `Table of +Contents `__ +`Next `__ - # Plot variance - w=vcs.init() +.. raw:: html -4. :: +
- w.plot(variance) - pause() - w.clear() - w.plot(n) - pause() - w.clear() +.. raw:: html - {% endhighlight %} + -The result of running this script is as follows: +.. raw:: html -{% highlight pycon %} % calcVar.py Enter dataset path -[/pcmdi/cdms/sample/obs/erbs\_mo.xml]: +
-Variables in file: /pcmdi/cdms/sample/obs/erbs\_mo.xml albt : Albedo TOA -[%] albtcs : Albedo TOA clear sky [%] rlcrft : LW Cloud Radiation -Forcing TOA [W/m^2] rlut : LW radiation TOA (OLR) [W/m^2] rlutcs : LW -radiation upward TOA clear sky [W/m^2] rscrft : SW Cloud Radiation -Forcing TOA [W/m^2] rsdt : SW radiation downward TOA [W/m^2] rsut : SW -radiation upward TOA [W/m^2] rsutcs : SW radiation upward TOA clear sky -[W/m^2] Select a variable: albt +.. raw:: html -Hit return to continue: +
- {% endhighlight %} +.. raw:: html -**Notes:** +
+ +.. raw:: html + +
+ +Project Information + +- `Mission `__ +- `Governance `__ +- `Acknowledgements `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Contribute +^^^^^^^^^^ + +- `GitHub Project Page `__ +- `Wiki `__ +- `Report a Bug `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Press +^^^^^ + +- `Presentations `__ +- `Publications `__ +- `Reports `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Info +^^^^ + +- `Animations `__ +- `Design Documents `__ +- `Use Cases `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +.. raw:: html + +
+ +-------------- + +.. raw:: html + + + +.. raw:: html + +
+ +.. |image0| image:: /images/uvcdat.png + :class: logo + :target: / +.. |Diagram 1| image:: /images/diagram1.jpg -1. n = count(x, 0) returns the pointwise number of valid values, summing - across axis 0, the first axis. count is an MV function. -2. dataset is a Dataset or CdmsFile object, depending on whether a .xml - or .nc pathname is entered. dataset.variables is a dictionary mapping - variable name to file variable. -3. var is a transient variable. -4. Plot the variance and count variables. Spatial longitude and latitude - information are carried with the computations, so the continents are - plotted correctly. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst deleted file mode 100644 index 41a55a3b..00000000 --- a/docs/source/manual/cdms_3.rst +++ /dev/null @@ -1,659 +0,0 @@ -CHAPTER 3 cdtime Module ------------------------ - -3.1 Time types -^^^^^^^^^^^^^^ - -The ``cdtime`` module implements the CDMS time types, methods, and -calendars. These are made available with the command - -{% highlight python %} import cdtime {% endhighlight %} - -Two time types are available: relative time and component time. Relative -time is time relative to a fixed base time. It consists of: - -- a units string, of the form 'units since basetime', and -- a floating-point value - -For example, the time "28.0 days since 1996-1-1" has value=28.0, and -units='days since 1996-1-1' - -Component time consists of the integer fields year, month, day, hour, -minute, and the floating-point field second. A sample component time is -``1996-2-28 12:10:30.0`` - -The ``cdtime`` module contains functions for converting between these -forms, based on the common calendars used in climate simulation. Basic -arithmetic and comparison operators are also available. - -3.2 Calendars -^^^^^^^^^^^^^ - -A calendar specifies the number of days in each month, for a given year. -cdtime supports these calendars: - -- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap - years, except century years not evenly divisible by 400. This is - sometimes called the proleptic Gregorian calendar, meaning that the - algorithm for leap years applies for all years. -- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates - before 158210-15 are encoded with the Julian calendar, otherwise are - encoded with the Gregorian calendar. The day immediately following - 1582-10-4 is 1582-10-15. This is the default calendar. -- ``cdtime.JulianCalendar``: years evenly divisible by four are leap - years, -- ``cdtime.NoLeapCalendar``: all years have 365 days, -- ``cdtime.Calendar360``: all months have 30 days. - -Several ``cdtime`` functions have an optional calendar argument. The -default calendar is the ``MixedCalendar``. The default calendar may be -changed with the command: - -{% highlight python %} cdtime.DefaultCalendar = newCalendar {% -endhighlight %} - -3.3 Time Constructors -^^^^^^^^^^^^^^^^^^^^^ - -The following table describes the methods for creating time types. - -Table 3.1 Time Constructors - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - -.. raw:: html - - - -.. raw:: html - -
TypeConstructorDefinition
Reltimecdtime.reltime(value, relunits) -

Create a relative time type.

- -

value is an integer or floating point value.

- -

relunits is a string of the form "unit(s) [since - basetime]" where

- -

unit = [second | minute | hour | day | week | month | season | - year]

- -

basetime has the form yyyy-mm-dd hh:mi:ss. The - default basetime is 1979-1-1, if no since clause is specified.

- -

Example:

- -

r = cdtime.reltime(28, "days since 1996-1-1")

-
Comptimecdtime.comptime(year, month=1, day=1, hour=0, minute=0, - second=0.0) -

Create a component time type.

- -

year is an integer.

- -

month is an integer in the range 1 .. 12

- -

day is an integer in the range 1 .. 31

- -

hour is an integer in the range 0 .. 23

- -

minute is an integer in the range 0 .. 59

- -

second is a floating point number in the range 0.0 ,, 60.0

- -

Example:

- -

c = cdtime.comptime(1996, 2, 28)

-
Comptime -

[Deprecated] cdtime.abstime(absvalue, - absunits)

-
-

Create a component time from an absolute time representation.

- -

absvalue is a floating-point encoding of an absolute time.

- -

absunits is the units template, a string of the form "unit - as format", where unit is one of second, minute, hour, - day, calendar_month, or calendar_year. format is - a string ofthe form "%x[%x[...] ][.%f]", where 'x' is - one of the formatletters 'Y' (year, including century), - 'm' (two digit month,01=January), 'd' (two-digit day - within month), 'H' (hourssince midnight), 'M' - (minutes), or 'S' (seconds ). The optional '.%f' - denotes a floating-point fraction of the unit.

- -

Example:

- -

c = cdtime.abstime(19960228.0, "day as %Y%m%d.%f")

-
- -3.4 Relative Time -^^^^^^^^^^^^^^^^^ - -A relative time type has two members, value and units. Both can be set. - -Table 3.2 Relative Time Members - - -+----------+---------+-------------------------------------------------------+ -| Type | Name | Summary | -+==========+=========+=======================================================+ -| Float | value | Number of units | -+----------+---------+-------------------------------------------------------+ -| String | units | Relative units, of the form "unit(s) since basetime | -+----------+---------+-------------------------------------------------------+ - -3.5 Component Time -^^^^^^^^^^^^^^^^^^ - -A component time type has six members, all of which are settable. - -Table 3.3 Component Time Membersch3\_cdms\_4.0.html/#Table\_3.1 - - -+-----------+----------+--------------------------------------+ -| Type | Name | Summary | -+===========+==========+======================================+ -| Integer | year | Year value | -+-----------+----------+--------------------------------------+ -| Integer | month | Month, in the range 1..12 | -+-----------+----------+--------------------------------------+ -| Integer | day | Day of month, in the range 1 .. 31 | -+-----------+----------+--------------------------------------+ -| Integer | hour | Hour, in the range 0 .. 23 | -+-----------+----------+--------------------------------------+ -| Integer | minute | Minute, in the range 0 .. 59 | -+-----------+----------+--------------------------------------+ -| Float | second | Seconds, in the range 0.0 .. 60.0 | -+-----------+----------+--------------------------------------+ - -3.6 Time Methods -^^^^^^^^^^^^^^^^ - -The following methods apply both to relative and component times. - -Table 3.4 Time Methods - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - - - - .. raw:: html - -
TypeMethodDefinitionExamples
Comptime or Reltimet.add(value, intervalUnits, calendar=cdtime.Default-Calendar) -

Add an interval of time to a time type t. Returns the same type of time.

-

value is the Float number of interval units.

-

intervalUnits is

cdtime.[Second(s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]
-

calendar is the calendar type.

-
-
-
-            from cdtime import \* c = comptime(1996,2,28) r =
-            reltime(28,"days since 1996-1-1") print r.add(1,Day) 29.00
-            days since 1996-1-1 print c.add(36,Hours) 1996-2-29 12:0:0.0
-
-            .. raw:: html
-
-               
- - .. raw:: html - -

- - Note: When adding or subtracting intervals of months or - years, only the month and year of the result are - significant. The reason is that intervals in months/years - are not commensurate with intervals in days or fractional - days. This leads to results that may be surprising. For - example: - - .. raw:: html - -

- - .. raw:: html - -
-               c = comptime(1979,8,31)
-               c.add(1,Month)
-               1979-9-1 0:0:0.0
- - .. raw:: html - -

- - In other words, the day component of c was ignored in the - addition, and the day/hour/minute components of the results - are just the defaults. If the interval is in years, the - interval is converted internally to months: - - .. raw:: html - -

- - .. raw:: html - -
-               c = comptime(1979,8,31)
-               c.add(2,Years)
-               1981-8-1 0:0:0.0
- - .. raw:: html - -
- - Integer - - .. raw:: html - - - - t.cmp(t2, calendar=cdtime.DefaultCalendar) - - .. raw:: html - - - - .. raw:: html - -

- - Compare time values t and t2. Returns -1, 0, 1 as t is less than, - equal to, or greater than t2 respectively. - - .. raw:: html - -

- - .. raw:: html - -

- - t2 is the time to compare. - - .. raw:: html - -

- - .. raw:: html - -

- - calendar is the calendar type. - - .. raw:: html - -

- - .. raw:: html - -
- - .. raw:: html - -
>>> from cdtime import *
-       >> r = cdtime.reltime(28,"days since 1996-1-1")
-       >> c = comptime(1996,2,28)
-       >> print r.cmp(c)
-       -1
-       >> print c.cmp(r)
-       1
-       >> print r.cmp(r)
-       0
- - .. raw:: html - -
- - Comptime or Reltime - - .. raw:: html - - - - t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar) - - .. raw:: html - - - - .. raw:: html - -

- - Subtract an interval of time from a time type t. Returns the same - type of time. - - .. raw:: html - -

- - .. raw:: html - -

- - value is the Float number of interval units. - - .. raw:: html - -

- - .. raw:: html - -

- - intervalUnits is - - .. raw:: html - -

- - .. raw:: html - -
cdtime.[Second(s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]
- - .. raw:: html - -

- - calendar is the calendar type. - - .. raw:: html - -

- - .. raw:: html - -
- - .. raw:: html - -
>>> from cdtime import *
-       >> r = cdtime.reltime(28,"days since 1996-1-1")
-       >> c = comptime(1996,2,28)
-       >> print r.sub(10,Days)
-       18.00 days since 1996-1-1
-       >> print c.sub(30,Days)
-       1996-1-29 0:0:0.0
- - .. raw:: html - -

- - For intervals of years or months, see the note under add(). - - .. raw:: html - -

- - .. raw:: html - -
- - Comptime - - .. raw:: html - - - - t.tocomp(calendar = cdtime.DefaultCalendar) - - .. raw:: html - - - - .. raw:: html - -

- - Convert to component time. Returns the equivalent component time. - - .. raw:: html - -

- - .. raw:: html - -

- - calendar is the calendar type. - - .. raw:: html - -

- - .. raw:: html - -
- - .. raw:: html - -
>>> r = cdtime.reltime(28,"days since 1996-1-1")
-       >> r.tocomp()
-       1996-1-29 0:0:0.0
- - .. raw:: html - -
- - Reltime - - .. raw:: html - - - - t.torel(units, calendar=cdtime.DefaultCalendar) - - .. raw:: html - - - - Convert to relative time. Returns the equivalent relative time. - - .. raw:: html - - - - .. raw:: html - -
>>> c = comptime(1996,2,28)
-       >> print c.torel("days since 1996-1-1")
-       58.00 days since 1996-1-1
-       >> r = reltime(28,"days since 1996-1-1")
-       >> print r.torel("days since 1995")
-       393.00 days since 1995
-       >> print r.torel("days since 1995").value
-       393.0
- - .. raw:: html - -
diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst deleted file mode 100644 index 1195379e..00000000 --- a/docs/source/manual/cdms_4.rst +++ /dev/null @@ -1,1282 +0,0 @@ -CHAPTER 4 Regridding Data -------------------------- - -4.1 Overview -~~~~~~~~~~~~ - -CDMS provides several methods for interpolating gridded data: - -- from one rectangular, lat-lon grid to another (CDMS regridder) -- between any two lat-lon grids (SCRIP regridder) -- from one set of pressure levels to another -- from one vertical (lat/level) cross-section to another vertical - cross-section. - -4.1.1 CDMS horizontal regridr -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The simplest method to regrid a variable from one rectangular, lat/lon -grid to another is to use the regrid function defined for variables. -This function takes the target grid as an argument, and returns the -variable regridded to the target grid: - -{% highlight python %} >>> import cdms >>> f = -cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') >>> rlsf = f('rls') # -Read the data >>> rlsf.shape (4, 48, 96) - - g = cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') rlsg - = g['rls'] # Get the file variable (no data read) outgrid = - rlsg.getGrid() # Get the target grid rlsnew = - rlsf.regrid(outgrid) rlsnew.shape (4, 46, 72) outgrid.shape - (46, 72) - -{% endhighlight %} - -A somewhat more efficient method is to create a regridder function. This -has the advantage that the mapping is created only once and can be used -for multiple arrays. Also, this method can be used with data in the form -of an MA.MaskedArray or Numeric array. The steps in this process are: - -1. Given an input grid and output grid, generate a regridder function. -2. Call the regridder function on a Numeric array, resulting in an array - defined on the output grid. The regridder function can be called with - any array or variable defined on the input grid. - -The following example illustrates this process. The regridder function -is generated at line 9, and the regridding is performed at line 10: - -{% highlight python %} 1 #!/usr/bin/env python 2 import cdms 3 from -regrid import Regridder 4 f = -cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') 5 rlsf = f['rls'] 6 -ingrid = rlsf.getGrid() 7 g = -cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') 8 outgrid = -g['rls'].getGrid() 9 regridfunc = Regridder(ingrid, outgrid) - -10 rlsnew = regridfunc(rlsf) 11 f.close() 12 g.close() {% endhighlight -%} - -Line Notes - -**2** Makes the CDMS module available. - -**3** Makes the Regridder class available from the regrid module. - -**4** Opens the input dataset. - -**5** Gets the variable object named 'rls'. No data is read. - -**6** Gets the input grid. - -**7** Opens a dataset to retrieve the output grid. - -**8** The output grid is the grid associated with the variable named -'rls' in dataset g. Just the grid is retrieved, not the data. - -**9** Generates a regridder function regridfunc. - -**10** Reads all data for variable rlsf, and calls the regridder -function on that data, resulting in a transient variable rlsnew. - -4.1.2 SCRIP horizontal regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To interpolate between grids where one or both grids is non-rectangular, -CDMS provides an interface to the SCRIP regridder package developed at -Los Alamos National Laboratory (http://climate.lanl.gov/Software/ -SCRIP). Figure 3 illustrates the process: - -1. Obtain or generate the source and target grids in SCRIP netCDF - format. A CDMS grid can be written to a netCDF file, in SCRIP format, - using the write-ScripGrid method. -2. Edit the input namelist file scrip\_in to reference the grids and - select the method of interpolation, either conservative, bilinear, - bicubic, or distance-weighted. See the SCRIP documentation for - detailed instructions. -3. Run the scrip executable to generate a remapping file containing the - transformation coefficients. -4. CDMS, open the remapping file and create a regridder function with - the readRegridder method. -5. Call the regridder function on the input variable, defined on the - source grid. The return value is the variable interpolated to the new - grid. Note that the variable may have more than two dimensions. Also - note that the input arguments to the regridder function depend on the - type of regridder. For example, the bicubic interpolation has - additional arguments for the gradients of the variable. - -.. figure:: /images/regridding.jpg - :alt: Regridding - - Regridding - -FIGURE 3. Regridding data with SCRIP - - -**Example:** - -Regrid data from a T42 to POP4/3 grid, using the first-order, -conservative interpolator. - -In this example: - -- The input grid is defined in remap\_grid\_T42.nc. -- The output grid is defined in remap\_grid\_POP43.nc. -- The input data is variable src\_array in file sampleT42Grid.nc. -- The file scrip\_in has contents: - -{% highlight text %} &remap\_inputs num\_maps = 1 - -| grid1\_file = 'remap\_grid\_T42.nc' grid2\_file = - 'remap\_grid\_POP43.nc' interp\_file1 = - 'rmp\_T42\_to\_POP43\_conserv.nc' interp\_file2 = - 'rmp\_POP43\_to\_T42\_conserv.nc' map1\_name = 'T42 to POP43 - Conservative Mapping' -| map2\_name = 'POP43 to T42 Conservative Mapping' map\_method = - 'conservative' normalize\_opt = 'frac' output\_opt = 'scrip' - restrict\_type = 'latitude' num\_srch\_bins = 90 luse\_grid1\_area = - .false. luse\_grid2\_area = .false. / {% endhighlight %} - -``num_maps`` specifies the number of mappings generated, either 1 or 2. -For a single mapping, ``grid1_file`` and ``grid2_file`` are the source -and target grid definitions, respectively. The ``map_method`` specifies -the type of interpolation, either 'conservative', 'bilinear', 'bicubic', -or 'distwgt' (distanceweighted). The remaining parameters are described -in the SCRIP documentation. - -Once the grids and input file are defined, run the scrip executable to -generate the remapping file 'rmp\_T42\_to\_POP43\_conserv.nc' - -{% highlight text %} % scrip Using latitude bins to restrict search. -Computing remappings between: T42 Gaussian Grid and POP 4/3 -Displaced-Pole T grid grid1 sweep grid2 sweep Total number of links = -63112 {% endhighlight %} - -Next, run UV-CDAT and create the regridder: - -{% highlight python %} # Import regrid package for regridder functions -import regrid, cdms # Read the regridder from the remapper file remapf = -cdms.open('rmp\_T42\_to\_POP43\_conserv.nc') regridf = -regrid.readRegridder(remapf) remapf.close() {% endhighlight %} - -Then read the input data and regrid: - -{% highlight python %} # Get the source variable f = -cdms.open('sampleT42Grid.nc') t42dat = f('src\_array') f.close() # -Regrid the source variable popdat = regridf(dat) {% endhighlight %} - -Note that ``t42dat`` can have rank greater than 2. The trailing -dimensions must match the input grid shape. For example, if ``t42dat`` -has shape (12, 64, 128), then the input grid must have shape (64,128). -Similarly if the variable had a generic grid with shape (8092,), the -last dimension of the variable would have length 8092. - -4.1.3 Pressure-level regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To regrid a variable which is a function of latitude, longitude, -pressure level, and (optionally) time to a new set of pressure levels, -use the ``pressureRegrid`` function defined for variables. This function -takes an axis representing the target set of pressure levels, and -returns a new variable ``d`` regridded to that dimension. - -{% highlight pycon %} >>> var.shape (3, 16, 32) >>> var.getAxisIds() -['level', 'latitude', 'longitude'] >>> len(levout) 2 >>> result = -var.pressureRegrid(levout) >>> result.shape (2, 16, 32) {% endhighlight -%} - -4.1.4 Cross-section regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To regrid a variable which is a function of latitude, height, and -(optionally) time to a new latitude/height cross-section, use the -``crossSectionRegridder`` defined for variables. This function takes as -arguments the new latitudes and heights, and returns the variable -regridded to those axes. - -{% highlight python %} >>> varin.shape (11, 46) >>> varin.getAxisIds() -[’level’, ’latitude’] >>> levOut[:][ 10., 30., 50., 70., 100., 200., -300., 400., 500., 700., 850., 1000.,] >>> varout = -varin.crossSectionRegrid(levOut, latOut) >>> varout.shape (12, 64) {% -endhighlight %} - -4.2 regrid module -~~~~~~~~~~~~~~~~~ - -The ``regrid`` module implements the CDMS regridding functionality as -well as the SCRIP interface. Although this module is not strictly a part -of CDMS, it is designed to work with CDMS objects. - -4.2.1 CDMS horizontal regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The Python command - -{% highlight python %} from regrid import Regridder {% endhighlight %} - -makes the CDMS Regridder class available within a Python program. An -instance of Regridder is a function which regrids data from rectangular -input to output grids. - -Table 4.1 CDMS Regridder Constructor - - -+------+------+ -| Cons | Desc | -| truc | ript | -| tor | ion | -+======+======+ -| regr | Crea | -| idFu | te | -| ncti | a | -| on | regr | -| = | idde | -| Regr | r | -| idde | func | -| r(in | tion | -| putG | whic | -| rid, | h | -| outp | inte | -| utGr | rpol | -| id) | ates | -| | a | -| | data | -| | arra | -| | y | -| | from | -| | inpu | -| | t | -| | to | -| | outp | -| | ut | -| | grid | -| | . | -| | `Tab | -| | le | -| | 4.3 | -| | <#Ta | -| | ble_ | -| | 4.3> | -| | `__ | -| | on | -| | page | -| | 131 | -| | desc | -| | ribe | -| | s | -| | the | -| | call | -| | ing | -| | sequ | -| | ence | -| | of | -| | this | -| | func | -| | tion | -| | . | -| | ``in | -| | putG | -| | rid` | -| | ` | -| | and | -| | ``ou | -| | tput | -| | Grid | -| | `` | -| | are | -| | CDMS | -| | grid | -| | obje | -| | cts. | -| | **No | -| | te:* | -| | * | -| | To | -| | set | -| | the | -| | mask | -| | asso | -| | ciat | -| | ed | -| | with | -| | inpu | -| | tGri | -| | d | -| | or | -| | outp | -| | utGr | -| | id, | -| | use | -| | the | -| | grid | -| | setM | -| | ask | -| | func | -| | tion | -| | . | -+------+------+ - -4.2.2 SCRIP Regridder -^^^^^^^^^^^^^^^^^^^^^ - -SCRIP regridder functions are created with the ``regrid.readRegridder`` -function: - -Table 4.2 SCRIP Regridder Constructor - - -.. raw:: html - - - -:: - - - - - - - - - - - - -.. raw:: html - -
ConstructorDescription
-
regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)
-
-

Read a regridder from an open CDMS file object.

-

fileobj is a CDMS file object, as returned from cdms.open.

-

mapMethod is one of

-
    -
  • 'conservative': conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved.
  • - -
  • 'bilinear': bilinear interpolation
  • - -
  • 'bicubic': bicubic interpolation
  • - -
  • 'distwgt': distance-weighted interpolation.
  • - -
- -

It is only necessary to specify the map method if it is not defined in the file.

-

If checkGridis 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.

- -4.3 Regridder Functions -~~~~~~~~~~~~~~~~~~~~~~~ - -It is only necessary to specify the map method if it is not defined in -the file. - -If ``checkGrid`` is 1 (default), the grid cells are checked for -convexity, and 'repaired' if necessary. Grid cells may appear to be -nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of -shifting the cell vertices to the same side modulo 360 degrees. - -4.3.1 CDMS regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A CDMS regridder function is an instance of the CDMS ``Regridder`` -class. The function is associated with rectangular input and output -grids. Typically its use is straightforward: the function is passed an -input array and returns the regridded array. However, when the array has -missing data, or the input and/or output grids are masked, the logic -becomes more complicated. - -Step 1: -''''''' - -The regridder function first forms an input mask. This mask is either -two-dimensional or n-dimensional, depending on the rank of the -user-supplied mask. If no mask or missing value is specified, the mask -is obtained from the data array mask if present. - -**Two-dimensional case:** - -- Let mask\_1 be the two-dimensional user mask supplied via the mask - argument, or the mask of the input grid if no user mask is specified. -- If a missing-data value is specified via the missing argument, let - the implicit\_mask be the two-dimensional mask defined as 0 where the - first horizontal slice of the input array is missing, 1 elsewhere. -- The input mask is the logical AND(mask\_1, implicit\_mask) - -**N-dimensional case:** - -- If the user mask is 3 or 4-dimensional with the same shape as the - input array, it is used as the input mask. - -Step 2: -''''''' - -The data is then regridded. In the two-dimensional case, the input mask -is 'broadcast' across the other dimensions of the array. In other words, -it assumes that all horizontal slices of the array have the same mask. -The result is a new array, defined on the output grid. Optionally, the -regridder function can also return an array having the same shape as the -output array, defining the fractional area of the output array which -overlaps a non-missing input grid cell. This is useful for calculating -area-weighted means of masked data. - -Step 3: -''''''' - -Finally, if the output grid has a mask, it is applied to the result -array. Where the output mask is 0, data values are set to the missing -data value, or 1.0e20 if undefined. The result array or transient -variable will have a mask value of 1 (invalid value) for those output -grid cells which completely overlap input grid cells with missing values - -Table 4.3 CDMS Regridder function - - -.. raw:: html - - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - -.. raw:: html - - - -.. raw:: html - -
TypeFunctionDescription
Array or Transient-VariableregridFunction(array, missing=None, order=None,mask=None) -

Interpolate a gridded data array to a new grid. The interpolation preserves the area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the input array is returned, otherwise a masked array is returned.

-

arrayis a Variable, masked array, or Numeric array of rank 2, 3, or 4.

-

For example, the string “tzyx” indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid.

-

missing is a Float specifying the missing data value. The default is 1.0e20.

-

order is a string indicating the order of dimensions of the array. It has the form returned from variable.getOrder().

-

mask is a Numeric array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MA module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the returnTuple argument.

-

If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. -

-

Array, Array

-
- regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1) - -

If called with the optional returnTuple argument equal to 1, the function returns a tuple (dataArray, maskArray).

-

dataArray is the result data array.

-

maskArray is a Float32 array of the same shape as dataArray, such that maskArray[i,j] is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid.

-
- -4.3.2 SCRIP Regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -A SCRIP regridder function is an instance of the ScripRegridder class. -Such a function is created by calling the regrid.readRegridder method. -Typical usage is straightforward: - -{% highlight pycon %} >>> regridf = regrid.readRegridder(remap\_file) ->>> outdat = regridf(indat) {% endhighlight %} - -The bicubic regridder takes four arguments: - -{% highlight pycon %} >>> outdat = regridf(indat, gradlat, gradlon, -gradlatlon) {% endhighlight %} - -A regridder function also has associated methods to retrieve the -following fields: - -- Input grid -- Output grid -- Source fraction: the fraction of each source (input) grid cell - participating in the interpolation. -- Destination fraction: the fraction of each destination (output) grid - cell participating in the interpolation. - -In addition, a conservative regridder has the associated grid cell areas -for source and target grids. - -Table 4.4 SCRIP Regridder functions - - -+------+------+------+ -| Retu | Meth | Desc | -| rn | od | ript | -| Type | | ion | -+======+======+======+ -| Arra | [con | Inte | -| y | serv | rpol | -| or | ativ | ate | -| Tran | e, | a | -| sien | bili | grid | -| t-Va | near | ded | -| riab | , | data | -| le | and | arra | -| | dist | y | -| | ance | to a | -| | -wei | new | -| | ghte | grid | -| | d | . | -| | regr | The | -| | idde | retu | -| | rs] | rn | -| | ``re | valu | -| | grid | e | -| | Func | is | -| | tion | the | -| | (arr | regr | -| | ay)` | idde | -| | ` | d | -| | | data | -| | | vari | -| | | able | -| | | . | -| | | ``ar | -| | | ray` | -| | | ` | -| | | is a | -| | | Vari | -| | | able | -| | | , | -| | | Mask | -| | | edAr | -| | | ray, | -| | | or | -| | | Nume | -| | | ric | -| | | arra | -| | | y. | -| | | The | -| | | rank | -| | | of | -| | | the | -| | | arra | -| | | y | -| | | may | -| | | be | -| | | grea | -| | | ter | -| | | than | -| | | the | -| | | rank | -| | | of | -| | | the | -| | | inpu | -| | | t | -| | | grid | -| | | , | -| | | in | -| | | whic | -| | | h | -| | | case | -| | | the | -| | | inpu | -| | | t | -| | | grid | -| | | shap | -| | | e | -| | | must | -| | | matc | -| | | h | -| | | a | -| | | trai | -| | | ling | -| | | port | -| | | ion | -| | | of | -| | | the | -| | | arra | -| | | y | -| | | shap | -| | | e. | -| | | For | -| | | exam | -| | | ple, | -| | | if | -| | | the | -| | | inpu | -| | | t | -| | | grid | -| | | is | -| | | curv | -| | | ilin | -| | | ear | -| | | with | -| | | shap | -| | | e | -| | | (64, | -| | | 128) | -| | | , | -| | | the | -| | | last | -| | | two | -| | | dime | -| | | nsio | -| | | ns | -| | | of | -| | | the | -| | | arra | -| | | y | -| | | must | -| | | matc | -| | | h. | -| | | Simi | -| | | larl | -| | | y, | -| | | if | -| | | the | -| | | inpu | -| | | t | -| | | grid | -| | | is | -| | | gene | -| | | ric | -| | | with | -| | | shap | -| | | e | -| | | (256 | -| | | 0,), | -| | | the | -| | | last | -| | | dime | -| | | nsio | -| | | n | -| | | of | -| | | the | -| | | arra | -| | | y | -| | | must | -| | | have | -| | | that | -| | | leng | -| | | th. | -+------+------+------+ - -\|Array or Transient-Variable\|[bicubic regridders] -``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``\ \| - -.. raw:: html - -

- -Interpolate a gridded data array to a new grid, using a bicubic -regridder. The return value is the regridded data variable. - -.. raw:: html - -

- -.. raw:: html - -

- -array is a Variable, MaskedArray, or Numeric array. The rank of the -array may be greater than the rank of the input grid, in which case the -input grid shape must match a trailing portion of the array shape. For -example, if the input grid is curvilinear with shape (64,128), the last -two dimensions of the array must match. Simiarly, if the input grid is -generic with shape (2560,), the last dimension of the array must have -that length. - -.. raw:: html - -

- -.. raw:: html - -

- -gradientLat: df/di (see the SCRIP documentation). Same shape as array. - -.. raw:: html - -

- -.. raw:: html - -

- -gradientLon: df/dj. Same shape as array. - -.. raw:: html - -

- -.. raw:: html - -

- -gradientLatLon: d(df)/(di)(dj). Same shape as array. - -.. raw:: html - -

- -\| \|Numeric array\|\ ``getDestinationArea()`` [conservative regridders -only]\|Return the area of the destination (output) grid cell. The array -is 1-D, with length equal to the number of cells in the output grid.\| -\|Numeric array\|\ ``getDestinationFraction()``\ \|Return the area -fraction of the destination (output) grid cell that participates in the -regridding. The array is 1-D, with length equal to the number of cells -in the output grid.\| \|CurveGrid or -Generic-Grid\|\ ``getInputGrid()``\ \|Return the input grid, or None if -no input grid is associated with the regridder.\| \|CurveGrid or -Generic-Grid\|\ ``getOutputGrid()``\ \|Return the output grid.\| -\|Numeric array\|\ ``getSourceArea()`` [conservative regridders -only]\|Return the area of the source (input) grid cell. The array is 1- -D, with length equal to the number of cells in the input grid.\| -\|Numeric array\|\ ``getSourceFraction()``\ \|Return the area fraction -of the source (input) grid cell that participates in the regridding. The -array is 1-D, with length equal to the number of cells in the input -grid\| - -4.4 Examples -~~~~~~~~~~~~ - -4.4.1 CDMS regridder -^^^^^^^^^^^^^^^^^^^^ - -**Example:** - -Regrid data to a uniform output grid. - -{% highlight python %} 1 #!/usr/local/bin/python 2 import cdms 3 from -regrid import Regridder 4 f = cdms.open('rls\_ccc\_per.nc') 5 rlsf = -f.variables['rls'] 6 ingrid = rlsf.getGrid() 7 outgrid = -cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) 8 regridFunc = -Regridder(ingrid, outgrid) 9 newrls = regridFunc(rlsf) 10 f.close() {% -endhighlight %} - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 4 | Open | -| | a | -| | netC | -| | DF | -| | file | -| | for | -| | inpu | -| | t. | -+------+------+ -| 7 | Crea | -| | te | -| | a 4 | -| | x 5 | -| | degr | -| | ee | -| | outp | -| | ut | -| | grid | -| | . | -| | Note | -| | that | -| | this | -| | grid | -| | is | -| | not | -| | asso | -| | ciat | -| | ed | -| | with | -| | a | -| | file | -| | or | -| | data | -| | set | -+------+------+ -| 8 | Crea | -| | te | -| | the | -| | regr | -| | idde | -| | r | -| | func | -| | tion | -+------+------+ -| 9 | Read | -| | all | -| | data | -| | and | -| | regr | -| | id. | -| | The | -| | miss | -| | ing | -| | data | -| | valu | -| | e | -| | is | -| | obta | -| | ined | -| | from | -| | vari | -| | able | -| | rlsf | -+------+------+ - -Return the area fraction of the source (input) grid cell that -participates in the regridding. The array is 1-D, with length equal to -the number of cells in the input grid. - -**Example:** - -Get a mask from a separate file, and set as the input grid mask. - -{% highlight python %} 1 import cdms 2 from regrid import Regridder 3 # -4 f = cdms.open('so\_ccc\_per.nc') 5 sof = f.variables['so'] 6 ingrid = -sof.getGrid() 7 g = cdms.open('rls\_mri\_per.nc') 8 rlsg = -g.variables['rls'] 9 outgrid = rlsg.getGrid() 10 regridFunc = -Regridder(ingrid,outgrid) 11 h = cdms.open('sft\_ccc.nc') 12 sfmaskvar = -h.variables['sfmask'] 13 sfmask = sfmaskvar[:] 14 outArray = -regridFunc(sof.subSlice(time=0),mask=sfmask) 15 f.close() 16 g.close() -17 h.close() {% endhighlight %} - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 6 | Get | -| | the | -| | inpu | -| | t | -| | grid | -| | . | -+------+------+ -| 9 | Get | -| | the | -| | outp | -| | ut | -| | grid | -+------+------+ -| 10 | Crea | -| | te | -| | the | -| | regr | -| | idde | -| | r | -| | func | -| | tion | -| | . | -+------+------+ -| 13 | Get | -| | the | -| | mask | -| | . | -+------+------+ -| 14 | Regr | -| | id | -| | with | -| | a | -| | user | -| | mask | -| | . | -| | The | -| | subs | -| | lice | -| | call | -| | retu | -| | rns | -| | a | -| | tran | -| | sien | -| | t | -| | vari | -| | able | -| | corr | -| | espo | -| | ndin | -| | g | -| | to | -| | vari | -| | able | -| | sof | -| | at | -| | time | -| | 0 | -+------+------+ - -**Note:** Although it cannot be determined from the code, both mask and -the input array sof are four-dimensional. This is the n-dimensional -case. - -**Example:** - -Generate an array of zonal mean values. - -1 f = cdms.open('rls\_ccc\_per.nc') 2 rlsf = f.variables['rls'] 3 ingrid -= rlsf.getGrid() 4 outgrid = cdms.createZonalGrid(ingrid) 5 regridFunc = -Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 3 | Get | -| | the | -| | inpu | -| | t | -| | grid | -| | . | -| | Retu | -| | rn | -| | the | -| | area | -| | frac | -| | tion | -| | of | -| | the | -| | sour | -| | ce | -| | (inp | -| | ut) | -| | grid | -| | cell | -| | that | -| | part | -| | icip | -| | ates | -| | in | -| | the | -| | regr | -| | iddi | -| | ng. | -| | The | -| | arra | -| | y | -| | is | -| | 1-D, | -| | with | -| | leng | -| | th | -| | equa | -| | l | -| | to | -| | the | -| | numb | -| | er | -| | of | -| | cell | -| | s | -| | in | -| | the | -| | inpu | -| | t | -| | grid | -| | . | -+------+------+ -| 4 | Crea | -| | te | -| | a | -| | zona | -| | l | -| | grid | -| | . | -| | outg | -| | rid | -| | has | -| | the | -| | same | -| | lati | -| | tude | -| | s | -| | as | -| | ingr | -| | id, | -| | and | -| | a | -| | sing | -| | leto | -| | n | -| | long | -| | itud | -| | e | -| | dime | -| | nsio | -| | n. | -| | crea | -| | teGl | -| | obal | -| | Mean | -| | Grid | -| | coul | -| | d | -| | be | -| | used | -| | here | -| | to | -| | gene | -| | rate | -| | a | -| | glob | -| | al | -| | mean | -| | arra | -| | y. | -+------+------+ -| 5 | Gene | -| | rate | -| | the | -| | regr | -| | idde | -| | r | -| | func | -| | tion | -| | . | -+------+------+ -| 6 | Gene | -| | rate | -| | the | -| | zona | -| | l | -| | mean | -| | arra | -| | y | -+------+------+ - -**Example:** - -Regrid an array with missing data, and calculate the area-weighted mean -of the result. - -{% highlight python %} 1 from cdms.MV import * ... 2 outgrid = -cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) 3 outlatw, outlonw -= outgrid.getWeights() 4 outweights = outerproduct(outlatw, outlonw) 5 -grid = var.getGrid() 6 sample = var[0,0] 7 latw, lonw = -grid.getWeights() 8 weights = outerproduct(latw, lonw) 9 inmask = -where(greater(absolute(sample),1.e15),0,1) 10 mean = -add.reduce(ravel(inmask*\ weights\ *sample))/ -add.reduce(ravel(inmask*\ weights)) 11 regridFunc = Regridder(grid, -outgrid) 12 outsample, outmask = regridFunc(sample, mask=inmask, -returnTuple=1) 13 outmean = -add.reduce(ravel(outmask\ *outweights*\ outsample)) / -add.reduce(ravel(outmask\*outweights)) {% endhighlight %} - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 2 | Crea | -| | te | -| | a | -| | unif | -| | orm | -| | targ | -| | et | -| | grid | -| | . | -+------+------+ -| 3 | Get | -| | the | -| | lati | -| | tude | -| | and | -| | long | -| | itud | -| | e | -| | weig | -| | hts. | -+------+------+ -| 4 | Gene | -| | rate | -| | a | -| | 2-D | -| | weig | -| | hts | -| | arra | -| | y. | -+------+------+ -| 5 | Get | -| | the | -| | inpu | -| | t | -| | grid | -| | . | -| | ``va | -| | r`` | -| | is a | -| | 4-D | -| | vari | -| | able | -| | . | -+------+------+ -| 6 | Get | -| | the | -| | firs | -| | t | -| | hori | -| | zont | -| | al | -| | slic | -| | e | -| | from | -| | ``va | -| | r``. | -+------+------+ -| 7-8 | Get | -| | the | -| | inpu | -| | t | -| | weig | -| | hts, | -| | and | -| | gene | -| | rate | -| | a | -| | 2-D | -| | weig | -| | hts | -| | arra | -| | y. | -+------+------+ -| 9 | Set | -| | the | -| | 2-D | -| | inpu | -| | t | -| | mask | -| | . | -+------+------+ -| 10 | Calc | -| | ulat | -| | e | -| | the | -| | inpu | -| | t | -| | arra | -| | y | -| | area | -| | -wei | -| | ghte | -| | d | -| | mean | -| | . | -+------+------+ -| 11 | Crea | -| | te | -| | the | -| | regr | -| | idde | -| | r | -| | func | -| | tion | -| | . | -+------+------+ -| 12 | Regr | -| | id. | -| | Beca | -| | use | -| | retu | -| | rnTu | -| | ple | -| | is | -| | set | -| | to | -| | 1, | -| | the | -| | resu | -| | lt | -| | is a | -| | tupl | -| | e | -| | (dat | -| | aArr | -| | ay, | -| | mask | -| | Arra | -| | y). | -+------+------+ -| 13 | Calc | -| | ulat | -| | e | -| | the | -| | area | -| | -wei | -| | ghte | -| | d | -| | mean | -| | of | -| | the | -| | regr | -| | idde | -| | d | -| | data | -| | . | -| | mean | -| | and | -| | outm | -| | ean | -| | shou | -| | ld | -| | be | -| | appr | -| | oxim | -| | atel | -| | y | -| | equa | -| | l | -+------+------+ - -4.4.2 SCRIP regridder -^^^^^^^^^^^^^^^^^^^^^ - -**Example:** - -Regrid from a curvilinear to a generic grid, using a conservative -remapping. Compute the area-weighted means on input and output for -comparison. - -{% highlight python %} import cdms, regrid, MA - -Open the SCRIP remapping file and data file -=========================================== - -direc = '' fremap = cdms.open(direc+'rmp\_T42\_to\_C02562\_conserv.nc') -fdat = cdms.open(direc+'sampleT42Grid.nc') - -Input data array -================ - -dat = fdat('src\_array') - -Read the SCRIP regridder -======================== - -regridf = regrid.readRegridder(fremap) - -Regrid the variable -=================== - -outdat = regridf(dat) - -Get the cell area and fraction arrays. Areas are computed only -============================================================== - -for conservative regridding. -============================ - -srcfrac = regridf.getSourceFraction() srcarea = regridf.getSourceArea() -dstfrac = regridf.getDestinationFraction() dstarea = -regridf.getDestinationArea() - -Calculate area-weighted means -============================= - -inmean = MA.sum(srcfrac\ *srcarea*\ MA.ravel(dat)) / -MA.sum(srcfrac\ *srcarea) outmean = -MA.sum(dstfrac*\ dstarea\ *MA.ravel(outdat)) / MA.sum(dstfrac*\ dstarea) -print 'Input mean:', inmean print 'Output mean:', outmean - -fremap.close) fdat.close() {% endhighlight %} diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst deleted file mode 100644 index 05bdb5f5..00000000 --- a/docs/source/manual/cdms_5.rst +++ /dev/null @@ -1,486 +0,0 @@ -CHAPTER 5 Plotting CDMS data in Python --------------------------------------- - -5.1 Overview -~~~~~~~~~~~~ - -Data read via the CDMS Python interface can be plotted using the ``vcs`` -module. This module, part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT) is documented in the UV-CDAT reference manual. -The ``vcs`` module provides access to the functionality of the VCS -visualization program. - -Examples of plotting data accessed from CDMS are given below, as well as -documentation for the plot routine keywords. - -5.2 Examples -~~~~~~~~~~~~ - -In the following examples, it is assumed that variable ``psl`` is -dimensioned (time, latitude, longitude). ``psl`` is contained in the -dataset named ``'sample.xml'``. - -5.2.1 Example: plotting a gridded variable -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -{% highlight python %} 1 import cdms, vcs 2 3 f = -cdms.open('sample.xml') 4 psl = f.variables['psl'] 5 sample = psl[0] 6 -w=vcs.init() 7 8 w.plot(sample) 9 f.close() {% endhighlight %} - -**Notes:** - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 5 | Get | -| | a | -| | hori | -| | zont | -| | al | -| | slic | -| | e, | -| | for | -| | the | -| | firs | -| | t | -| | time | -| | poin | -| | t. | -+------+------+ -| 6 | Crea | -| | te | -| | a | -| | VCS | -| | Canv | -| | as | -| | ``w` | -| | `. | -+------+------+ -| 8 | Plot | -| | the | -| | data | -| | . | -| | Beca | -| | use | -| | samp | -| | le | -| | is a | -| | tran | -| | sien | -| | t | -| | vari | -| | able | -| | , | -| | it | -| | enca | -| | psul | -| | ates | -| | all | -| | the | -| | time | -| | , | -| | lati | -| | tude | -| | , | -| | long | -| | itud | -| | e, | -| | and | -| | attr | -| | ibut | -| | e | -| | info | -| | rmat | -| | ion. | -+------+------+ -| 9 | Clos | -| | e | -| | the | -| | file | -| | . | -| | This | -| | must | -| | be | -| | done | -| | afte | -| | r | -| | the | -| | refe | -| | renc | -| | e | -| | to | -| | the | -| | pers | -| | iste | -| | nt | -| | vari | -| | able | -| | ``ps | -| | l``. | -+------+------+ - -Thats it! The axis coordinates, variable name, description, units, etc. -are obtained from variable sample. - -What if the units are not explicitly defined for ``psl``, or a different -description is desired? ``plot`` has a number of other keywords which -fill in the extra plot information. - -5.2.2 Example: using aplot keywords. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -{% highlight python %} w.plot(array, units='mm/day', -file\_comment='High-frequency reanalysis', long\_name="Sea level -pressure", comment1="Sample plot", hms="18:00:00", ymd="1978/01/01") {% -endhighlight %} - -**Note:** Keyword arguments can be listed in any order. - -5.2.3 Example: plotting a time-latitude slice -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Assuming that variable ``psl`` has domain ``(time,latitude,longitude)``, -this example selects and plots a time-latitude slice: - -{% highlight python %} 1 samp = psl[:,:,0] 2 w = vcs.init() 3 -w.plot(samp, name='sea level pressure') {% endhighlight %} - -Notes: - -+------+------+ -| Line | Note | -| | s | -+======+======+ -| 1 | ``sa | -| | mp`` | -| | is a | -| | slic | -| | e | -| | of | -| | ``ps | -| | l``, | -| | at | -| | inde | -| | x | -| | ``0` | -| | ` | -| | of | -| | the | -| | last | -| | dime | -| | nsio | -| | n. | -| | Sinc | -| | e | -| | ``sa | -| | mp`` | -| | was | -| | obta | -| | ined | -| | from | -| | the | -| | slic | -| | e | -| | oper | -| | ator | -| | , | -| | it | -| | is a | -| | tran | -| | sien | -| | t | -| | vari | -| | able | -| | , | -| | whic | -| | h | -| | incl | -| | udes | -| | the | -| | lati | -| | tude | -| | and | -| | time | -| | info | -| | rmat | -| | ion. | -+------+------+ -| 3 | The | -| | ``na | -| | me`` | -| | keyw | -| | ord | -| | defi | -| | nes | -| | the | -| | iden | -| | tifi | -| | er, | -| | by | -| | defa | -| | ult | -| | the | -| | name | -| | in | -| | the | -| | file | -| | . | -+------+------+ - -5.2.4 Example: plotting subsetted data -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Calling the variable ``psl`` as a function reads a subset of the -variable. The result variable ``samp`` can be plotted directly: - -{% highlight python %} ... 1 samp = psl(time = (0.0,100.0), longitude = -180.0) 2 w = vcs.init() 3 w.plot(samp) {% endhighlight %} - -5.3 ``plot`` method -~~~~~~~~~~~~~~~~~~~ - -The ``plot`` method is documented in the UV-CDAT Reference Manual. This -section augments the documentation with a description of the optional -keyword arguments. The general form of the plot command is: - -{% highlight python %} canvas.plot(array [, args] [,key=value [, -key=value [, ...] ] ]) {% endhighlight %} - -where: - -- canvas is a VCS Canvas object, created with the vcs.init method. - -- array is a variable, masked array, or Numeric array having between - two and five dimensions. The last dimensions of the array is termed - the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', - and 'w'. For example, if array is three-dimensional, the axes are - (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). - (Note that the t dimension need have no connection with time; any - spatial axis can be mapped to any plot dimension. For a graphics - method which is two-dimensional, such as boxfill, the y-axis is - plotted on the horizontal, and the x-axis on the vertical. - - If array is a gridded variable on a rectangular grid, the plot - function uses a box-fill graphics method. If it is non-rectangular, - the meshfill graphics method is used. - - Note that some plot keywords apply only to rectangular grids only. - -- args are optional positional arguments: - - ``args`` := template\_name, graphics\_method, graphics\_name - - ``template_name``: the name of the VCS template (e.g., 'AMIP') - - ``graphics_method``: the VCS graphics method (boxfill) - - ``graphics_name``: the name of the specific graphics method - ('default') - - See the UV-CDAT Reference Manual and VCS Reference Manual for a - detailed description of these arguments. - -- ``key=value``, ... are optional keyword/value pairs, listed in any - order. These are defined in the table below. - -Table 5.1 ``plot`` keywords - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -.. raw:: html - -
KeyTypeValue
comment1stringComment plotted above file_comment
comment2stringComment plotted above comment1
comment3stringComment plotted above comment2
continents0 or 1if 1, plot continental outlines (default:plot if xaxis is - longitude, yaxis is latitude -or- xname is 'longitude' and yname is - 'latitude'
file_commentstringComment, defaults to variable.parent.comment
gridCDMS grid objectGrid associated with the data. Defaults to - variable.getGrid()
hmsstringHour, minute, second
long_namestringDescriptive variable name, defaults to variable.long_name.
missing_valuesame type as arrayMissing data value, defaults to variable.getMissing()
namestringVariable name, defaults to variable.id
timecdtime relative or absolute -

Time associated with the data.

- -

Example:

- -

cdtime.reltime(30.0, "days since 1978-1-1").

-
unitsstringData units. Defaults to variable.units
variableCDMS variable objectVariable associated with the data. The variable grid must have the - same shape as the data array.
xarray ([y|z|t|w]array)1-D Numeric arrayRectangular grids only. Array of coordinate values, having the - same length as the corresponding dimension. Defaults to xaxis[:\] - (y|z|t|waxis[:])
xaxis ([y|z|t|w]axis)CDMS axis objectRectangular grids only. Axis object. xaxis defaults to - grid.getAxis(0), yaxis defaults to grid.getAxis(1)
xbounds (ybounds)2-D Numeric arrayRectangular grids only. Boundary array of shape (n,2) where - n is the axis length. Defaults to xaxis.getBounds(), or - xaxis.genGenericBounds() if None, similarly for ybounds.
xname ([y|z|t|w]name)stringRectangular grids only. Axis name. Defaults to xaxis.id - ([y|z|t|w]axis.id)
xrev (yrev)0 or 1 -

If xrev (yrev) is 1, reverse the direction of the x-axis (y-axis). Defaults to - 0, with the following exceptions:

- -
    -
  • If the y-axis is latitude, and has decreasing values, yrev defaults to - 1
  • - -
  • If the y-axis is a vertical level, and has increasing pressure levels, yrev - defaults to 1.
  • -
-
xunits ([y|z|t|w]units)stringRectangular grids only. Axis units. Defaults to xaxis.units - ([y|z|t|w]axis.units).
diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst deleted file mode 100644 index 6ee84692..00000000 --- a/docs/source/manual/cdms_6.rst +++ /dev/null @@ -1,3128 +0,0 @@ -CHAPTER 6 Climate Data Markup Language (CDML) ---------------------------------------------- - -6.1 Introduction -~~~~~~~~~~~~~~~~ - -The Climate Data Markup Language (CDML) is the markup language used to -represent metadata in CDMS. CDML is based on the W3C XML standard -(http://www.w3.org). This chapter defines the syntax of CDML. Read this -section if you will be building or maintaining a CDMS database. - -XML, the eXtensible Markup Language, makes it possible to define -interoperable dialects of markup languages. The most recent version of -HTML, the Web hypertext markup language, is an XML dialect. CDML is also -an XML dialect, geared toward the representation of gridded climate -datasets. XML provides rigor to the metadata representation, ensuring -that applications can access it correctly. XML also deals with -internationalization issues, and holds forth the promise that utilities -for browsing, editing, and other common tasks will be available in the -future. - -CDML files have the file extension .xml or .cdml. - -6.2 Elements -~~~~~~~~~~~~ - -A CDML document consists of a nested collection of elements. An element -is a description of the metadata associated with a CDMS object. The form -of an element is: - -`` element-content `` - -or - -```` - -where - -- ``tag`` is a string which defines the type of element -- ``attribute-list`` is a blank-separated list of attribute-value - pairs, of the form: - - ``attribute = "value"`` -- ``element-content`` depends on the type of element. It is either a - list of elements, or text which defines the element values. For - example, the content of an axis element either is a list of axis - values, or is a linear element. For datasets, the content is the - blank-separated list of elements corresponding to the axes, grids, - and variables contained in the dataset. - -The CDML elements are: - -Table 6.1 CDML Tags - - -+------------+---------------------------------------+ -| Tag | Description | -+============+=======================================+ -| attr | Extra attribute | -+------------+---------------------------------------+ -| axis | Coordinate axis | -+------------+---------------------------------------+ -| domain | Axes on which a variable is defined | -+------------+---------------------------------------+ -| domElem | Element of a variable domain | -+------------+---------------------------------------+ -| linear | Linearly-spaced axis values | -+------------+---------------------------------------+ -| rectGrid | Rectilinear Grid | -+------------+---------------------------------------+ -| variable | Variable | -+------------+---------------------------------------+ - -6.3 Special Characters -~~~~~~~~~~~~~~~~~~~~~~ - -XML reserves certain characters for markup. If they appear as content, -they must be encoded to avoid confusion with markup: - -Table 6.2 Special Character Encodings - - -+-------------+------------+ -| Character | Encoding | -+=============+============+ -| < | < | -+-------------+------------+ -| > | > | -+-------------+------------+ -| & | & | -+-------------+------------+ -| “ | " | -+-------------+------------+ -| ‘ | ' | -+-------------+------------+ - -For example, the comment - -{% highlight text %} Certain "special characters", such as <, >, and , -must be encoded. {% endhighlight %} - -would appear in an attribute string as: - -{% highlight html %} comment = "Certain "special characters", such as <, ->, and ', must be encoded." {% endhighlight %} - -6.4 Identifiers -~~~~~~~~~~~~~~~ - -In CDMS, all objects in a dataset have a unique string identifier. The -id attribute holds the value of this identifier. If the variable, axis, -or grid has a string name within a data file, then the id attribute -ordinarily has this value. Alternatively, the name of the object in a -data file can be stored in the name\_in\_file attribute, which can -differ from the id. Datasets also have IDs, which can be used within a -larger context (databases). - -An identifer must start with an alphabetic character (upper or lower -case), an underscore (\_), or a colon (:). Characters after the first -must be alphanumeric, an underscore, or colon. There is no restriction -on the length of an identifier. - -6.5 CF Metadata Standard -~~~~~~~~~~~~~~~~~~~~~~~~ - -`The CF metadata standard `__ defines a set -of conventions for usage of netCDF. This standard is supported by CDML. -The document defines names and usage for metadata attributes. CF -supersedes the GDT 1.3 standard. - -6.6 CDML Syntax -~~~~~~~~~~~~~~~ - -The following notation is used in this section: - -- A ``monospaced block`` is used for a syntax specification. -- **Bold** text indicates literals. -- (R\|S) denotes either R or S. -- R\*denotes zero or more R. -- R+ denotes one or more R. - -A CDML document consists of a prolog followed by a single dataset -element. - -``CDML-document ::= prolog dataset-element`` - -The prolog defines the XML version, and the Document Type Definition -(DTD), a formal specification of the document syntax. See http:// -www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML -Version 1.0. - -``prolog ::= `` - -6.6.1 Dataset Element -^^^^^^^^^^^^^^^^^^^^^ - -A dataset element describes a single dataset. The content is a list of -elements corresponding to the axes, grids, and variables contained in -the dataset. Axis, variable, and grid elements can be listed in any -order, and an element ID can be used before the element is actually -defined. - -``dataset-element ::=`` **** ``dataset-content`` **** - -``dataset-content ::= (axis-element | grid-element | variable-element)* extra-attribute-element+`` - -Table 6.3 Dataset Attributes - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
- -Attribute - -.. raw:: html - - - -Required - -.. raw:: html - - - -CF - -.. raw:: html - - - -GDT - -.. raw:: html - - - -Notes - -.. raw:: html - -
- -appendices - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Version number - -.. raw:: html - -
- -calendar - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -.. raw:: html - -

- -Calendar used for encoding time axes. - -.. raw:: html - -

- -.. raw:: html - -

- -``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| -``proleptic_gregorian`` \| ``standard`` - -.. raw:: html - -

- -.. raw:: html - -

- -Note: for the CF convention, the calendar attribute is placed on the -time axis. - -.. raw:: html - -

- -.. raw:: html - -
- -comment - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Additional dataset information - -.. raw:: html - -
- -conventions - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -The netCDF metadata standard. Example: "CF-1.0" - -.. raw:: html - -
- -cdms\_filemap - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Map of partitioned axes to files. See note below. - -.. raw:: html - -
- -directory - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Root directory of the dataset - -.. raw:: html - -
- -frequency - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Temporal frequency - -.. raw:: html - -
- -history - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Evolution of the data - -.. raw:: html - -
- -id - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Dataset identifier - -.. raw:: html - -
- -institution - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Who made or supplied the data - -.. raw:: html - -
- -production - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -How the data was produced (see source) - -.. raw:: html - -
- -project - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Project associated with the data Example: "CMIP 2" - -.. raw:: html - -
- -references - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -Published or web-based references that describe the data or methods used -to produce it - -.. raw:: html - -
- -source - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -The method of production of the original data. - -.. raw:: html - -
- -template - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Filename template. This is an alternate mechanism, other than -cdms\_filemap, for describing the file mapping. See ‘cdimport -h’ for -details. - -.. raw:: html - -
- -title - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -A succinct description of the data. - -.. raw:: html - -
- -**Notes:** - -The ``cdms_filemap`` attribute describes how the dataset is partitioned -into files. The format is: - -``filemap ::= [ varmap, varmap, ...]`` - -``varmap ::= [ namelist, slicelist ]`` - -``namelist ::= [ name, name, ... ]`` - -``slicelist ::= [ indexlist, indexlist, ,,, ]`` - -``indexlist ::= [ time0, time1, lev0, lev1, path ]`` - -``name ::= variable name`` - -``time0 ::= first index of time in the file, or '-' if not split on time`` - -``time1 ::= last index of time + 1, in the file, or '-' if not split on time`` - -``lev0 ::= first index of vertical levels in the file, or '-' if not split on level`` - -``lev1 ::= last index +1 of vertical levels in the file, or '-' if not split on level`` - -``path ::= pathname of the file containing data for this time/level range.`` - -The pathname is appended to the value of the directory attribute, to -obtain an absolute pathname. - -6.6.2 Axis Element -^^^^^^^^^^^^^^^^^^ - -An axis element describes a single coordinate axis. The content can be a -blank-separated list of axis values or a linear element. A linear -element is a representation of a linearly-spaced axis as (start, delta, -length). - -``axis-element ::=`` **** ``axis-content`` **** - -``axis-content ::= (axis-values | linear-element) extra-attribute-element*`` - -``axis-values ::= [value*]`` - -``linear-element ::=`` ** ** - -Table 6.4 - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -.. raw:: html - -
AttributeRequired?CFGDTNotes
associateNNYIDs of variables containing alternative sets of coordinates.
axisNYY -

The spatial type of the axis:

- -
    -
  • "T" - time
  • - -
  • "X" - longitude
  • - -
  • "Y" - latitude
  • - -
  • "Z" - vertical level
  • - -
  • "-" - not spatiotemporal
  • -
-
boundsNYYID of the boundary variable
calendarNYNSee dataset.calendar
climatologyNYNRange of dates to which climatological statistics apply.
commentNYNString comment
compressNYYDimensions which have been compressed by gathering
datatypeYNNChar, Short, Long, Float, Double, or String
datesNYNRange of dates to which statistics for a typical diurnal cycle apply.
expandNNYCoordinates prior to contraction
formula_termsNYNVariables that correspond to the terms in a formula.
idYNNAxis identifier. Also the name of the axis in the underlying file(s), if - name_in_file is undefined.
isvarNNN -

'true' | 'false'

- -

'false' if the axis does not have coordinate values explicitly defined in the - underlying file(s).

- -

Default: 'true'

-
leap_monthNYNFor a user-defined calendar, the month which is lengthened by a day in leap - years.
leap_yearNYNAn example of a leap year for a user-defined calendar. All years that differ - from this year by a multiple of four are leap years.
lengthNNNNumber of axis values, including values for which no data is defined. Cf. - partition_length.
long_nameNYYLong description of a physical quantity
moduloNNYArithmetic modulo of an axis with circular topology.
month_lengthsNYNLength of each month in a non-leap year for a user-defined calendar.
name_in_fileNNNName of the axis in the underlying file(s). See id.
partitionNNNHow the axis is split across files.
partition_lengt hNNNNumber of axis points for which data is actually defined. If data is missing - for some values, this will be smaller than the length.
positiveNYYDirection of positive for a vertical axis
standard_nameNYNReference to an entry in the standard name table.
topologyNNY -

Axis topology.

- -

'circular' | 'linear'

-
unitsYYYUnits of a physical quantity
weightsNNNName of the weights array
- -6.6.3 partition attribute -^^^^^^^^^^^^^^^^^^^^^^^^^ - -For an axis in a dataset, the .partition attribute describes how an axis -is split across files. It is a list of the start and end indices of each -axis partition. - -FIGURE 4. Partitioned axis - - -.. figure:: /images/timeLine.jpg - :alt: - -For example, Figure 4 shows a time axis, representing the 36 months, -January 1980 through December 1982, with December 1981 missing. The -first partition interval is (0,12), the second is (12,23), and the third -is (24,36), where the interval (i,j) represents all indices k such that -i <= k < j. The .partition attribute for this axis would be the list: - -``[0, 12, 12, 23, 24, 36]`` - -Note that the end index of the second interval is strictly less than the -start index of the following interval. This indicates that data for that -period is missing. - -6.6.4 Grid Element -^^^^^^^^^^^^^^^^^^ - -A grid element describes a horizontal, latitude-longitude grid which is -rectilinear in topology, - -``grid-element ::=`` **** -``extra-attribute-element*`` **** - -Table 6.5 RectGrid Attributes - - -.. raw:: html - - - -:: - - - -.. raw:: html - - - -:: - - - - - - - - -.. raw:: html - -
Attribute Required? GDT? Notes
idYNGrid identifier
typeYN

Grid classification

"gaussian" | "uniform" | "equalarea" |"generic"

Default: "generic"

latitudeYNLatitude axis name
longitudeYNLongitude axis name
maskNNName of associated mask variable
orderYN

Grid ordering "yx" | "xy"

Default: “yx”, axis order is latitude, longitude

- -6.6.5 Variable Element -^^^^^^^^^^^^^^^^^^^^^^ - -A variable element describes a data variable. The domain of the variable -is an ordered list of domain elements naming the axes on which the -variable is defined. A domain element is a reference to an axis or grid -in the dataset. - -The length of a domain element is the number of axis points for which -data can be retrieved. The partition\_length is the number of points for -which data is actually defined. If data is missing, this is less than -the length. - -``variable-element ::=`` **** -``variable-content`` **** - -``variable-content ::=`` variable-domain extra-attributeelement\*\` - -``variable-domain ::=`` **** ``domain-element*`` **** - -``domain-element ::=`` **\*\* - -Table 6.6 Variable Attributes - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
- -Attribute - -.. raw:: html - - - -Required? - -.. raw:: html - - - -CF - -.. raw:: html - - - -GDT - -.. raw:: html - - - -Notes - -.. raw:: html - -
- -id - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Variable identifier. Also, the name of the variable in the underlying -file(s), if name\_in\_file is undefined. - -.. raw:: html - -
- -add\_offset - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Additive offset for packing data. See scale\_factor. - -.. raw:: html - -
- -associate - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -IDs of variables containing alternative sets of coordinates - -.. raw:: html - -
- -axis - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -.. raw:: html - -

- -Spatio-temporal dimensions. - -.. raw:: html - -

- -.. raw:: html - -

- -Example: "TYX" for a variable with domain (time, latitude, longitude) - -.. raw:: html - -

- -.. raw:: html - -

- -Note: for CF, applies to axes only. - -.. raw:: html - -

- -.. raw:: html - -
- -cell\_methods - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -The method used to derive data that represents cell values, e.g., -"maximum", "mean", "variance", etc. - -.. raw:: html - -
- -comments - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Comment string - -.. raw:: html - -
- -coordinates - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -IDs of variables containing coordinate data. - -.. raw:: html - -
- -datatype - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Char, Short, Long, Float, Double, or String - -.. raw:: html - -
- -grid\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Id of the grid - -.. raw:: html - -
- -grid\_type - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -"gaussian" \| "uniform" \| "equalarea" \| "generic" - -.. raw:: html - -
- -long\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Long description of a physical quantity. - -.. raw:: html - -
- -missing\_value - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Value used for data that are unknown or missint. - -.. raw:: html - -
- -name\_in\_file - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Name of the variable in the underlying file(s). See id. - -.. raw:: html - -
- -scale\_factor - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Multiplicative factor for packing data. See add\_offset. - -.. raw:: html - -
- -standard\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -Reference to an entry in the standard name table. - -.. raw:: html - -
- -subgrid - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Records how data values represent subgrid variation. - -.. raw:: html - -
- -template - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Name of the file template to use for this variable. Overrides the -dataset value. - -.. raw:: html - -
- -units - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Units of a physical quantity. - -.. raw:: html - -
- -valid\_max - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Largest valid value of a variable - -.. raw:: html - -
- -valid\_min - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Smallest valid value of a variable - -.. raw:: html - -
- -valid\_range - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Largest and smallest valid values of a variable - -.. raw:: html - -
- -6.6.6 Attribute Element -^^^^^^^^^^^^^^^^^^^^^^^ - -Attributes which are not explicitly defined by the GDT convention are -represented as extra attribute elements. Any dataset, axis, grid, or -variable element can have an extra attribute as part of its content. -This representation is also useful if the attribute value has non-blank -whitespace characters (carriage returns, tabs, linefeeds) which are -significant. - -The datatype is one of: **Char**, **Short**, **Long**, **Float**, -**Double**, or **String**. - -``extra-attribute-element ::=`` **** ``attribute-value`` -**** - -6.7 A Sample CDML Document -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Dataset "sample" has two variables, and six axes. - -**Note:** - -- The file is indented for readability. This is not required; the added - whitespace is ignored. -- The dataset contains three axes and two variables. Variables u and v - are functions of time, latitude, and longitude. -- The global attribute cdms\_filemap describes the mapping between - variables and files. The entry - ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` - indicates that variable ``u`` is contained in file u\_2000.nc for - time index 0, u\_2001.nc for time index 1, etc. - -{% highlight xml %} - -.. raw:: html - - - -.. raw:: html - - - - [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] - -:: - - - - [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. - - 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 - - 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 - - 303.75 315. 326.25 337.5 348.75] - - - - - [ 0. 366. 731.] - - - - - - - - - - - - - - - - - - - {% endhighlight %} diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst deleted file mode 100644 index a4b739ad..00000000 --- a/docs/source/manual/cdms_7.rst +++ /dev/null @@ -1,423 +0,0 @@ -CHAPTER 7 CDMS Utilities ------------------------- - -7.1 ``cdscan``: Importing datasets into CDMS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -7.1.1 Overview -^^^^^^^^^^^^^^ - -A dataset is a partitioned collection of files. To create a dataset, the -files must be scanned to produce a text representation of the dataset. -CDMS represents datasets as an ASCII metafile in the CDML markup -language. The file contains all metadata, together with information -describing how the dataset is partitioned into files. (Note: CDMS -provides a direct interface to individual files as well. It is not -necessary to scan an individual file in order to access it.) - -For CDMS applications to work correctly, it is important that the CDML -metafile be valid. The ``cdscan`` utility generates a metafile from a -collection of data files. - -CDMS assumes that there is some regularity in how datasets are -partitioned: - -- A variable can be partitioned (split across files) in at most two - dimensions. The partitioned dimension(s) must be either time or - vertical level dimensions; variables may not be partitioned across - longitude or latitude. Datasets can be parti-tioned by variable as - well. For example, one set of files might contain heat fluxes, while - another set contains wind speeds. - -Otherwise, there is considerable flexibility in how a dataset can be -partitioned: - -- Files can contain a single variable or all variables in the dataset. -- The time axis can have gaps. -- Horizontal grid boundary information and related information can be - duplicated across files. -- Variables can be on different grids. -- Files may be in any of the self-describing formats supported by CDMS, - including netCDF, HDF, GrADS/GRIB, and DRS. - -7.1.2 ``cdscan`` Syntax -^^^^^^^^^^^^^^^^^^^^^^^ - -The syntax of the ``cdscan`` command is - -{% highlight text %} cdscan [options] file1 file2 ... {% endhighlight %} - -or - -{% highlight text %} cdscan [options] -f file\_list {% endhighlight %} - -where - -- ``file1 file2 ...`` is a blank-separated list of files to scan -- ``file_list`` is the name of a file containing a list of files to - scan, one pathname per line. - -Output is written to standard output by default. Use the -x option to -specify an output filename. - -Table 7.1 cdscan command options - - -.. raw:: html - - - -:: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -.. raw:: html - -
OptionDescription
-a alias_file -

Change variable names to the aliases defined in an alias file.

- -

Each line of the alias file consists of two blank separated fields: - variable_id alias. variable_id is the ID of the - variable in the file, and alias is the name that will be substituted - for it in the output dataset. Only variables with entries in the - alias_file are renamed.

-
-c calendarSpecify the dataset calendar attribute. One of "gregorian" (default), "julian", - "noleap", "proleptic_gregorian", "standard", or "360_day".
-d dataset_idString identifier of the dataset. Should not contain blanks or non-printing - characters. Default: "none"
- -e newattr - -

Add or modify attributes of a file, variable, or axis. The form of - newattr is either:

- -

var.attr = value

- -

to modify a variable or attribute, or

- -

.attr = value

- -

to modify a global (file) attribute. In either case, value may be quoted to - preserve spaces or force the attribute to be treated as a string. If value is not - quoted and the first character is a digit, it is converted to integer or - floating-point. This option does not modify the input datafiles. See notes and - examples below.

-
--exclude var,var,... -

Exclude specified variables. The argument is a comma-separated list of - variables containing no blanks. Also see --include.

-
-f file_list -

File containing a list of absolute data file names, one per line.

-
-hPrint a help message.
-i time_deltaCauses the time dimension to be represented as linear, producing a more compact - representation. This is useful if the time dimension is very long. - time_delta is a float or integer. For example, if the time delta is 6 - hours, and the reference units are 'hours since xxxx' , set the time delta to 6. - See the -r option. See Note 2.
--include var,var,... -

Only include specified variables in the output. The argument is a - comma-separated list of variables containing no blanks.

-

Also see --exclude.

-
-j -

Scan time as a vector dimension. Time values are listed individually.

- -

Note: Turns off the -i option.

-
-l levelsSpecify that the files are partitioned by vertical level. That is, data for - different vertical levels may appear in different files. levels is a - comma-separated list of levels containing no blanks. See Note 3.
-m levelidName of the vertical level dimension. The default is the vertical dimension as - determined by CDMS. See Note 3.
-p templateAdd a file template string, for compatibility with pre-V3.0 datasets. - cdimport -h describes template strings.
-qQuiet mode.
-r time_unitsTime units of the form units since yyyy-mm-dd hh:mi:ss, where - units is one of "year", "month","day", "hour", "minute", - "second".
-s suffix_fileAppend a suffix to variable names, depending on the directory containing the - data file. This can be used to distinguish variables having the same name but - generated by different models or ensemble runs. suffix_file is the - name of a file describing a mapping between directories and suffixes. Each line - consists of two blank-separated fields: directory suffix. Each file - path is compared to the directories in the suffix file. If the file path is in that - directory or a subdirectory, the corresponding suffix is appended to the variable - IDs in the file. If more than one such directory is found, the first directory - found is used. If no match is made, the variable ids are not altered. Regular - expressions can be used: see the example in the Notes section.
-t timeidID of the partitioned time dimension. The default is the name of the time - dimension as determined by CDMS. See Note 1.
--time-linear tzero,delta,units[,calendar] -

Override the time dimensions(s) with a linear time dimension. The arguments - are comma-separated list:

- -
    -
  • zero is the initial time point, a floating-point value.
  • - -
  • delta is the time delta, floating-point.
  • - -
  • units are time units as specified in the [-r] option.
  • - -
  • calendar is optional, and is specified as in the [-c] option.
  • -
- -

If omitted, it defaults to the value specified by [-c], otherwise as specified - in the file. Example: --time-linear '0,1,months since - 1980,noleap'

-
-x xmlfileOutput file name. By default, output is written to standard output.
- -**Notes:** - -.. raw:: html - -
    - -.. raw:: html - -
  1. - -Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be -listed in any order. Most commonly, the files are the result of a single -experiment, and the 'partitioned' dimension is time. The time dimension -of a variable is the coordinate variable having a name that starts with -'time' or having an attribute axis='T'. If this is not the case, specify -the time dimension with the -t option. The time dimension should be in -the form supported by cdtime. If this is not the case (or to override -them) use the -r option. - -.. raw:: html - -
  2. - -.. raw:: html - -
  3. - -By default, the time values are listed explicitly in the output XML. -This can cause a problem if the time dimension is very long, say for -6-hourly data. To handle this the form cdscan -i delta may be -used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given -file is not linear. - -.. raw:: html - -
  4. - -.. raw:: html - -
  5. - -Another form of the command is cdscan -l lev1,lev2,..,levn . This -asserts that the dataset is partitioned in both time and vertical level -dimensions. The level dimension of a variable is the dimension having a -name that starts with "lev", or having an attribute "axis=Z". If this is -not the case, set the level name with the -m option. - -.. raw:: html - -
  6. - -.. raw:: html - -
  7. - -:: - -

    An example of a suffix file:

    -
    /exp/pr/ncar-a _ncar-a
    -
    -/exp/pr/ecm-a \_ecm-a /exp/ta/ncar-a \_ncar-a /exp/ta/ecm-a \_ecm-a
    -
    -.. raw:: html
    -
    -   
    - -:: - -

    For all files in directory /exp/pr/ncar-a or a subdirectory, the corresponding variable ids will be appended with the suffix '_ncar-a'. Regular expressions can be used, as defined in the Python 're' module. For example, The previous example can be replaced with the single line:

    -
    /exp/[^/]*/([^/]*) _\g<1>
    -

    Note the use of parentheses to delimit a group. The syntax \g<n> refers to the nth group matched in the regular expression, with the first group being n=1. The string [^/]* matches any sequence of characters other than a forward slash.

    - -.. raw:: html - -
  8. - -.. raw:: html - -
  9. - -:: - -

    Adding or modifying attributes with the -e option:

    -
    time.units = "days since 1979-1-1"
    -

    sets the units of all variables/axes to "days since 1979-1-1". Note that since this is done before any other processing is done, it allows overriding of non-COARDS time units.

    -
    .newattr=newvalue
    -

    Set the global file attribute 'newattr' to 'newvalue'.

    - -.. raw:: html - -
  10. - -.. raw:: html - -
  11. - -:: - -

    The [--time-linear] option overrides the time values in the file(s). The resulting dimension does not have any gaps. In contrast, the [-i], [-r] options use the specified time units (from [-r]), and calendar from [-c] if specified, to convert the file times to the new units. The resulting linear dimension may have gaps.

    -

    In either case, the files are ordered by the time values in the files.

    -

    The [--time-linear] option should be used with caution, as it is applied to all the time dimensions found.

    - -.. raw:: html - -
  12. - -.. raw:: html - -
- -7.1.3 Examples -^^^^^^^^^^^^^^ - -{% highlight text %} cdscan -c noleap -d test -x test.xml [uv]\*.nc {% -endhighlight %} - -{% highlight text %} cdscan -d pcmdi\_6h -i 0.25 -r 'days since -1979-1-1' *6h*.ctl {% endhighlight %} - -7.1.4 File Formats -^^^^^^^^^^^^^^^^^^ - -Data may be represented in a variety of self-describing binary file -formats, including - -- netCDF, the Unidata Network Common Data Format -- HDF, the NCSA Hierarchical Data Format -- GrADS/GRIB, WMO GRIB plus a GrADS control file (.ctl) The first - non-comment line of the control file must be a dset specification. -- DRS, the PCMDI legacy format. - -7.1.5 Name Aliasing -^^^^^^^^^^^^^^^^^^^ - -A problem can occur if variables in different files are defined on -different grids. What if the axis names are the same? CDMS requires that -within a dataset, axis and variable IDs (names) be unique. What should -the longitude axes be named in CDMS to ensure uniqueness? The answer is -to allow CDMS IDs to differ from file names. - -If a variable or axis has a CDMS ID which differs from its name in the -file, it is said to have an alias. The actual name of the object in the -file is stored in the attribute ``name_in_file``. ``cdscan`` uses this -mechanism (with the ``-a`` and ``s`` options) to resolve name conflicts; -a new axis or variable ID is generated, and the ``name_in_file`` is set -to the axis name in the file. - -Name aliases also can be used to enforce naming standards. For data -received from an outside organization, variable names may not be -recognized by existing applications. Often it is simpler and safer to -add an alias to the metafile rather than rewrite the data diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst deleted file mode 100644 index 6229e776..00000000 --- a/docs/source/manual/cdms_appendix.rst +++ /dev/null @@ -1,1411 +0,0 @@ -APPENDIX A ----------- - -CDMS Classes -~~~~~~~~~~~~ - -Figure 1, "CDMS Classes", on page 175 illustrates the class inheritance -structure of CDMS. The classes may be categorized as abstract or -concrete. Only concrete classes are meant to be used directly. In -contrast an abstract class defines the common interface of its -subclasses. For example, the class AbstractAxis2D defines the common -interface for two-dimensional coordinate axes. It has concrete -subclasses DatasetAxis2D, FileAxis2D, and TransientAxis2D, which are -used in applications. Abstract classes are denoted in italics. - -For many abstract classes there are three 'flavors' of subclass: -dataset, file, and transient. Dataset-related objects are thought of as -being contained in datasets in the sense that operations on those -objects result in I/O operations on the corresponding dataset. The same -is true of file-related objects. Objects in datasets and files are -examples of persistent objects, whose state persists after the -application exits. On the other hand, transient objects live in memory -and are not persistent. - -In general the concrete subclasses closely mirror the interface of the -abstract parent class. For this reason this document defines the -interfaces of the abstract classes, and only discusses a concrete class -in the few cases where the interface has been extended. This allows -applications to treat the behavior of, say a dataset axis and file axis, -as identical. - -.. figure:: /images/cdms_classes.jpg - :alt: - -FIGURE 1. CDMS Classes - - -APPENDIX B ----------- - -Version Notes -~~~~~~~~~~~~~ - -B.1 Version 4.0 -^^^^^^^^^^^^^^^ - -CDMS version 4.0 adds support for nonrectangular grids: - -- The following grid classes were added: AbstractHorizontalGrid, - AbstractCurve-Grid, AbstractGenericGrid, DatasetCurveGrid, - FileCurveGrid, TransientCurve-Grid, DatasetGenericGrid, - FileGenericGrid, and TransientGenericGrid. -- The following axis classes were added: AbstractCoordinateAxis, - AbstractAuxAxis1D, AbstractAxis2D, DatasetAuxAxis1D, FileAuxAxis1D, - TransientAuxAxis1D, DatasetAxis2D, FileAxis2D, and TransientAxis2D. -- The getMesh and clone methods were added for grids. -- An interface to the SCRIP package was added. - -B.2 Version 3.0 Overview -^^^^^^^^^^^^^^^^^^^^^^^^ - -CDMS version 3.0 is a significant enhancement of previous versions. The -major changes were: - -- UV-CDAT/CDMS was integrated with the Numerical Python masked array - class MA.MaskedVariable. The MV submodule was added as a wrapper - around MA. -- Methods that read data, such as subRegion, subSlice, and the slice - operations, return instances of class TransientVariable. The plot and - regrid modules were modified to handle masked array input. The - specifiers time=..., latitude=..., etc. were added to the I/O - routines. -- The class TransientVariable was added. -- A number of new functions were added, notably subRegion and subSlice, - which return instances of TransientVariable. -- When a masked array is returned from a method, it is "squeezed": - singleton dimensions are removed. In contrast, transient variables - are not squeezed. I/O functions have a squeeze option. The method - setAutoReshapeMode was removed. -- Internal attributes are handled in the InternalAttributes class. This - allows CDMS classes to be subclassed more readily. -- The class Variable was renamed DatasetVariable. -- The cu module was emulated in cdms. cu and cdms methods can be mixed. -- The code was modularized, so that Python, CDMS, and Numerical Python - can be built and installed separately. This significantly enhances - the portability of the code. - -B.3 V3.0 Details -^^^^^^^^^^^^^^^^ - -B.3.1 AbstractVariable -'''''''''''''''''''''' - -- Functions getDomain, getSlice, rank, regrid, setMissing, size, - subRegion, and subSlice were added. -- The functions getRegion, getSlice, getValue, and the slice operators - all return an instance of MA, a masked array. Singleton dimensions - are squeezed. -- The functions subRegion and subSlice return an instance of - TransientVariable. Singleton dimensions are not squeezed. -- The xxSlice and xxRegion functions have keywords time, level, - latitude, and longitude. -- The input functions have the keyword squeeze. -- AbstractVariable inherits from class Slab. The following functions - previously available in module cu are Slab methods: getattribute, - setattribute, listdimattributes, getdimattribute, listall, and info. -- AbstractVariable implements arithmetic functions, astype. -- The write function was added. - -B.3.2 AbstractAxis -'''''''''''''''''' - -- The functions asComponentTime, asRelativeTime, clone, getAxisIds, - getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were - added. -- subaxis was renamed subAxis for consistency. -- Generalized wraparound was implemented, to handle multiple cycles, - reversing, and negative strides. By default, coordinate intervals are - closed. The intersection options 'n','e','b',and 's' were added to - the interval indicator - see mapIntervalExt. - -B.3.3 AbstractDatabase -'''''''''''''''''''''' - -- The function open is synonymous with openDataset. - -B.3.4 Dataset -''''''''''''' - -- The function open is synonymous with openDataset. - -B.3.5 cdms module -''''''''''''''''' - -- The functions asVariable, isVariable, and createVariable were added. -- The function setAutoReshapeMode was removed. It is replaced by the - squeeze option for all I/O functions. - -B.3.6 CdmsFile -'''''''''''''' - -- The function createVariable has a keyword fill\_value. The datatype - may be a Numeric/MA typecode. -- The function write was added. - -B.3.7 CDMSError -''''''''''''''' - -- All errors are an instance of the class CDMSError. - -B.3.8 AbstractRectGrid -'''''''''''''''''''''' - -- The function createGaussianGrid was added. - -B.3.9 InternalAttributes -'''''''''''''''''''''''' - -- The class InternalAttributes was added. It has methods - add\_internal\_attribute, is\_internal\_attribute, and - replace\_external\_attributes. - -B.3.10 TransientVariable -'''''''''''''''''''''''' - -- The class TransientVariable was added. It inherits from both - AbstractVariable and MA. -- The cdms module function createVariable returns a transient variable. -- This class does not implement the functions getPaths or getTemplate. - -B.3.11 MV -''''''''' - -- The MV submodule of cdms was added. - -APPENDIX C ----------- - -``cu`` Module -~~~~~~~~~~~~~ - -The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 -it is emulated in the ``cdms`` module. It is maintained for backward -compatibility. - -The ``cu`` classes are ``Slab``, corresponding to ``TransientVariable`` -in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. - -C.1 Slab -~~~~~~~~ - -Table C.1 Slab Methods - - -+------+------+------+ -| Type | Meth | Defi | -| | od | niti | -| | | on | -+======+======+======+ -| Vari | ``ge | Get | -| ous | tatt | the | -| | ribu | valu | -| | te(n | e | -| | ame) | of | -| | `` | an | -| | | attr | -| | | ibut | -| | | e. | -| | | ``na | -| | | me`` | -| | | is | -| | | the | -| | | stri | -| | | ng | -| | | name | -| | | of | -| | | the | -| | | attr | -| | | ibut | -| | | e. | -| | | The | -| | | foll | -| | | owin | -| | | g | -| | | spec | -| | | ial | -| | | name | -| | | s | -| | | can | -| | | alwa | -| | | ys | -| | | be | -| | | used | -| | | : | -| | | 'fil | -| | | enam | -| | | e', | -| | | 'com | -| | | ment | -| | | s', | -| | | 'gri | -| | | d\_n | -| | | ame' | -| | | , | -| | | 'gri | -| | | d\_t | -| | | ype' | -| | | , | -| | | 'tim | -| | | e\_s | -| | | tati | -| | | stic | -| | | ', | -| | | 'lon | -| | | g\_n | -| | | ame' | -| | | , | -| | | 'uni | -| | | ts'. | -+------+------+------+ -| Vari | ``ge | Get | -| ous | tdim | the | -| | attr | valu | -| | ibut | e | -| | e(di | of a | -| | m, f | dime | -| | ield | nsio | -| | )`` | n | -| | | attr | -| | | ibut | -| | | e. | -| | | ``di | -| | | m`` | -| | | is | -| | | the | -| | | dime | -| | | nsio | -| | | n | -| | | numb | -| | | er, | -| | | an | -| | | inte | -| | | ger | -| | | in | -| | | the | -| | | rang | -| | | e | -| | | 0..r | -| | | ank- | -| | | 1. | -| | | ``fi | -| | | eld` | -| | | ` | -| | | is a | -| | | stri | -| | | ng, | -| | | one | -| | | of: | -| | | "nam | -| | | e", | -| | | "val | -| | | ues" | -| | | , | -| | | "len | -| | | gth" | -| | | , | -| | | "uni | -| | | ts", | -| | | "wei | -| | | ghts | -| | | ", | -| | | "bou | -| | | nds" | -| | | . | -+------+------+------+ -| None | ``in | Prin | -| | fo(f | t | -| | lag= | slab | -| | None | info | -| | , de | rmat | -| | vice | ion. | -| | =sys | If | -| | .std | ``fl | -| | out) | ag`` | -| | `` | is | -| | | nonz | -| | | ero, | -| | | dime | -| | | nsio | -| | | n | -| | | valu | -| | | es, | -| | | weig | -| | | hts, | -| | | and | -| | | boun | -| | | ds | -| | | are | -| | | also | -| | | prin | -| | | ted. | -| | | Outp | -| | | ut | -| | | is | -| | | sent | -| | | to | -| | | ``de | -| | | vice | -| | | ``. | -+------+------+------+ -| List | ``li | Prin | -| | stal | t | -| | l(al | slab | -| | l=No | info | -| | ne)` | rmat | -| | ` | ion. | -| | | If | -| | | ``al | -| | | l`` | -| | | is | -| | | nonz | -| | | ero, | -| | | dime | -| | | nsio | -| | | n | -| | | valu | -| | | es, | -| | | weig | -| | | hts, | -| | | and | -| | | boun | -| | | ds | -| | | are | -| | | also | -| | | prin | -| | | ted. | -+------+------+------+ -| List | ``li | List | -| | stdi | dime | -| | matt | nsio | -| | ribu | n | -| | tes( | attr | -| | dim, | ibut | -| | fie | es. | -| | ld)` | Retu | -| | ` | rns | -| | | a | -| | | list | -| | | of | -| | | stri | -| | | ng | -| | | attr | -| | | ibut | -| | | e | -| | | name | -| | | s | -| | | whic | -| | | h | -| | | can | -| | | be | -| | | inpu | -| | | t | -| | | to | -| | | ``ge | -| | | tdim | -| | | attr | -| | | ibut | -| | | e``. | -| | | ``di | -| | | m`` | -| | | is | -| | | the | -| | | dime | -| | | nsio | -| | | n | -| | | numb | -| | | er, | -| | | an | -| | | inte | -| | | ger | -| | | in | -| | | the | -| | | rang | -| | | e | -| | | 0..r | -| | | ank- | -| | | 1. | -| | | ``fi | -| | | eld` | -| | | ` | -| | | is a | -| | | stri | -| | | ng, | -| | | one | -| | | of: | -| | | "nam | -| | | e", | -| | | "val | -| | | ues" | -| | | , | -| | | "len | -| | | gth" | -| | | , | -| | | "uni | -| | | ts", | -| | | "wei | -| | | ghts | -| | | ", | -| | | "bou | -| | | nds" | -| | | . | -+------+------+------+ -| None | ``se | Set | -| | tatt | an | -| | ribu | attr | -| | te(n | ibut | -| | ame, | e. | -| | val | ``na | -| | ue)` | me`` | -| | ` | is | -| | | the | -| | | stri | -| | | ng | -| | | name | -| | | of | -| | | the | -| | | attr | -| | | ibut | -| | | e. | -| | | ``va | -| | | lue` | -| | | ` | -| | | is | -| | | the | -| | | valu | -| | | e | -| | | of | -| | | the | -| | | attr | -| | | ibut | -| | | e | -+------+------+------+ - -C.2 ``cuDataset`` -~~~~~~~~~~~~~~~~~ - -Table C.2 cuDataset Methods - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
- -Type - -.. raw:: html - - - -Method - -.. raw:: html - - - -Definition - -.. raw:: html - -
- -None - -.. raw:: html - - - -cleardefault() - -.. raw:: html - - - -Clear the default variable name. - -.. raw:: html - -
- -None - -.. raw:: html - - - -default\_variable(vname ) - -.. raw:: html - - - -.. raw:: html - -

- -Set the default variable name. - -.. raw:: html - -

- -.. raw:: html - -

- -vname is the string variable name. - -.. raw:: html - -

- -.. raw:: html - -
- -Array - -.. raw:: html - - - -dimensionarray(dname, vname=None) - -.. raw:: html - - - -.. raw:: html - -

- -Values of the axis named dname. - -.. raw:: html - -

- -.. raw:: html - -

- -dname is the string axis name. - -.. raw:: html - -

- -.. raw:: html - -

- -vname is the string variable name. The default is the variable name set -by default\_variable. - -.. raw:: html - -

- -.. raw:: html - -
- -Axis - -.. raw:: html - - - -dimensionobject(dname, vname=None) - -.. raw:: html - - - -Get an axis. dname is the string name of an axis. vname is a string -variable name. The default is the variable name set by -default\_variable. - -.. raw:: html - -
- -Various - -.. raw:: html - - - -getattribute (vname, attribute) - -.. raw:: html - - - -Get an attribute value. vname is a string variable name. attribute is -the string attribute name. - -.. raw:: html - -
- -String - -.. raw:: html - - - -getdimensionunits (dname,vname=None) - -.. raw:: html - - - -.. raw:: html - -

- -Get the units for the given dimension. - -.. raw:: html - -

- -.. raw:: html - -

- -dname is the string name of an axis. - -.. raw:: html - -

- -.. raw:: html - -

- -vnameis a string variable name. The default is the variable name set by -default\_variable. - -.. raw:: html - -

- -.. raw:: html - -
- -Various - -.. raw:: html - - - -getglobal (attribute) - -.. raw:: html - - - -Get the value of the global attribute. attribute is the string attribute -name. - -.. raw:: html - -
- -Variable - -.. raw:: html - - - -getslab (vname, \*args) - -.. raw:: html - - - -.. raw:: html - -

- -Read data for a variable. - -.. raw:: html - -

- -.. raw:: html - -

- -vname is the string name of the variable. - -.. raw:: html - -

- -.. raw:: html - -

- -args is an argument list corresponding to the dimensions of the -variable. Arguments for each dimension can be: - -.. raw:: html - -

- -.. raw:: html - -
    - -.. raw:: html - -
  1. - -":" or None -- select the entire dimension - -.. raw:: html - -
  2. - -.. raw:: html - -
  3. - -Ellipsis -- select entire dimensions between the ones given. - -.. raw:: html - -
  4. - -.. raw:: html - -
  5. - -a pair of successive arguments giving an interval in world coordinates. - -.. raw:: html - -
  6. - -.. raw:: html - -
  7. - -a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc') - -.. raw:: html - -
  8. - -.. raw:: html - -
- -.. raw:: html - -
- -List - -.. raw:: html - - - -listall (vname=None, all=None) - -.. raw:: html - - - -.. raw:: html - -

- -Get info about data from the file. - -.. raw:: html - -

- -.. raw:: html - -

- -vname is the string name of the variable. - -.. raw:: html - -

- -.. raw:: html - -

- -If all is non-zero, dimension values, weights, and bounds are returned -as well - -.. raw:: html - -

- -.. raw:: html - -
- -List - -.. raw:: html - - - -listattribute (vname=None ) - -.. raw:: html - - - -Return a list of attribute names. vname is the name of the variable. The -default is the variable name set by default\_variable. - -.. raw:: html - -
- -List - -.. raw:: html - - - -listdimension (vname=None) - -.. raw:: html - - - -Return a list of the dimension names associated with a variable. vname -is the name of the variable. The default is the variable name set by -default\_variable. - -.. raw:: html - -
- -List - -.. raw:: html - - - -listglobal () - -.. raw:: html - - - -Return a list of the global attribute names. - -.. raw:: html - -
- -List - -.. raw:: html - - - -listvariable () - -.. raw:: html - - - -Return a list of the variables in the file. - -.. raw:: html - -
- -None - -.. raw:: html - - - -showall (vname=None, all=None, device=sys.stdout) - -.. raw:: html - - - -Print a description of the variable. vname is the string name of the -variable. If all is non-zero, dimension values, weights, and bounds are -returned as well. Output is sent to device. - -.. raw:: html - -
- -None - -.. raw:: html - - - -showattribute (vname=None, device=sys.stdout) - -.. raw:: html - - - -Print the attributes of a variable. vname is the string name of the -variable. Output is sent to device. - -.. raw:: html - -
- -None - -.. raw:: html - - - -showdimension (vname=None, device=sys.stdout) - -.. raw:: html - - - -Print the dimension names associated with a variable. vname is the -string name of the variable. Output is sent to device. - -.. raw:: html - -
- -None - -.. raw:: html - - - -showglobal (device=sys.stdout ) - -.. raw:: html - - - -Print the global file attributes. Output is sent to device. - -.. raw:: html - -
- -None - -.. raw:: html - - - -showvariable (device=sys.stdout ) - -.. raw:: html - - - -Print the list of variables in the file. - -.. raw:: html - -
diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst deleted file mode 100644 index 43aa0530..00000000 --- a/docs/source/mvBaseWriter.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvBaseWriter -======== - -.. automodule:: cdms2.mvBaseWriter - :members: - diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst deleted file mode 100644 index 3d2de85f..00000000 --- a/docs/source/mvCdmsRegrid.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvCdmsRegrid -======== - -.. automodule:: cdms2.mvCdmsRegrid - :members: - diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst deleted file mode 100644 index 057ed975..00000000 --- a/docs/source/mvSphereMesh.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvSphereMesh -======== - -.. automodule:: cdms2.mvSphereMesh - :members: - diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst deleted file mode 100644 index e8c41c17..00000000 --- a/docs/source/mvVsWriter.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvVsWriter -======== - -.. automodule:: cdms2.mvVsWriter - :members: - diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst deleted file mode 100644 index 89fef4aa..00000000 --- a/docs/source/selectors.rst +++ /dev/null @@ -1,6 +0,0 @@ -selectors -======== - -.. automodule:: cdms2.selectors - :members: - diff --git a/docs/source/sliceut.rst b/docs/source/sliceut.rst deleted file mode 100644 index e14aab4e..00000000 --- a/docs/source/sliceut.rst +++ /dev/null @@ -1,6 +0,0 @@ -sliceut -======== - -.. automodule:: cdms2.sliceut - :members: - diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst deleted file mode 100644 index 8fd37354..00000000 --- a/docs/source/tvariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -tvariable -======== - -.. automodule:: cdms2.tvariable - :members: - diff --git a/docs/source/uvcdat.png b/docs/source/uvcdat.png deleted file mode 100644 index 75c1cf72d8c2a3938c550b1c938bbf7bf4957667..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37672 zcmV)oK%BpcP)thr000U^X+uL$Nkc;* zP;zf(X>4Tx07wm;mUmPX*B8g%%xo{TU6vwc>AklFq%OTkl_mFQv@x1^BM1TV}0C2duqR=S6Xn?LjUp6xrb&~O43j*Nv zEr418u3H3zGns$s|L;SQD-ufpfWpxLJ03rmi*g~#S@{x?OrJ!Vo{}kJ7$ajbnjp%m zGEV!%=70KpVow?KvV}a4moSaFCQKV= zXBIPnpP$8-NG!rR+)R#`$7JVZi#Wn10DSspSrkx`)s~4C+0n+?(b2-z5-tDd^^cpM zz5W?wz5V3zGUCskL5!X++LzcbT23thtSPiMTfS&1I{|204}j|3FPi>70OSh+Xzlyz zdl<5LNtZ}OE>>3g`T3RtKG#xK(9i3CI(+v0d-&=+OWAp!Ysd8Ar*foO5~i%E+?=c& zshF87;&Ay)i~kOm zCIB-Z!^JGdti+UJsxgN!t(Y#%b<8kk67vyD#cE*9urAm@Y#cTXn~yERR$}Y1E!Yd# zo7hq8Ya9;8z!~A3Z~?e@Tn26#t`xT$*Ni)h>&K1Yrto;Y8r}@=h7ZGY@Dh9xekcA2 z{tSKqKZ<`tAQQ9+wgf*y0zpVvOQ<9qCY&Y=5XJ~ILHOG0j2XwBQ%7jM`P2tv~{#P+6CGu9Y;5!2hua>CG_v;z4S?CC1rc%807-x z8s$^ULkxsr$OvR)G0GUn7`GVjR5Vq*RQM{JRGL%DRgX~5SKp(4L49HleU9rK?wsN|$L8GCfHh1tA~lw29MI^|n9|hJ z^w$(=?$kW5IibbS^3=-Es?a*EHLgw5cGnhYS7@Kne#%s4dNH$@Rm?8tq>hG8fR0pW zzfP~tjINRHeBHIW&AJctNO~;2RJ{tlPQ6KeZT(RF<@$~KcMXUJEQ54|9R}S7(}qTd zv4$HA+YFx=sTu_uEj4O1x^GN1_Ap*-Tx)#81ZToB$u!w*a?KPrbudjgtugI0gUuYx z1ZKO<`pvQC&gMe%TJu2*iiMX&o<*a@uqDGX#B!}=o8@yWeX9hktybMuAFUm%v#jf^ z@7XBX1lg>$>9G0T*3_13TVs2}j%w#;x5}>F?uEUXJ>Pzh{cQ)DL#V?BhfaqNj!uqZ z$0o;dCw-@6r(I5iEIKQkRm!^LjCJ;QUgdn!`K^nii^S!a%Wtk0u9>cfU7yS~n#-SC zH+RHM*Nx-0-)+d9>7MMq&wa>4$AjZh>+#4_&y(j_?>XjW;+5fb#Ot}YwYS*2#e16V z!d}5X>x20C`xN{1`YQR(_pSDQ=%?$K=GW*q>F?mb%>QfvHXt})YrtTjW*|4PA#gIt zDQHDdS1=_wD!4lMQHW`XIHV&K4h;(37J7f4!93x-wlEMD7`83!LAX));_x3Ma1r4V zH4%>^Z6cRPc1O{olA;bry^i*dE{nc5-*~=serJq)Okzw!%yg_zYWi`#ol25V;v^kU#wN!mA5MPH z3FFjqrcwe^cBM>m+1wr6XFN|{1#g`1#xLiOrMjh-r#?w@OWT$Wgg6&&5F%x&L(6hXP*!%2{VOVIa)adIsGCtQITk9vCHD^izmgw;`&@D zcVTY3gpU49^+=7S>!rha?s+wNZ}MaEj~6Hw2n%|am@e70WNfM5(r=exmT{MLF4tMU zX8G_6uNC`OLMu~NcCOM}Rk&(&wg2ivYe;J{*Zj2BdTsgISLt?eJQu}$~QLORDCnMIdyYynPb_W zEx0YhEw{FMY&}%2SiZD;WLxOA)(U1tamB0cN!u@1+E?z~LE0hRF;o>&)xJ}I=a!xC ztJAA*)_B)6@6y<{Y1i~_-tK`to_m`1YVIxB`);3L-|hYW`&(-bYby`n4&)tpTo+T< z{VnU;hI;k-lKKw^g$IWYMIP#EaB65ctZ}%k5pI+=jvq-pa_u{x@7kLzn)Wv{noEv? zqtc^Kzfb=D*0JDYoyS?nn|?6(VOI;SrMMMpUD7()mfkkh9^c-7BIrbChiga6kCs0k zJgIZC=9KcOveTr~g{NoFEIl)IR&;jaT-v#j&ZN$J=i|=b=!)p-y%2oi(nY_E=exbS z&s=i5bn>#xz3Ke>~2=f&N;yEFGz-^boBexUH6@}b7V+Mi8+ZXR+R zIyLMw-18{v(Y+Dw$g^K^e|bMz_?Y^*a!h-y;fd{&ljDBl*PbqTI{HlXY-Xb9SH)j< zJvV;-!*8Cy^-RW1j=m7TnEk!!L%G_}Ibekb|EZ?v-uq&3xPZvo2NsT~i1X3dqX9QBf z7iUmXS=V+10sykvkWzkt+oWFs)Bti~kx3#PK+T5&K>(cwM0ACqNZiv~02|r!{1?H( za6Yn~K)o~|W46PPY$x{(Nw*sY^HM1_0;v&5jet1I`}2&2||YpOJ%`OQbMAP14dF64LM%20DVA{^1X*;#>p_StfE0 z&FOQb6A7Mfkb?F=K>QOkV(|y0rqm;wO4GvR;UN>cR}k&UA?{7!vPXfLVYx zfE)m?wlqub+*2Xx=?={XWm^P2llo&h@;bYECgttAUTNtc*Y&1n0}=!fX1Z;%p~xe5 z)D*~jx93YqmeU|>G?h{#kQ#woYXnljcWXWG>vFdfpzJ{1$-M;{2Dx-RNuIBjy*rXqP@dx7k#%#vIW zC4{Mz8iCXZ+zKO*0=`?}DPO019GL@k2RYq@50o8{$qKNt0qh8P7W~F0=H%r0L3tU} zSbP7ZjL-SS2>^0f!^*`F`^g*xe+rc0hLTJYYQYVFJ1f*xgUXxZENf^!H-+q zBkS|L9pE}TJ}b{1X_KSpdc+2nCxMmyFcT?7FW8?Bt4+3+XUPLw3+2(h#ga>HnN&)R zKxzbT>Jdl*-%b5^ug}em&V^L}Y*=S7%D4xd7k|)ZWIjEcwF6c8U|!-yC?S1UCGi2RglvKg^E?KLTp+ z;Iy1+=##F&N$DP*mWio3vEsVG!1)vg+YqjAk%}C*d~k1>d}4p8WTyadevDE(sS&u@ zMj!=zH`^1vPWMBgIo3F$tRA;GGF%dXOpdgY4Zsq@{@IpcP;N?2G!Dx1pzwUyC-q0U zTpmE|L;EV_eYcfM=g_o#_4{XKIvCUxVs!VZ+3AGx%lmhh%l-Q*Bs<$F)7~I7J|iGU z%FhJ6NFLkQN-@|H;m9I20BXa-V5`2`B+c_;w<^)LlyGK zt|BPN#1xF~U}`@#0;v(WAx9tud^hA{duKb{(mSpG=7lzS8EnhEOs9PDlRKp-*DVIX zV|vCXPrlwRKYhDXYVti&1U6+xnhn5WXmCt-*<{zrfBGg})#mQq0eAt@c$7B910OT1^n@3J{$(g1; z8ACrc^%r|V98)8d?A8O2H~#uvYvj7MXvxmhWwII=crD)-dumjHNO8dRuV**-Zd{j+|}#sv02xg;c6E>L@i zsSRe?+wFG9y$9FIZQD!b#Wz~yWb**ze_+X)l_FaQ0GNP#_`;yncaF z-d`mJ9(!!jaE%aznt@pn|Ey9$KQ0!)@tnTLn5M&r><|e_y9Jqwr&4MJ zQX_EfM<4}!*M5v|iYuJ&oYYj_v*!ndz~F?o-F(7?KRWG~7XXeQJhTREQJOUvvS&?>yjtHcevnzQEJ)TR+PERJoACOi zA9A~jk_-vJ7BCEX_#58UGQKd)XvmD$FBbL_^=7FsgEC}e5^plVn*G52wP1saoNOA< z$}qe}bYef!oL2F|4)D8gUXoLn#^ehRRjU1k0O*-f2~G5fnwu0g)eACr0C^*#y!atc z{9f#jg~2VlQFEXDwE}S6*#JCfs(K3HdZs{0c9mE%O2sJLEJj{!Y?sX1scmWmQX_Dc zBai~Vs~o^vq54zD`_wm{y9ni!SpZO&LIQ?JKa^E^ho_{yXF~q*)fNdxs6TT|ICE2* zQiBfuP{v1x3IFt3o0R0G$^CnZAy)%V(BMzgWoFGdTNJrxYq4wti_{Mw(*Os=1C(iC zv;f6O+fmj?C76GFx*p&dl7m}IW&7r$Fy)61X?7^eQ1kNx_txtEox0EuO;KPG`bQaM zbkYC_MV<4#6Y`(_rC$Dg-7~T?cvwQyV-oQDQ6IFf1wU>L)a8$fR2=!Gym@Y!RAdpr zfe8gAG&zW!ehCdVhtDC;usOuYEEUVf_bc1Je`kmzlQmN*H3F#-Sj7=Y$@o@rFmJY| z2q52lrd9ppn;l>qDoyD{-y^BHqI4%%ofhexn!N%vSeC>M(Z&PHYYKoxvxF+h{r==v zc1U5KTOWgkDsR>e$p8FB;}zPStnLR;9a>i)zx^RlLZIUO;9-)DNp>W01#p2<@YaI% zpLn53-T;uzp$;iQJAmwwLu=Bux>tx(;mFwn96*N$D13!Nh}3xoL~+Ww)AcA198 zqk$03i^no2pU-(p8 z%0I2CMVSS)I5#eqybWSK_`711-3D|gGdYz~Baj+_)fj;k#kU%xcoVkKJ2I>O^rubo zY{LN9krr{7luXpUlHEB186HzKKtvVMRM&@hmC2Sh+4AKd*K3F(%W-nj2dd94LA0Bd z4y{X2lQb}owzXqBgfuFf6lS@^fqu}5b(q=eeaP);FX6=<#|v3b|GWv@n-S@nmvlc|U-~1@_@XdrPGY-dZ^8Q$E-;HYl0 zk8YOzn+kM(Kh8%Of@XES^@7aWQ=KdCg?$|pn$zV-&C$yz$vRSfmdLgOZp}VXkS@89 z<2AGm>pC^n`C<7U>*L4kM2J3pJ_s-+E)^AJ$VVU8B;S3yPSzA<$@;aq@=rgn)AB`K z5P$3jz!MPquVdTgoUc?qcTb_*y}KGG(xK&(VHR827E~h87GAX>^Fy+h9|*TIH;xXb zD8BGur2eKx;Oa+U=~?aS+fTJ{gN?wMwh8s6AJ)so!Kr0IZ?RhghG@kWA6S^Tug{b6 zf;7#R^Z@jr_o$UhdZ+wwSJnmK%hv#Q7d)pt-`KyPNexawsoU1&NljI{3{OJ&1)0p} zH3(J)WP6nEF_(J*041r$_d$8)-u+boJOCZaQT7)uAFfBRG!yfKIN#AZCYb=t|NG;6 zQ7{)RIY2e~L2X_J9)hRa;*+}R9QlKn?eYidF8R=|s{}o>Gx4_0lsQGbVM*ns zMqs5QkOIDyj@(UHukO;M`r`NNrDJSb(jk*uX(FY!p}->_f`R(&HMu%o-cOEp$|P8p zwAEV=k1aj$qLSlrXoVMEXV->2*;1S#C!s{*j3}5;5ypl6OotsT(+IT(P_vq-1@Izh z5%TE9j4V&?Q}Kp&e54K)P%2zJ43Ii63iNnw8#F9i+lS=I7tU*q&)c?^$j;5Bk`8~N zzxwc2dF8E3(%d~7_WQ{SNN5^ikAl!1osj?j#AzUBt@_a3VrHjOY6Mav@Gc*LWoNg} z@BEDl&Cw<)xo^7Y{T~ol+1lhPEi+hwi4oQJ)Dsezg4`uCIWAR2LC9kd%!tc7AgT^up4~y z?G8D7wo5D3unjX&Q*{pG{@;GwNPtxzzU>A8KWdoCFyRi%%+vmdH@4<&_#o@ft|L(HDcj<2dG!v6}9}=8^Ih){>&fKzv zz_+Sn;vXB7j&D6Kvwfqm^R3;QR#3t*jK@YeL!Ka;6QUH8QA?(c#Jd#wst1TS7 zcvigM{suG{q0Erzf&=%eya1OE{Ib~ge=w;obdS!d-~E?!p!8;R)B-e>bmC*51$fX0 zC*^p@y2fM>QD*5O#S3jpbDhH5xd6YJJF9Z!gZs-hnvp^Tm8KrpSu7_nj>=Q#dc_0T zBFoO;1s(=aLa#*wA3GMr2@5W0Dynb><&Vjv`l9p9b8L_Oj7`)utyy0nr3i_167JRB ztnZdOP=Hg<_~gMm*2}u8Jh}V!HPQq3YW0_fbV#M>HmEu32l)NTla1nX+SNnb^UO;| z7kg*-1F$U|Z&5M zmcMR%8ShVWi?--CmfPn$z(tWxIG`i-N~cGvJOxsbU8Z)GZI#;W3fWY!!LVGzek|9| z*z=>4bLyKfw8$Aacc&Y_M3N8R-N)dn?<;Gw5-G0BjG+A&|Miqi3{8nOioKt31MiZ8 zekiq7Zz+*I_pT%GUD2y6b7G1ZHhPx8FG=9LCMzerr1Skr0Qk6WWUy1O-zpxMLq*$C z$J}PzLj&Jmpze+9417@4uRn}QA6`6?`S5@oMutbMI}T#@U-q%i-!JXJzxjNt2G|X7 zG1eRL$TD9bfgPGUq+#-Z-=-3It9?{DM!m8Pt1UOkw7Y6@jP1X@PyP2N8sy2kKJC2v z{`L8?4{pmGz&1oMQl#dn(dkBofB%6EidvkM_c@?78a6AyEpfuak1{?29$A_MKT?2P z;E+Njr5TJW$1(;?D48~B+?MyO+LstiIkollox;3Gqui6Nwarc0{s_6&OayR?kw3^RIBc< z*d>qD-iJllJO3=3`=;gmKv)D3fAp>#F@Be)x+i65Y)<88gPKhs=_n?6&*{rQ@qephOlD>R2nd_5%>%F) z;l(ruGlbxM1-VY+k3O+g?K_bx-#gMFtx#5(fwz|#1hb{mN+4p+z`nDh`NOVGeAT0& ziRaBcla|qS@Fy0-sNHG70xuT;*xWNFPOyAw`}gYUPU#t(fWOdem^q}$xEGv&IFq*x zb^9S7{o@~>m%se;sZi&OVd{>fLURba z=Nk3s#%rzIsU>J5Vic-Q#kq zeMCEMUZnUH*#wv%faw6VEd2Ef|)ns+A8MUqKBBM4JSOP?7VH!BC#j>U{}x!ouyBK(%Vp- zBX7cIC4wC0Pe z^LbAH_&1#9^RZ*rn?J`q^B`(V_6R$$8D3&)%W^dPl{dqQhvp3DT8E{NvJc(KsERSW zY2e|WY#WiUKMi?W%(;~us=+!HeDmwd|Fh4D|Cv9K!0GR!8Gv%l`*9;tiXiYBqb~fD z3Z3{L0KIk;0pMx2cf7k@Nl$LAI(#ol1w!dXe$jJIKK=7QmY+2|vl@>yse!D6;#o74 z&a5k7L%XnOJJUKQ!xMAYz28aQoNN0#9O`${AYAL6h7?MeCLA2!I` zY*3L6uYnAOxHUnFTLO^}Q5eYHWCASfZFnEY03eo&PP%>^xFPko3|{GG2y*K|)&1&Y z+hsG9TF5Ebu_h0!u&@lVx;zImJjbH4KC>?b`yUxP12^zo=9HO9dOg4VR$srbEz6rBxdN52)sjxheUN zul}Wc`_vOE$T7Z7=`g~7QBfu8^-uW9R5m-0#aey$RKj&`g@QLdt5ZKjOrW9iS_FTC z@ESfPub3^Dc+ym+33gqSU`La(uHSQcqFJKON>7C@fz3JGi$#3YV==*wjZ!DUjtpze zTndds+om#TiVOnbVMrZM<`d}@qxm#Wgg}kK4h^i|W_V|L8`NI3f%bC!XTa8N@R0KF z0D2Bka6W(@=?(&m2}Jnb7QhcFzvljF`TRehl}>~!8i%Ild8lUZTAvdJBuM!b(24)i z49)L!eGa(!W4|=8#oWGmp4Ug$E+-rl@OVC6Vt#aSvy7(jz_Pq^UzHR=;b-5DGO@jO z5mabUYkwZ8?^(1>vyJdLgyes}cu}@hWT-8r2s^Y~!s05_eO!e)j!Nj#E1=rIQl%ma z`SmgEO53(y!i{m1kYI`sI`bE(_blEGXCyz~orR01{;q5UTvoe|Ao7L7e=Eb&qw4c_ z{KoRnbY+*CuQdlBeW$@@2Lptk|B4dhPQG?_08ZZXS5*IItQ0lF-i)^wxhGIFMn)E7 zA{!+5_9?BUn(*D)Y!VtCkznh20q`YUZ6yT*%?%P79Yp`2fIyOo^I8U!IhQq47+zUt74rmfLAco&)#347qomy~5fHc&e4l1 zc;P7tb)673)CBhW6yAX}JWKpy6DSQMXANxO_RpVDXa7ot+5vhrf6;e1e=4=J$|FE_ zqs#7;Z=C&!lxF0qPwx28;xE7|T)P>R+J&BJu`i*axZGtJ{_EA&5g8fxsoX5bHSOzcqjlwn;`>rr5XLDZXPzF`*>6cEU<8)bzHQ#ZJvtlU%VAS}< zwie-S+>u$8S7nzu2b)w3KQ%r*{t)fka3G**Mu84$sso$S5SiXNd$Hw}%BxdsWo zZq+fEF<7wRx|+9|3q^7;UTq$}2EDv7o4hqBK0F)chpVL04Tf#)7Ue(v7Cm; zh*?>Ufud?UF1Ec7E>`NQ@`Ei6m?4J%dRV#hsl;M40gj&+^3@D{Q^G_;yy({q94LR_ zGh*Kh4L?$O`V)j36tK&5LYz2b?4k@nwAqyZuvh{57H~Us0NH-JKMGS};lhdkrN-L} zh{k@jWkh<1X5>@%ts(dsZglGsqC30uA!WD(b@;d(|_?;c=kv~87kMd{l z`y#H6XSs@L2#eEG?XV|Z;WrxH6`C?M_DxAw|BNaxNiBnyAS?udEdlK|as?NL`o|2jd*mc^(SLYD_d1w`O*d*9P zl*<>}miNJaZ=+%4tTT*U{@`w@WLNlyAg2B;pET+#KPj^o4}d5HHeE^^g12*MHU|EdWExxRy!;PwH*_3;_E1@1BE^I@MD( zc5C>KR~OnlOM)`iI5w=@$(9z5iLPRR_V1hFoqA;I*8qFrIfpPQ4jyP9$~laizw%SfX4n zmENflpuF#ii-+ae#+Md-XII*{V;4qb5K3UctgB8GEp)yHP{8aaDFzDsW*PH zR8)zjblsAlM#n@*jUdF1%>cCrr0In}z6*#pU?u8YWzuX;2;QHq@0auK$7U3W6>w|CworOOfrl{;lYvDXypC@BF zpzFr1HD5j99a4R1X*St|C=MPcWWcy+2=c&kXuEncobup%Hp;I(yiIB=^K{4~deInx zJGjST;^2pAyk+w*8Ma6M+OR+PXJXy<5j=a>((e}Jf7Y^HViayOWU2#ly{B=1E0_Bu zcBA1Di;OC&tk&`3S6{6w#A|2qtFHWv4GZEK{JweW3Gw=-dD&G<$lm_RH;ktKRJ{HQo5(%E#&z!Y4OB{8n3N;csPK;xegx@gaaTvb() zZg`Re87If{ z9DIy!-&mx59hSgf=|gv|m+$`U9PAfu(mpsTr{S`#bu6H2a-miW)|gRwhheKcBb=(lo?_liV0u?1j7-=H@Buzxiv4f5F&!8;V)SAm=|m+N-}b0-L$m2BRBKZl6>e?eZ9J&kg`cwq-h{u7u2tTB2Q$g{>=1pMPIXU^71g z-nO}K?wDl=?6Ju_$NcEiIzKuiw&D`Ul)0R~&@Zo^>JTT`y_Dnep6Su0Yj{fFa#Y(~ z&BC)y0n9$`yS-WlG46%A>5`R`CY?S*HsIO>{BXjU(Exq;Vz`s@`H|D0_NcIA6u~d& zRHsrshf(<|KV5yLtbl`CPpp3vr?NxN?id*6RbwRuHblbQ9_^vq5jBJG9de6sqh!^Fk zl(o`C06p=1vrLY7^`bD*c35vcyg^lMDngYNexRsnh9z>~`;3?3=f*2}6Xn_VzE6BV zdjd<6#VMsLZWk|&f(RJ*#FI+iqT$?YIWm$Lz2!n%hf;p9R z&xBM3Vi2-!sOyLdyz<{fjdtO^0?RWt!PLc4`)dHHOhcW2LMen3TKW5jQ6b=ERKfGh z{bI@4%-DDUJxtc`u(y|cH{NaF7kl^D!dJ27O*=JUjIJ zm+VDJIbN9PmzSDemPfZgnr!te%D;hlkX}$;X>mg8Tv0fQ3@*}MIMXlh-&-8FR$h_E zc;q*3k9#iJ%;wWQY67zUs1@F_O@#2xY`bHvy!Vqk^|!HXg%uWvH>IwysT-%7rEDFv z<4QT}Ce>-0H3YjZ0Fc@_r>;s0w4Q~cN;`lf286L77iw-UlBlI>-+52t>UbWFu27+cs|QeAmNgHF_0ZSEvhkN;aES@VUGR>B z-g0BU+UH$Pk5Q4g*0{6!pz;44_>A$xNB>0bE!+sU^&H-*(dG8R-n4G`xL9_6-Vj&*wRs7a z>%+VB{KmqK#$P=6hw_24?V#d)^RHGi-DLpXw|X0-Vd&!J7b2MkB4rx@Os#{{pgvds z5%JR>#{&3uuu^a3bV~vsCl2f8+rc`*$~k7mzU<2Y$}HG;6qDH1uSyu_FW7htB$-P> zBY=ejp9bZD*0r^8Lqp!AkASFHVnI zES5U~b|m-Cfa;tB^|7YRLr_z_V?Oml+d18f$E7}4?n7C_qr4EkE{+NmEOb1xWorqBJ znPjqKUg?Et%4>+@ zx6;JNf24T?^73o5K;@#>iv{o-h|zZ|rv#_kn{SA$h}K{&tAbJqc!5bI0|8?F_3)`U zGr7_!X#Q$ybU*@ajhX@ojo?v`%Hy=emO%h&AdGhvC_-2_?}snWyhSImfmsE2TbF@| zE4>qEyJct!K~xuEMdFIrBoUm-G6C+m?hnBZox_Cw`A2Ky-mUpiOf`%Pos;l;=#)Qt zWV75`Qvk=(N}7A8WC}OHeiOh-!=r!r!!46pmixpG9#d4Rk0W_z*>G<1 ze_5Y^zH3XVtSQX~l@RU~ftt2^ekiuQ-Ovk10a&?1+jD3-Bxjn&WJCWma`&;{l#;>2 zqDbXMYZQXbM!>Ue|F~EyAZLNng>}sx@Xfg%CJdb_G=6bm`9!-7H)lpxwOF=%7WGMY zr_y30kb`gPiw8d|ZYU3#@7ZEym5(y>{YG_nKZD*6H6u)Sw2>?0);V;NC z8mNZ`qNqLsUwWKxhn`ombH!G(C4QsGC3~<76D?(FOq`6z#%D3{!Y=4KgC4JM$A>lv ztY)x@yc#VP!kn*F+hzo4a zp@~_&$nZkPv)DE(huZ$9>^S*H;+h?lkXDY0JRo)|0ELtET(RHxWwGA*CBw4uVLUjn zIT?k4Y2-W%vEc0`8YshOmiddDhT?^FJ!FJwV3(%SvLmp+YOnDbL|mWodzUR6TY%nN z&Ou(=GdU1@Dxu>Rcvoo}onBN8$o@RZr41bX_*v!{u zxz$Ld?zYwzNo8S%20h9t55a2-wLSYrW)YR%DR(+rE$modv)Ayl@2aLr zSKPA6w*79Xb^kq3f_@W|U;$y)3^dk@6GCuUX|8Depy#WC7n^X|$V(2e(>^%6VNhEg zra~>5pkF+g!lzKiT%v$tvu@c6*$?clVv?HbQ!>&l(}TSd%KwnALZF+3&%YLUYDpU3 zW7@x(LvS>8b=nV7)>sei&l8u1r7XiOpS^b-6hSN+=m?HfiZj`pL@@#v^Vxq=RAC?s z16(){Cs~f?^)4wdb01q~>ilqC_-J+h(s^}GmRo-9u^s3?s8fLT%SSHB&rkG8R&Yvw zFZ&JoMCOa)u}+9jL8crvsW~h@Xac&$w(XVclR@k~OR;9|UA_Ry+xK81GgDw%Lai^Tz#CtK z$N&FJ0zdkU_y^9T+3-YXhkS|Z^aGGJt(K=2^U}#~2}~CJF;}#=A+q^bKDk})*AsN@VA_h#4k?-L#k-Ou@IhW^q`~mL^w4VF?k&^SeHFVT6VHI}V={@QPl4STge*Rp zbgFq&b&bs?Z8%P?;^cbB^|m4Xh(`T(OT<}vG9A4M%HGnz$LD9?br&YcR{bd?>r*c>)(dbbj!99|zp( zAM!a*nfu{wm;&St@c3FJxDyaR7A3aHe))3t6Y{mfe~|6&1^}J|_YnTfG~ihRxG$^x zyl1z3?ZN}{%3y``UU(ZmShdITxLs3_?I|y#T_g#7RBFj1cOd&6eDZN`>4wPMzh=Lb zd*Ev|Neyl;>_%oMrDwD&ske>p>?Q$5=E5+MLE<-14yO-pd|Q0)lS!x|&z&PBsJWwLIllt8g`r`eXw6^ zL;OI*IB7r4>XWgER&vUjSN(3 z@j|JjyLViB44J>_>%2oyD~DF+=O5i9+c)G&2An$AuF007e78(^$<(|INc?#9aU_rX zn!Sk~0wELg2!h;(f$d7!o<66`hCz>Y&HC6~)f9k;ODE5onmGkRNvLlDf$fnMli)zVsq#>1Ysn;a??Guv-~x5ox1f^8%n!lkI3_ z1-&Q9o3}0L_tWh2t-f{IUB>PC)#}1HsO=<@fd$Ys9M887w@XDHzQqL6EFzPfXrIvT z?!XXFIL*M=`;Ogt(m(8#moAMa<#vs-zBACCrontcu5-aVmv9Ge(1N!-#b?PbH0)dU zi1Hy|T@uM~z>7;;orDHEImafIf}O1r?C;cO3~?*ssVI1D@weHr(uYIc3?;UzfY>(R z#LR0FIQ=is@B^EaQMYyQ(y)Be3eCWg>}}$6o*2KB2CR879swmT7rfacL=xs^QgP8#nx^v5Sq?0{KWIvi`^ez*A1+V!4udQK^jIJHgiu|F z`;oFN&!o@ePqM4xaP4@1ac!`ZX_r?rcuWqw{d=PsZpQfltoY8^BGt#Zr=A(@i)!U=3Qg9Dvp6%i&p()LbG76JD?f za=z|1L`_d@RcAIEY6Y8f2I}i+8D`d%Tg;oGVZ;E0`oA5@E|x;V0TNNbh*7Aau`Q@Q z3p~s8=kFIUz|bB5wFuJ-x(FMG0rfj!#-O{4kCESFP6mJuUD6=NkP%UdpDT0B`Gpjo z&ch!wpU3=ZRwwqDPtmL{$9(LuKCi`VgzI5v!7&Q1LJ9)#xMIxkc1X>|e~{9yXT|Ot zmw=55N8$I!0#gK1dES6iULD*hPjzpT*4aGqdNO4c?6X2LiVrsCr^}Yo3h0LWuOQT$ZYM0WyrEaEJPR- zV@U=_or0reI;XwfiCT`7>$#!$VTBn3C8-hk)_^tNpU5rpSc6{VSeM1V1~Ht|N-x~% za-^l0XC8+^Q0GPRvC(CiXM!s8R+>V1AOYAwu2H_Zvm?l?Cz+D1{U(+ljr+6HIj&<0RwX2N6%8$QFjr$YR#Pb%fb0>=Yz zO~ZSZ$j#t>b;zNV8G|{ZE84msPAE&ymrJ9aNdX_DHH=IRB0P={L15yC05Ut&H#)11 zcZ`Z73BclePiGK^s>AOL0qpLr1@dYe*sDpj!^rGyqcd{0b3y=oW|waIZQ`^1%{&xX z)mb-hmq5d*@QON7b|=b(2H=IG=K@$#+oSPj(a{Q=dmZvQ&_2$kfznz5(4#4XCVQfq zqcRO$mciiJde48sHtKga&k+p3< zlJbt9O2$MR;Eh0dc`~yhraE-$WWvanBf;C{$)-~2olTcHur)_KIpU)%7B>?MdS;hw zU`e<1FXAPH2I!d{)W`UZjEThuijl{B>PtOWOuU9O*Sth(yTTE0LZp%7&cfJVLJNsc zmke}E&o5rTS7q4a2YofWbmaW7OoC!_CIMJv7-YHaa@UqZvl-b|mLd7@7&L`%Z?Om| z^MxZj`ZdB!{$}H_JOr~M%KdJIl=zdp$w$M!>t30A>IdKrk|CF1;;e}B{!=fDvub-n zl>&7qz~5SerGXdPk_&}*lhT`S71yGAx+@#rU0{q3b!jU;E;Fff-&LX0-xup`e~zs1 z%get7kO8=`GNcj-yL&y-9Lz3kpvwY1WHq;r}NMX^SK{xV`+Rqu`7}SwH3f5lr`NgWqmIK^u8zV$u3R#1>jKJ97s}l zcIA^{YoRn)w#hMdyG*!BWYB|{hn_U?f~|?G!}Az>vv{KXwHq#^`~kWH#??UR#A|v3ixr{Q;i(vHgM3W2DBIEy!O!-xQmLui` zOth67t6U2BBG1bxuQjYCB`Vn7ju$-fmj+)1D8)K)J_^8G#;iesG7Pm}Lb=O;wcvH( z43A4&N#xHJF5X9nQZqr`x2u<401`{hYYHefq)y>t(q|n57w#F(X&%EIZ|> z+9%`oVoA@jqTr* z7u8aD_rSVb`QC{hnA6}3ihg&lD7i3$@8I)w{VCvEI4rluk#+k$V*K=9!ZU56FAY|M zA%qtSwq8KIv(1YSlnO{N;;qF1Z$56qyk|-0v>lW165H0!RN^ z6jkFfDbCrlWX72d5Dc?x2|6w~eJ(8Uz!@#tO=2=OuanG{L*_?c-$WFM-J1&~53Csa zt~4pocx`d2pP%lrV^Vm`GjTxg;|#YZ;BlYgPkqdD$e0H_?DKs14|lFiyiNd$OfJ|y z77d&LOY>zZ2Zd(^g+(pRAWcT7MTulmcte(AX|mLUrMXXr0eCsk(p+CwA{qI4n79m? zo|r?R-{d{yaNHQZB08XLydLW{ydCdOq+bL-H8BOxJ^;T|x@IF#mR$~NoT_7qFNi6I z7=eR{aoF3IF48l88*d?I8rHb1&W-SHp z3Be1e#eVQ%%#xTe<0LhNcxvtNp^121OQzUY4u-Ins{LYF_rQWPs_P9EIQ?Brf_Q{v z(eWR)0RXWTY!Ikl%wOhuDz|WzISb{T83e)21-Jy^TysIk=X-T|M}rg&310L2IG#61 zXMW@y&l3=NcU)1kf|(Z$d^mkY;`oFxA+bNsz@)5ge@04sUXLcKQ_I9#~&ol@wOo*JAMbgmNoT_UZ*E0A; zid>P+CmevH*rCmNlIDsP2m_j3R$~Xu8rnvnER_WEap63Kh1*e3pa8xru6wg(q<}B# zi5h7+hNXI|lC!6m)w+zTru}1vT25p2J*14B_%Y9d?H47`17Dg9KAJ>Q1iqTbFv&&n zDdDFx@Y>hl-*EzpX5sdN)-)*`J|^26|5h3{d={W!7b~dDIe_x;$P6fwsQO7dsd3OUXb+ZE+~x5L4F5MD|To~BAE&+J}9yD7-e$8dO*&HHi*}e zFX>rXQd?cFw-(5ODc>dNnTd|7=?Faf-pq4LZNrc$GVW87O&j>dk}e2%*DTD-1F4-M zxRzN^E!Ji#f7ua8ctNskOA8A$4@^n(;IufLiL+8EO2~CPU@8P~io5~~TNSx)XR-Xa zejqk`$z#qA;2$7j%D8+Ip|h;^MH*kSl^f?|3ix84m9=)K7%%@s`{GcuW;+RV zL(bRNCDxocj15dwAvz+4)}Ac$La7e7m~qF66n zv8An(^5%b)%$asMz3KCqtP$80Y){ILuGPmI-7oGF42p8xk^wf1AN?mw(M)=eNEJ!u zE~!;BanA$}G^G<2PN=zQo@03v3`zZ&l%82HTnp3?D7+w8kXbW5l0SSxM?Ej>J1kZx z2ZcZ>(^+&#dt2d4UT_kO*%7pEqL;AozPt>e|O;P*%6uh{! z_D`t|H#xgA1$;3tkF9o(SPIG{*wF^hUI{5w?JGgfCA}cb9CN<%H*x@=HViD2Gn{zPz>N zKg)D(wG`%gpwWr8!cB%7x(0t~wvd6<=v}+Y!F@HfdVUzL!u{txpbI+bA&czmP2>bO z`iDOe+|zSG$(}${%I68lM~R+ zyk_p-ri+N7Bh8dVKMpep4Ke{SH>+3tu+X*(eGWVM0M`v3L(4ERnqyJDkL4rx5$^93p7L zpD28C2G0Eu1+eOm3Pek-&S3sVncn?bnK(Zp-F8w<|2G@bb1p>Bc-gUsH8jKQOqdVAOrgh8Aq}AJ zPOF_VX~`0MMvfE~=1X2#5uEX0;e&~WHe4!-rKvj<^N0O&f@Q_{hqL7I&M#GB3NCRN zzSG4D;2tKR5zL!LpB5xOQ(X57(7Q&@dcn1CfrGJ`QG7QGzv<;}I|wdM7PvK@sP8no z&e_&6)rkPnW`O4CbBpcssnf05(dJ?Kw}1IIur>Z0LjdbW+w{tkY$6apccxz++gEy1 z8?&c?FV34`-*G_vue})O%o14uyHIaGeivcZP_tlW3e>%^M8%j>oWI85*Rs@ zp4gcQaI6FcYj{D}t19;uTe$T;(cPKd)h1TZ9MK|O_AB+||r z@MI2d#B!wGx>K5=tkP)Iir11UxdmBLnV&D&#f4&phMkt*nY>or!qR^cU*Meg`y0>k<0sf`m^01F!&ZGghDC zisJ8Ma2!Fl;06Z-V}o)vSjC20S>xlDgAYEbpIvS-$8#FMpbLpR}oBXoVrl z^HMej%l2+z0SesHpwO~)J;LB%_V$6=i$=QTE@cjl*4c<^nsYaQnx#p39qx_C7ErkE zxqc}hctP^}k4e@q&1Gy|eqP>uxcWvIKTF3#@~s54+Q=|-%M==e=c{a<8(PH|{ zGv0tY-2(^K%hX@&G^xZSd~7V%Ox%1zJk2X!JUt-4c3)N8GB-nJ3i#qYMT847>|1v$ z->abd5|;B}n#F_{IDbwY5Au}`e<-2WlS&QsCI_JWB=81W@B5M%v*#sn_3OEZCT^VFTD{GY(RA5r@$PJh~E7m>@GRl92^j3>~YRgJzb&u?oQ3k9nNhu4n}OL7y6fJzlah zKAJJ)!ZCR^{CviyMnpsC8J*Q~_t)gXU}>X#A*)-yH+4WdRVL^l_<>vmnly+;5Q+O~P}e_n+Zu6!wbpuRL|Xgk z8p+VIy^R&{M+j;!Kxz-keEjBi{@zW5i=L6$WfahE!@%F9tz8IUX9opcFnU(9htEph z$Qj8SJtIy~b~*s80TTs!z=;3??*ZyX)YAm0+oajP1+2^(X_0l(C&gI5xFoj{(cck% zDkBepdSM98F(TlZU7GLX3U)~KX2TXCCks?|KV)%9Bu+HBh*xNha(Sm(pI3q7ePCP8WrqNK))=|{a;;Js%LcN{X1UVV z?)arK8JzM-S`xAMmb>0+o+sCcW)?JN-%xRL8na&m;KPhY_5EqEX5LMSfRIEoO4o?B zpa5nAr$7VC7ZxG)7d=9p$f@33oRg-70u8_eF#rE;piM_xPGAyZJB z?t@D-(swjFU@~znmd$Abp~=>y$w7!LOjNKF$l;STf9isi^t~cEFf31-=@%!$0ckcS zT*;YiOkRUBJK8D|WqpWxJ}&uk&bCLILe(;C6w0hE8!X>+sV>f!jNCjB%Pz32Aos(V zgsy_RzEw+$|SBH6iu&|ZIjoZMYVdNsb@q80n#Yb^sb|Hn&!jbn_gI;FT zB8car6O}PQ5et2NMwEJ@Pp9@18-XdjlWo((Nh`Mmznd*~cE(B5R;JO%MzMyy=mJ-cn`&bTqoXbKe?C z2le;F%T3bMIV$@haL>wi=@3NbIwKlP33|-eUiJe*Z8j+ee8zK%B_*9G8_`ir*H zWD^)X%Jj(IG}199<{-yy9^c9w92|Iu!1uj%0*uBTimS-%g(<^W05atm09&d_zVmi0 zN(-UY$tVrcsT(ZLx-NQaS(qPP=AGW>mlnW^^?1ved~|=gaySxvq2K9_CvpAdfp5u= zD~T(uLebzD!twZ$HxTB8=dRk2Tn|81**5Q%z%c*~$G{|2mTAR+7G|&&zz51j^>#ur zWmpV%SdD&}s`|9TM`kTqFP1f%uPAP**e{Y~7{j1^dyA@q$hJN}qRJ(02t?}ZtfJ=QhS zW~{|;jr760$_SjJdEo!FuqYQ49;iHk9!(K6E0fReI=#c39;UcBAOgloS{oI26T~3! z?rLo#a)+lu?sV13wqUbJ%Pjn^f)m`$(S2KX^sNxq!>wWRX}J$G`4+`DIwqmHMO3<%Y7cXVEi-xg(^j(!6Ajp%09>s= zu+%lobC4YcIxfMBOPiuWd#p{LS!~fQR$7+zklVSlFOxWt!bag%!?yWDDsb$t(Jm%H zOm0R_C9ZW!RNW7hGjFRD6+R{-?s9E_O^V72%&=$&yN2xEQX&oQL*hdpjZCorW~ZfY zBuAQ^IkG#WUw$R+w7fRAMj8V-Qn{uO#OFf#(F8rS@1z8?pwO|gJXbmfCgoDssC4#D z%B0VbN8Yg!*X`hkslgbK{!5N*gIYgde#s@u_ncS&7a?-{f`pgh zmAU~f6JL=3E$8X=LUxouaIEL0OW=tZ5*6n zg-9`S8`KicVi#-8DA{NjWowig9m31M>>455489V~ZxVR@N8&#NZ!O6H>m_ZvNB)iDaoMGgNNw4vjtjJcvAKa^G8iNtjtRo)9SoZ52>*_b|n9qIBK+n`i|rF_WIDhJ#RQs(GIF4(xB z{(O}0DX=Z069u6D830|8SZY5gmb?nsa()XX@DP((P!jw`>P6N(jLs$a{zmuX7T@>7 zl;Px9Czut@CsdLb)PW4Sv2keGO42t~R=|1_$!Ll2ozsYoR`LBWV zRI&+^j}Hd7tDSs^KSqkr61y^9;z9~5aC<>IJlJyzNtWj~ zuFw-r7&i;d5UlI>EdHfoGPB?NWh0ngr~;?{NkZ*!YQuJ;c(-9I-YrLtzNRc4FUyXO z$ED`t-^*0yS{e0hl+nB$GEs87?ATH%7klBW5+5@OIvRn`rGr(7iFOR`u%4N%lHCO} zvSIW!nUxJPkg*kIL0MjL4_wzm=@gMyciJwKAJR{FWjDHK{qR zg$eH}W+Lm73{V6H(tnxnLl~e-mW^6o*Q<(T&|0inm_gLfgv+&QN0D^T9+NepRs@Hc zk=miBB{=$`Ok~wcf5Gk2TYA3?XIy3v)69WjdMy*d+XQi5iGCLqqH{2JFQ~dr&Q96k zIxib-LsDVy10c>|t>OUKaTR%aCCPs3g&ECL&}#!K@Rn^K6YIu@#3w(6w~pMK7X4+ljH`H0O}oVCzl z{jo-HTd-J7R0f>*6|YT6E9R~`IMVJJ@~YDOo6DGeS>SWSIq&#eB=;|WsLKsAWomPX zGqu`jwtGy1Aiph{an!pPyBNU4iU{NuP&g||)?M!v`QdkxTxnw}qkE}jtxUn9v({{h zk@3XoH5@Bj5BgdZ?kJJHMeF5MV7(ll%$2F2OQu3;GGxt>5S(GVeKT^n-y>UHn`M*gl6Cz* z1NiO0q>gY$h+UU8b4fC$J0xQYa=D312-pgc3(bn#09(!qj}m<_B8RDgLV3SEY-mrQ zv%#(o(k;yE7MU^9Axm__gGz?9gQDw{O6dv}ix>Iyk!f+bCEeqeiu^3eLg*hWWLjQd zNKPJUkm{Kh4VHdHqoDFj7EB$oM$gHbOOMM~&KBvcd`t#%cFC-(5R@Z^5@X78tC6T^ zqc9mzPDu*dft7X8G?n5%yi*4k^nxa;45gvDo}k!**&W< z1h-ThuXLT%@$_7axE)(;Fu20ln^OhAygcXd6?~(0M7y)20@RI=Na#)=GW!ds`{h&j zuelMroNynP1wM!NNT1xw*}wx2OpZgFdPLbgxqJ_IzCy7ZXS=osgT)VxHFq11(mfJtcw7aK{-uPx z!?F)@z5+*{bWS*B!pN4x#z85_+AWoV3z9q6DOs~a@}RR-9&-LdX5DGh=`WQwe~Dc1 z=gW{v*Hn@N4xZOHzAi=CN;2nqq-OFjFw=*`?i+{K6dHz;reOlWYc>$f3G_acE})oU zKu&1|^#W!lKnL@+*1oKiVJM-Dp-2nL((h9l^7$-^%V4xv4HIbs8g zSj!Y6tUVVLW`+t6No)J-vR;~SJy0{~2R*f5E3Sm1Z@%bWS0hH3$-qtgnF8G0MMeq zj+C7RV`Br@aqRlMxzaoec5}rp+4H^+ioI-S{BH&FPXm;@>VGSmP~-zxJ`t=tUQ7Ys z@*}mN#Q5~EI?@XtyI4HLe<%xzFF4?Axu3%4TU*e~bv5%IRSNXC}j<@%7&dH=|O@^*JZRIzNA z7qmw^Hb;JeSlufm)j4TyzeoIU9fQ0s3E*4Mi{%d#?0&4JrDBw?U%qg3353nD?EJK0 z+4!&uU3yhq4L_1C{fA|{g%p?zl$8t0CLT~z9#{mxSQ|j)4{;1_n1lne4j{O})hrKS zs>W9yZkZD^6i0&~+No(t>WxVQ%_3}O&AcQjgr)6NFb!q~l``fmltDx-9}MN9xh(Aj zn)Y^1sB&wH4rUv473RRA#F3T;u!B)K-ZlNhbBj(kD_GWW1=rNOL#ln`K!jPX;W7kZ zOz@EvwiD(M8yf#kDm#86;~6#5S9-T}7r$4gokb`E$ic^Kq5a=7iOg6+Sn23-S=aK< zpz0tSor6pj>|JgtZwt|o9^+#Mu;rIRjamYn9ez=n=vNfZa=9Wjc-H(XcTbG;>Em`ZrA(Tiu%r882^Gp9h*$`x`#(0}DvZ|N7#?lSlT4!JD zIxQy#o5dY#QnJi25cJXkmb)uzy?5Bc1HwM<%P%jH~8hO~@lfYx)t<4i70GfE{Z7ZhDykrZTSiw8D# z4i^mX(G=!~@Ene7(8ixX}cb*vLx+78*#^H)&%@rn<|=3&Jg z8X<$a#fajK$5@e-3u_awjwb_Y(B`zts4q<}Ojbzebe3GgZzAA?FGNKC1EuQ609c_s zwq;A{|KHx1M#puY=RJ2;U7T4h+Y8gT+~%!Dp@ZjYu1R{!J4{-i;iAr^W6>g@=VTR_1`ItjeoBtx}k> zIB(-Y72|InMZtlOXg-@1c3W|i$#>pDVwyQ_SxZ0cmftxJXH7kSUOix$sfAgp80C2C zC<6}``)QUxu8v=LLkRVhslJsv>A5VII0l0&yw$Dv$$%Y)l-=-I$KX>2kQW~&p};6Z z>Vt5oOfOLRFytw9t3t;_?MH6NxkJxHGg%GX0V{JM%ob`^+)nnho2f<4Z6q2@f{re^ zjjU=IrLoJ%u?=HWMFvLw3_pppJP$+kXM))%^<~pcT#iVP(TmgM#N-&m_PjaY8$0L! zapp}%>|!0@AImf|`9U47AjWK^D2xgKEVJR<*8+esO(hgMK<1zKFBs zzr){XmK6E zJa)YImoOLZP?e&+$&aP`0C(07&z=5f92%k-o7d#>SL4!ij*{YRUsW5UrZe7?^T=I>Jh2og`M0H!qIiH+Gb$ z_B$k*Jt^?nxXN~v7s7vjfB=?s^Y=t=q3LSmSFgk0epbzH-TvN1@ZJVGKE%T_>cGpd zF*5VIu&YIDjlLT>m&qFE;G&PXf}nfld<5Sc%S4muf>!vq4+WHB27`67Gyt5TFEe6d z@lmF4jZKZ9j|?4&TnB=hb|-ZrOxV)A0rzgNz^~r!MDOWqXew}##Ur)bLt#`d`VS== z@r}QWtQeS-c=x+7XIGPSwJ5a%-q_O}|IOj9H`V`n@`tdAUsvaBqg=q2Fz0etF}3pr z?fkWA^h||x0iPUOtSy^J8Ky%?TyWGIKi*T9i~o0~Ul;I6FBvuyjxw2jh^E>y?<_sy zjlJJq-y}sct0z}+R@SJKr@D0kpJ<2inFOwU=R4T+SBV>nie9dRYx@iZZul|rxa-@?=@u8dYK_w7G%&ESrRm*7MvD|i(Qc;|*4wI1C zTRvNLATl$9z{C{7Atp;RC1jeVN5mgDNf{+vD*7%Cp|^Wj%S972WZXtWAVJGIuAru= zh|!e}oIiC9Q{*l+)9#;TSKwpVy{v_NwrMojt}^Rx6fSC#frK5gi3w7mh2SDvmfaFz z8cGZ{YKB%b`=lmmqt>Y{BD8^vN;Cs|lukuW0<*~u3+E)C1*in@B*j5|iYqk%JjRt` zQprP?sTyyagp|94l&QJM3D{6TOO(VPrGkBu5T8k3WbNiA^mJt4t-%5glmFQ>Nt$DU zojytjc}(+N4hHEsC@Th2dHZo>`aDhS6cE8P%9Y2qdLKUeU>!flFg!fXg@p-^wHB^4 zjYYpHg}W8SQJ@MNi|%VsQX7~{nK<$dm^S}`ik!tYBNrX$F8$-@7k{b#$JhTF!%=$1 zsU_=eVJb_M-Z)DxHZFM^@ zv6nzX0fDQJW<@U6_;9wevVxU`YCW@C^FkIaO-iT4LSgN5bxRaKez_f21|~^TLk>ya z_>$|#MJ!Bq4+@!BeT&hQU2o#K_Lsrs*s4H}9&wsRZFszLH_e>1iO;oAIIg}O5E>Xj%^y9hI%*nduTFN@ID=zG)N9}Sdt7_&1;nYPn7E?W z)o3PAc(PoL)b?n$SaV}8kGW|R64$!d+|{BE1X)-&&$8{&MPIM=k3t5qIw)qT5+wQ) z#j#|Nl0|qQ+1&IoKKMW*zW>r$3{TBaGa}3oh~#WvyfTFLPL&jqB*msFM~gHg@%AU` zY6&zf1H{!}gzPV){Uf*%=NaOl zMEeWT#L6-9&lo{95%eRQ6kQ38{!2zjoDmI+X3higpQ13{t5su|{Y84ANt<9NeGah% z(J9LgoKqSw#w2(L!M?88%M^(`*k~%(B1TtPnPC|0x9C)SeeKp)JeG zvg5J)YB2f28H~`(_3(~L6f=-Twm*E5G-4#8{zOYTNxrE*r`mWvl+p*F^t?)+JAJgP zxvoX?V??TY?r))XzeskNN>$0J<2AT}CSdZwIv8lPo^k7(KO=>Bj2oW;GtrP57MeEB zbG=%K9J<}3T^RBY;{xB0@YOMXjS;pJG&wV#VU>2p7#EQZE+6*S?prkUqx6jpOp|nD z6;s+w|F7G5V_Bm`2hj0{kWFtZ&sJY~cZk=aJ~7KxdT}Ixb62L+#){iNy7R`XZwW!V z>YI>JSj;HRZr#8qfi4O)zp=yb;`rI$N8a8os_#PwU@P#FKhvqLqU9+Pr{)o5(sy*+ zkI{p#P*XgH@DQ~E-XOX`Pv*cgYoaMCZ_n-}X0*DmY`YF1`tui7xASs)@rJQBP@{Ha zuj1BNu2Ue}swiH&qV@zRhZTCBeV7xENSs^B8|}$Q8u9Y$m(Vjfg&97;Wu+%YXC<9L zdma&}#N;UE(g>?GcvycLVkF!GBKa#PCaWbN+-a54$^E(;7jdbxA0ae0iQLmNO8B;tNx2uRyP%%L=*iW ziBJNAFTRa|e>nsTeMYt%vQ=n_vd^k1gsWx8 zTCV4XUBXmS%U3ZHy`+xPo1ng^r}zI*Sy|k?k--*eZUS~C4ioxjX6x*wB7_KS|79f} zJbhpjx=1+PPd}8r_l-_#j`>iOpeG9%o=+jLe&t{XN($Vw5BY2d&3mklz;p!%{bBym zQS^+N&}Dv{&}I+D)5q4vmPq+$e4Ivd}C`EHNNO0B^QJ1GVZ8 zpoxrf8C;b|0GH2F3$VA(Pnx$N9(A6BdWp1at`gO9@1Le}dfuCXsp?}$^u12dqy|j@ zTU`@DFJTE0lk<8ut^fDW_rgPI+B1KTulE?_c|>0^Db$xqh*>zQ_PUK@)VOFHq)tC>bI)lt{*Y2Aq~+@H0znDk(leZCO`HnwkUI&lnYY{ zbuu!it)^(E)C%%U!uu4 zXa;@i(I(VXdud*c!A*0ZldL~8lauHiVg8-^Fe-88ToBvmAY=-JF@QdyCAuyC%6Cd1r3GRn}LSa#)ye9oI0MVW~XQzMR}l_b^`P&0Fp z@ADwPw1|E;Ql9Zz677y_`xIupzMF__<`pOlwddZUDS~+vRW+3WwbS^?=cu99s-}%k zrG8Vns}*zELu&le^AuXT(`!;6#_A-ua{mGm`e0&pqe$0YvaA#~qkp&UDdad7vs9hG z=EvoMX=_r={khOLO|D-*TB_0y z%6iAMmhDqU1vfP(_ohm9;&>+)iYf25?AWw|nv&qO4lN-M?_v*p`#+NA-ub|9xfjZ7 zKh}a9Rwls1tyS*^>&!m|We9k-A?tflCztZ%Xy1?D2# zihO?J;RYN$as?+Z4r*1`rRJVcbWxFkpB$=_L29pa#}Q3SG#n?B*d?fDngDpYFM@96 zA^383qkQHF>W+Q`_Us&7DfkeHro{}J&zwN|8(HBXpJ@PMBGj}1uFflmU(w8?hpi9d zgt862YN6Jz&zq0D;sOSl%;sDP%TQeGrMFlUFbJs-@GYhQ3^EBc zTPH!j1XAtYn9rc8lrM+H$4>Isz7`+8`({s)t#16;%7@5cAdKVPlXnmB$;>u1S2CAXz*Jg}cux<_vHH?07EOf@X9*NC zH87f!PWAO_GAN@& zS^0+O*IL*#|KS`6xd?zczI?PF@4(Mq@1y@~6EcDYIFK`nhVCDs{@VA^m%S71nR^l2 zuob5}Mp^66hBD?6MhT+hCNKWc@(ixVX})GL*2LnMb>YVJW!lhK%n<5zYBj}KN_CDyy)YKk9c?O$ z-PhYk@N`?Lnqi+`=C0E~*Rfk&s$1TD_aU!s3q}r}fW?^xQ{OsFOiY|vjN~kN>XUTV zr}z-jF%BhfgJP;~QR7{m+-nWM$A`7TU=T|k16$Uy*(rj?Y%`8g>(k|ESYk|~35tKO zrjnuhRrzSC^=W}HCof6}x{*banGU@UZujzOR-`xQAskL%v?s;_ zwmI0?@HFb2L)dWoWwbe8#Po%7@&h)ar*t=p9^8opZ??{O1txPWsNYb;NX=~45v0#p zw7csfDwi1c2mY1JU&ea$Y(MIlu>Mf<`*c>?;G8~1aY`V=>;faz0V`z>D$3|-RlQ6L z#DYS;sqSxVw|WW4f-phT{D0W`+o&(RF(-0xGK@3*Q?Ti@YK7@XuPMvM2BsdYR}<6g zy$$&|`Rgu?3Qf;(g!ScQ?<59DV^&eHij*2X2V2K&bpfBro~4w3;Td)6>_x-^WLwIVSnX{$GDY$ z)cqLrY}=!h{pJ%;saf4p_ZT0@F@FGMpLv45y(gBu7}IqkEG_qwTazKZYcQ`#bfjhT zJ-pJFh^$N3K&c|YmH@210XCJ<|hV*4l_~{pX>2N1HI)|C_M>8%T z_yUq)e*Xq@*90!DTmjPz1b;9LabZMg<{kDFpg+G9K_-@8nR4Q9F1O*Emp+2$dUvqo z(i>R9q`)1~9)W)_txHDk{*=o0>#|G8huCJ z!XVv)eZ$X{xoJ|l< z_c4tAG~$IYEfgOv-Gpy_=qt#)&aXEwqN{^J_43&JxvBHtCwmu7GB?YH*4mt8o38nH zUtWgNTA8h$qB)kiLAsh;!5zGw&vs6#&DH76Kh`ynHEgVN%Cko@*&Ry#*S=1N&sQ<@ z^4l!?MiWc=Z|9V!6$^%#y3mHY|MX`tr8yCNxj|UBJ%s3+uQNbp=@s8{`)S|P4`yy^ zq^Yywrb=y-$Ba=%7D}OwbRJmDnm(F1Kl^wKPM;gV1qN`O=^Ca9G=frs-c{xSMyVaj zN^!X+HSDCtiHehChndK5!^wQNP{j3nIOyAFE4LRG{!$EOCUz; zPLyd2pRe18Ki>NVG7BwVQR86yFvbInaMroPB<^7&wXiIQ&K*;p#o`TjGOgjCkM(Qr z2eHni+9c&@l2P1mb&i6-m+Ee})OM=^J^_akc?O3S4EW*|PNnBzS+uX0x^T*P;xFwuA+FeMS!dq0a`)4}pgmoqjqO}+@_mR^{dJYLrIJc|2X z#Yo;3T;1?d^m!kk2FRcU9?Q(Y2OEQO&R-s7E@KeSd~`8m|9hRM^8-s4nRomd66gOx zO?1CR(;UTQvBp#E_Cr|?YcClrfi`JgtT**nJMaLL7U>Mfeh zVcy?J9@v}ITB~WrAdAa@pOk7k0yO0wmEfMYyC(3NU`%z~B%n^GSXK>uG6+jnwzBar z{tGK0{15fo|NSZ1SHi4xzWhaz&Vk2gCae(y^(x#}mtUdwn)Ir)mEX`32- z^AMBSC8!|9CXta0S5|7bq_{(RH>-7S17u z0*|K{XD$w)izYvdo|WaC78oW8K_t_oX@QOyt4qvGVSFYN7Xn_qbhR4wc>(58b)(vU z5!F*aK+Tos5VRFw#J3$o`MWUYZqn-i1zE_IB?OspEWjkeHv);NHu7&4l;A>d8#V;K zPye0`F-B4<u9{j<>B=B~nTiVNv+m;Pe z%fD4j`J2_mrGFwR^#uYT8D7jxnVF+*TV_w=>je^s@!AW}m*?fe>!I>{@Q3$2japw_ zQnjdOFrc36og&e@zVHdT5Nr76a1=xmb0bgtKruAu-n zR@{DC-|cnkO&BQK zkALW>!NV<^aR0`<6t9l?qov`!c&}nA*bb%l*J`5g5Y%CsKVvgQectjKC+GZ-=HJtB z%-ggJ30RR!Ox}gRGs?wGA)jj>uiJ-D)jx>c6+2TF(m7I;^^AvLlZY}MO}J@yaj~d3 z*wB$b{PDav{l9J6K~)i76%$^1kf z*IZbGiv!Kr9)E-6*bA*292u|m7>m(nO?04s;yk_-^C3UF8|v8SSOKA$@jN2!o7iaT zRW>}Lm`fgjI@PJFgYU2?@DU`Y`?xw`6$E*)@G#4EaI$M&1E)5zIL)tfn*8-U2;c;{ zsGVh(z5ds9{>^0$#~?4M#$cmG!Ag_3iyXl%?jqb*u><#2?nF(_268N>4q(D7`-`(f zS{eh{0y$u96_s@0vX!5!(4CE}AYxnPgEHw+mfoPX+5;zP04M3E*M_|GW=no6=jmrB z2l3?YQZ;jlDkDOCA7MndC7$|qFOlMLzLsnvs5CvS(t5R9bA3wD$3KmN10N#*zKo$) z-#~!TpP~Li#8{d|R+}aQgs}2!s)jsV<`X;x;P{e@MJlJO!p0#4&a^>imKMNSR}Jq2 z_rUk)Z;+mFF-yXdLb?fGnu==_>*h8!*4a+YHwE?;`U~jzfu&{FO&HzEhY%jm#)zu6 zPe{;7+ODUi56aW3omo*Y({$lVH&Vk-d=1vDEONZ&VUX9%vED(b6Jcc1_nOB%!Bb3= zu*SE+6&^yhr3bajMHD%v;kBNJcl-#@{R0A62152c_&xRTyID%eQGsbksbN zVc0j#no&Lj%|*qy*trKS6Gs`(D|+pXH+6!5BfpfeI(@w3r-*d_66Ug9s=4_oC`GL# zBTeC2Sz3~-`<8w_C8v?~BpZSH--0PLqN?N6zWrB8dBzeoVXpYYjPBFU(&`S8@?KG< zTr87pUqaB??yX@pkQ5e?DIf604aH|GC5T)MpenOvqBgr2jlNpccx#c9>EQxpbr1itHruAs1j zsXHnu4Rv6-_(-$!*FQ0yi&$;=*9|&-f6iRJs7mU?%#{Jm^mJ*j@YsYFl#-ALLx#nQ z`O?htHdgX83MkrH!8*h1gQL0unUy7Q)mKx~YfRr$Gkw#O2L>~`X+lbAHBVWKsp&d0 z+jI^`PhTX7z}q7+^%_eT>2yixIgDoNJWGDh=YH0%o5Cs81F_T?f)Q%4g5vxvW=K2z zf%cgoGU(%SMng~-2qiF8=82MZhQO3D0$-vZ#pr{NHU7k3r)eVss4Vmv%J9-m>P5(w zOP?Xhx2@Tj$?#!jxEJ-qKVwN=0$VESEOL* znsevEEL|&;MV&AFgR)@mp>`iE{FmuBrSG<%3{45KA>Jby1fx_RLJP+}AgZ+&>ZK`PAu8VSf&$ zbl5W)D6o!g-GOiM*kepGpHk!D2*HkuGBvvdO7#20c{X%@_!lUM%iezvrR2t% zbgA`cY-LEmkic3bkXBP?@_|@rlFC&quH;)9TihH8h!6grJQLm==4zGYi*8)ErC}UI zK06s+1f0z4q)}WCdNOL!`@|e7Ey^I2D5K^=^y8@X363$!XJ11#;?yt#Q_~n@A>_fC z8XRZEj0F8&+14QPF^YVJufzb{i3wyW0c5Jw9#wKMf{V9Q=0cy9_|cTSYM6`ffvIXA zwZ7fDd`H>@jDHLX7!pXE1a30$rET0sM`@IRo7LLeybN|3ierM=?db+T3$>i4IxmiO z45V??`nnPjl>ep0XlW>9!hJz$p_bktR)z?x!biyd6J^wGghi19{%Q0D%5a(AhY8qL z3kw^AnxZm^&qV(>r1JZcz$bwl;>#5qkZ5;hbEeJG9YA*Zx|(lhXJ`CtNWhRlG6@*K zmrO!;$?r@vQ`&qMMta85uK9`czN|PK)vWH`L1uTog*nrC3WR~f!}3ZW+FeE9V%o)A z1et|FS5~cRJ0X(e6%y=(nBxgzVfqOp!5NJEqbM2s1+v1EG;&_&%onhegmD(tRkBN9 z-msg|yB~&<%iJ&P`Z4XNQ#M9lh6L^w2^he4x18w|=ILVW#cpbTZ!yhbjAqYtxtGQ1 z?{;ONzA|5zz4cM1}+m2_%z% z0es0MbQk|FT3(aKthj9^_2gI_(-QG1Zm%`SL@Q53&1?SywX8C2!=ckx5hp4MpXYiu z0o?}r7=<)DPId@AO&D56kcU&2PouhRJMQ0HM6MU384@rgaJx#tFm>LpXYMACo1mwj zW;vs4EMzONvDTCaNn{rQeYay6zkcTmu8pvA0|8OYp=$xwrNkm`I?|KkcRt>Vq5?NH zzW0MzmfC*dcQRM9biy<}iCTLYTWX5aJ-mg7Gd>#(atHx|%l?FV zZc?;AM((dwNh5^VtQL%q1#tM}HC*f(!PsNmb!8@mWaqjAvHoCQ%K;w+$6tI|ROp^c@R+d4IO+iJLf*O}uk@|&3GbCV0 z;LehO0epAX`TRg;(-TOj9a9Vd3D2U+S~Wn?uPg++{{AVvc&Gzi15+A%y`IU5IkU1T z8{0P)qoKx2zoh7-H=>^Q4gV1>k5*7rI!&l@nc&n@DqhdPjBO1G7!vrvC13#G2Yw3f zi~&gA-xx_PJEr0oV&XdkKsBgY3kcfDpglYs!1rHz7ya}DO7Kf6O^R98kRt7q`!^z+ z<*q{1Ag|Z-M7xuhxDuUID63pdP^T|1%K*GoL~LwhNZ_`XfB}5B_367c2T!^)wTu40 zVQPSrq&^dX5zJbRA25?u+fTjQj~~3+t~nEzs=}~P3IcFq82#Min^9Kkp-*pd1gB_r zG9CvLdGhGPD{+_zcqYZVn!znRu<_ZDfFXg~Mgm42-)(cMZl8hXGIt<1&x{})X4L*v zp*|Z5B@kpJsF*ROX>a@|8Qz26xJ{aCJ`-6KuKUokZAsWehQLwE&(qu{;C5fFAcHSJ&P5K4V6v$7CN#BJ99hi zxNl1twzibODuFWmUMjQa*nk27yG#WcR2hwc6-{);KZXSES_v4ych{c!4|d{HOo$gV zs1(0tdIY2rJTVaws%Qd+^7nibh%*z&68zyHlid%V=s}P`C@?7i=OBS}UX~r7|5!7L zu(MetHjXTQ@1gxNKZEh2vluzwo$+o+z>vUQE&&7h?(z%ZR++wNe={uHCuw%Gz&Fbf zBif)O%ZqL&nxB|5`})Q)9SFg0v%p4x%cS|!%OIADLZ@OE)zN5%1Plon5?Db32Jo#Q z9OEZL0)_+(2^bQ%^CV!bkMF#5YRt%xfFS`x0)_-ukbnVvD+tH<$&i2{0Yd_Y1nxWu s7{GVuol|2*h6D@=7!oifu!02sKY8z97Hk@I*8l(j07*qoM6N<$f_Q(<^8f$< diff --git a/docs/source/variable.rst b/docs/source/variable.rst deleted file mode 100644 index 8438c35d..00000000 --- a/docs/source/variable.rst +++ /dev/null @@ -1,6 +0,0 @@ -variable -======== - -.. automodule:: cdms2.variable - :members: - From 0e3678fdc868ea52e44284460addbaebeb1798eb Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 11 Oct 2017 15:02:05 -0700 Subject: [PATCH 015/239] add chapter 3 --- docs/source/conf.py | 2 +- docs/source/index.rst | 2 ++ docs/source/manual/cdms_2.rst | 7 ++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8cf53b44..4b1b3e01 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -65,8 +65,8 @@ napoleon_use_admonition_for_notes = True napoleon_use_admonition_for_references = True napoleon_use_ivar = False -napoleon_use_param = True napoleon_use_rtype = False +napolean_use_param = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/index.rst b/docs/source/index.rst index 172630a7..951d2959 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -10,6 +10,8 @@ Contents: .. toctree:: manual/cdms_1 + manual/cdms_2 + manual/cdms_3 # AbstractAxis # AbstractVariable # avariable diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index c66978eb..bfacaeb4 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -72,7 +72,9 @@ latitude, longitude). >>> julyavg.long_name = "mean July surface temperature" >>> out = cdms2.open('janjuly.nc','w') >>> out.write(janavg) + >> out.write(julyavg) + >> out.comment = "Average January/July from Jones dataset" >>> jones.close() >>> out.close() @@ -904,8 +906,8 @@ Table 2.14 CdmsFile Methods +--------------------------+--------------------------+--------------------------+ | ``Variable`` | ``createVariable(String | Create a new Variable. | | | id, String datatype,List | This is a persistent | -| | axes, fill_value=None)` | object which can be used | -| | ` | to read or write | +| | axes, fill_value=None)`` | object which can be used | +| | | to read or write | | | | variable data to the | | | | file. ``id`` is a String | | | | name which is unique | @@ -1776,7 +1778,6 @@ Table 2.25 Dataset Methods | | | ``t = f.axes['time']`` | +--------------------------+--------------------------+--------------------------+ | ``None`` | ``close()`` | Close the dataset. | - +--------------------------+--------------------------+--------------------------+ | ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | | | , lon, order, type="gene | dataset. This is not a | From 74d1981bb5ed16dec94a04d84c7b36994e6f857b Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 11 Oct 2017 16:28:32 -0700 Subject: [PATCH 016/239] finish chapter 3 started chapter 4 --- docs/source/index.rst | 1 + docs/source/manual/cdms_3.rst | 218 +++++ docs/source/manual/cdms_4.rst | 870 ++++++++++++++++++ .../source/manual/images/curvilinear_grid.jpg | Bin 0 -> 105315 bytes docs/source/manual/images/generic_grid.jpg | Bin 0 -> 86702 bytes docs/source/manual/images/uvcdat.png | Bin 0 -> 37672 bytes 6 files changed, 1089 insertions(+) create mode 100644 docs/source/manual/cdms_3.rst create mode 100644 docs/source/manual/cdms_4.rst create mode 100644 docs/source/manual/images/curvilinear_grid.jpg create mode 100755 docs/source/manual/images/generic_grid.jpg create mode 100644 docs/source/manual/images/uvcdat.png diff --git a/docs/source/index.rst b/docs/source/index.rst index 951d2959..8ab57f9f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,6 +12,7 @@ Contents: manual/cdms_1 manual/cdms_2 manual/cdms_3 + manual/cdms_4 # AbstractAxis # AbstractVariable # avariable diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst new file mode 100644 index 00000000..dae840c8 --- /dev/null +++ b/docs/source/manual/cdms_3.rst @@ -0,0 +1,218 @@ +CHAPTER 3 cdtime Module +----------------------- + +3.1 Time types +^^^^^^^^^^^^^^ + +The ``cdtime`` module implements the CDMS time types, methods, and +calendars. These are made available with the command + +.. doctest:: + + >>> import cdtime + +Two time types are available: relative time and component time. Relative +time is time relative to a fixed base time. It consists of: + +- a units string, of the form ‘units since basetime’, and +- a floating-point value + +For example, the time “28.0 days since 1996-1-1” has value=28.0, and +units=’days since 1996-1-1’ + +Component time consists of the integer fields year, month, day, hour, +minute, and the floating-point field second. A sample component time is +``1996-2-28 12:10:30.0`` + +The ``cdtime`` module contains functions for converting between these +forms, based on the common calendars used in climate simulation. Basic +arithmetic and comparison operators are also available. + +3.2 Calendars +^^^^^^^^^^^^^ + +A calendar specifies the number of days in each month, for a given year. +cdtime supports these calendars: + +- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap + years, except century years not evenly divisible by 400. This is + sometimes called the proleptic Gregorian calendar, meaning that the + algorithm for leap years applies for all years. +- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates + before 158210-15 are encoded with the Julian calendar, otherwise are + encoded with the Gregorian calendar. The day immediately following + 1582-10-4 is 1582-10-15. This is the default calendar. +- ``cdtime.JulianCalendar``: years evenly divisible by four are leap + years, +- ``cdtime.NoLeapCalendar``: all years have 365 days, +- ``cdtime.Calendar360``: all months have 30 days. + +Several ``cdtime`` functions have an optional calendar argument. The +default calendar is the ``MixedCalendar``. The default calendar may be +changed with the command: + + +``cdtime.DefaultCalendar = newCalendar`` + +3.3 Time Constructors +^^^^^^^^^^^^^^^^^^^^^ + +The following table describes the methods for creating time types. + + +.. csv-table:: Time Constructors + :header: "Type", "Constructor", "Defintion" + :widths: 10, 40, 80 + + "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." + ,, "``value`` is an integer or floating point value." + ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" + ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + + "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." + ,,"``year`` is an integer." + ,,"``month`` is an integer in the range 1 .. 12" + ,,"``day`` is an integer in the range 1 .. 31" + ,,"``hour`` is an integer in the range 0 .. 23" + ,,"``minute`` is an integer in the range 0 .. 59" + ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + + +3.4 Relative Time +^^^^^^^^^^^^^^^^^ + +A relative time type has two members, value and units. Both can be set. + +Table 3.2 Relative Time Members +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++----------+---------+-------------------------------------------------------+ +| Type | Name | Summary | ++==========+=========+=======================================================+ +| Float | value | Number of units | ++----------+---------+-------------------------------------------------------+ +| String | units | Relative units, of the form “unit(s) since basetime | ++----------+---------+-------------------------------------------------------+ + +3.5 Component Time +^^^^^^^^^^^^^^^^^^ + +A component time type has six members, all of which are settable. + +.. csv-table:: Table 3.3 Component Time + :header: "Type", "Name", "Summary" + :widths: 15, 15, 50 + + "Integer", "year", "Year value" + "Integer", "month", "Month, in the range 1..12" + "Integer", "day", "Day of month, in the range 1 .. 31" + "Integer", "hour", "Hour, in the range 0 .. 23" + "Integer", "minute", "Minute, in the range 0 .. 59" + "Float", "second", "Seconds, in the range 0.0 .. 60.0" + +3.6 Time Methods +^^^^^^^^^^^^^^^^ + +The following methods apply both to relative and component times. + +.. csv-table:: Table 3.4 Time Methods + :header: "Type", "Method", "Definition" + :widths: 20, 75, 80 + + "Comptime or Reltime", "``t.add(value, intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" + ,, "``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." + ,, "``t2`` is the time to compare." + ,, "``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" + ,, "``calendar`` is the calendar type. " + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." + ,, "``calendar`` is the calendar type." + "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." + + +3.7 Examples +^^^^^^^^^^^^ +.. doctest:: + + >>> from cdtime import * + >>> c = comptime(1996,2,28) + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.add(1,Day) + 29.000000 days since 1996-1-1 + >>> print c.add(36,Hours) + 1996-2-29 12:0:0.0 + + +**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising. + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(1,Month) + 1979-9-1 0:0:0.0 + + +In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months: + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(2,Years) + 1981-8-1 0:0:0.0 + +Compare time values. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print c.cmp(r) + 1 +# >>> print r.cmp(c) +# -1 +# >>> print r.cmp(r) +# 1 + +Subtract an interval of time. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print r.sub(10,Days) + 18.000000 days since 1996-1-1 + >>> print c.sub(30,Days) + 1996-1-29 0:0:0.0 + + +For intervals of years or months, see the **note** under add() in the example above. + +Convert to component time. + +.. doctest:: + + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> r.tocomp() + 1996-1-29 0:0:0.0 + + +Convert to relative time. + +.. doctest:: + + >>> c = comptime(1996,2,28) + >>> print c.torel("days since 1996-1-1") + 58.000000 days since 1996-1-1 + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.torel("days since 1995") + 393.000000 days since 1995 + >>> print r.torel("days since 1995").value + 393.0 + diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst new file mode 100644 index 00000000..a5d22d7c --- /dev/null +++ b/docs/source/manual/cdms_4.rst @@ -0,0 +1,870 @@ +CHAPTER 4 Regridding Data +^^^^^^^^^^^^^^^^^^^^^^^^^ + +4.1 Overview +^^^^^^^^^^^^ + +CDMS provides several methods for interpolating gridded data: + +- from one rectangular, lat-lon grid to another (CDMS regridder) +- between any two lat-lon grids (SCRIP regridder) +- from one set of pressure levels to another +- from one vertical (lat/level) cross-section to another vertical + cross-section. + +4.1.1 CDMS horizontal regridr +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The simplest method to regrid a variable from one rectangular, lat/lon +grid to another is to use the regrid function defined for variables. +This function takes the target grid as an argument, and returns the +variable regridded to the target grid: + +.. doctest:: + + >>> import cdms2 + >>> f = cdms2.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') + >>> rlsf = f('rls') # Read the data + >>> rlsf.shape + (4, 48, 96) + >>> g = cdms2.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') + >>> rlsg = g['rls'] # Get the file variable (no data read) + >>> outgrid = rlsg.getGrid() # Get the target grid + >>> rlsnew = rlsf.regrid(outgrid) + >>> rlsnew.shape + (4, 46, 72) + >>> outgrid.shape + (46, 72) + + +A somewhat more efficient method is to create a regridder function. This +has the advantage that the mapping is created only once and can be used +for multiple arrays. Also, this method can be used with data in the form +of an MA.MaskedArray or Numeric array. The steps in this process are: + +#. Given an input grid and output grid, generate a regridder function. +#. Call the regridder function on a Numeric array, resulting in an array + defined on the output grid. The regridder function can be called with + any array or variable defined on the input grid. + +The following example illustrates this process. The regridder function +is generated at line 9, and the regridding is performed at line 10: + + +.. doctest:: + + >>> #!/usr/bin/env python + >>> import cdms + >>> from regrid import Regridder + >>> f = cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') + >>> rlsf = f['rls'] + >>> ingrid = rlsf.getGrid() + >>> g = cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') + >>> outgrid = g['rls'].getGrid() + >>> regridfunc = Regridder(ingrid, outgrid) + + >>> rlsnew = regridfunc(rlsf) + >>> f.close() + >>> g.close() + + +Notes +----- + +**Line #2** Makes the CDMS module available. + +**Line #3** Makes the Regridder class available from the regrid module. + +**Line #4** Opens the input dataset. + +**Line #5** Gets the variable object named ‘rls’. No data is read. + +**Line #6** Gets the input grid. + +**Line #7** Opens a dataset to retrieve the output grid. + +**Line #8** The output grid is the grid associated with the variable named ‘rls’ in dataset g. Just the grid is retrieved, not the data. + +**Line #9** Generates a regridder function regridfunc. + +**Line #10** Reads all data for variable rlsf, and calls the regridder +function on that data, resulting in a transient variable rlsnew. + +4.1.2 SCRIP horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To interpolate between grids where one or both grids is non-rectangular, +CDMS provides an interface to the SCRIP regridder package developed at +Los Alamos National Laboratory (http://oceans11.lanl.gov/trac/SCRIP). + +Figure 3 illustrates the process: + +#. Obtain or generate the source and target grids in SCRIP netCDF + format. A CDMS grid can be written to a netCDF file, in SCRIP format, + using the write-ScripGrid method. +#. Edit the input namelist file scrip\_in to reference the grids and + select the method of interpolation, either conservative, bilinear, + bicubic, or distance-weighted. See the SCRIP documentation for + detailed instructions. +#. Run the scrip executable to generate a remapping file containing the + transformation coefficients. +#. CDMS, open the remapping file and create a regridder function with + the readRegridder method. +#. Call the regridder function on the input variable, defined on the + source grid. The return value is the variable interpolated to the new + grid. Note that the variable may have more than two dimensions. Also + note that the input arguments to the regridder function depend on the + type of regridder. For example, the bicubic interpolation has + additional arguments for the gradients of the variable. + + +FIGURE 3. Regridding data with SCRIP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Example:** + +Regrid data from a T42 to POP4/3 grid, using the first-order, +conservative interpolator. + +In this example: + +- The input grid is defined in remap\_grid\_T42.nc. +- The output grid is defined in remap\_grid\_POP43.nc. +- The input data is variable src\_array in file sampleT42Grid.nc. +- The file scrip\_in has contents: + +.. raw:: html + +
+ +:: + + &remap_inputs + num_maps = 1 + + grid1_file = 'remap_grid_T42.nc' + grid2_file = 'remap_grid_POP43.nc' + interp_file1 = 'rmp_T42_to_POP43_conserv.nc' + interp_file2 = 'rmp_POP43_to_T42_conserv.nc' + map1_name = 'T42 to POP43 Conservative Mapping' + map2_name = 'POP43 to T42 Conservative Mapping' + map_method = 'conservative' + normalize_opt = 'frac' + output_opt = 'scrip' + restrict_type = 'latitude' + num_srch_bins = 90 + luse_grid1_area = .false. + luse_grid2_area = .false. + / + +.. raw:: html + +
+ +``num_maps`` specifies the number of mappings generated, either 1 or 2. +For a single mapping, ``grid1_file`` and ``grid2_file`` are the source +and target grid definitions, respectively. The ``map_method`` specifies +the type of interpolation, either ‘conservative’, ‘bilinear’, ‘bicubic’, +or ‘distwgt’ (distanceweighted). The remaining parameters are described +in the SCRIP documentation. + +Once the grids and input file are defined, run the scrip executable to +generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ + +.. raw:: html + +
+ +:: + + % scrip + Using latitude bins to restrict search. + Computing remappings between: + T42 Gaussian Grid + and + POP 4/3 Displaced-Pole T grid + grid1 sweep + grid2 sweep + Total number of links = 63112 + +.. raw:: html + +
+ +Next, run UV-CDAT and create the regridder: + +.. raw:: html + +
+ +:: + + # Import regrid package for regridder functions + import regrid, cdms + # Read the regridder from the remapper file + remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') + regridf = regrid.readRegridder(remapf) + remapf.close() + +.. raw:: html + +
+ +Then read the input data and regrid: + +.. raw:: html + +
+ +:: + + # Get the source variable + f = cdms.open('sampleT42Grid.nc') + t42dat = f('src_array') + f.close() + # Regrid the source variable + popdat = regridf(dat) + +.. raw:: html + +
+ +Note that ``t42dat`` can have rank greater than 2. The trailing +dimensions must match the input grid shape. For example, if ``t42dat`` +has shape (12, 64, 128), then the input grid must have shape (64,128). +Similarly if the variable had a generic grid with shape (8092,), the +last dimension of the variable would have length 8092. + +.. rubric:: 4.1.3 Pressure-level regridder + :name: pressure-level-regridder + +To regrid a variable which is a function of latitude, longitude, +pressure level, and (optionally) time to a new set of pressure levels, +use the ``pressureRegrid`` function defined for variables. This function +takes an axis representing the target set of pressure levels, and +returns a new variable ``d`` regridded to that dimension. + +.. raw:: html + +
+ +:: + + >>> var.shape + (3, 16, 32) + >>> var.getAxisIds() + ['level', 'latitude', 'longitude'] + >>> len(levout) + 2 + >>> result = var.pressureRegrid(levout) + >>> result.shape + (2, 16, 32) + +.. raw:: html + +
+ +4.1.4 Cross-section regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To regrid a variable which is a function of latitude, height, and +(optionally) time to a new latitude/height cross-section, use the +``crossSectionRegridder`` defined for variables. This function takes as +arguments the new latitudes and heights, and returns the variable +regridded to those axes. + +.. raw:: html + +
+ +:: + + >>> varin.shape + (11, 46) + >>> varin.getAxisIds() + [’level’, ’latitude’] + >>> levOut[:] + [ 10., 30., 50., 70., 100., 200., 300., 400., 500., + 700., 850., 1000.,] + >>> varout = varin.crossSectionRegrid(levOut, latOut) + >>> varout.shape + (12, 64) + +.. raw:: html + +
+ +4.2 regrid module +^^^^^^^^^^^^^^^^^ + +The ``regrid`` module implements the CDMS regridding functionality as +well as the SCRIP interface. Although this module is not strictly a part +of CDMS, it is designed to work with CDMS objects. + +4.2.1 CDMS horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Python command + +.. raw:: html + +
+ +:: + + from regrid import Regridder + +.. raw:: html + +
+ +makes the CDMS Regridder class available within a Python program. An +instance of Regridder is a function which regrids data from rectangular +input to output grids. + +Table 4.1 CDMS Regridder Constructor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++-----------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=====================================================+============================================================================================================================================================================================================================================================================================================================================+ +| regridFunction = Regridder(inputGrid, outputGrid) | Create a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function. | ++-----------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +.. rubric:: 4.2.2 SCRIP Regridder + :name: scrip-regridder + +SCRIP regridder functions are created with the ``regrid.readRegridder`` +function: + +Table 4.2 SCRIP Regridder Constructor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++--------------------------------------+--------------------------------------+ +| Constructor | Description | ++======================================+======================================+ +| :: | Read a regridder from an open CDMS | +| | file object. | +| regridFunction = regrid.readRegr | | +| idder(fileobj, mapMethod=None, check | ``fileobj`` is a CDMS file object, | +| Grid=1) | as returned from ``cdms.open``. | +| | | +| | ``mapMethod`` is one of | +| | | +| | - ``'conservative'``: conservative | +| | remapper, suitable where | +| | area-integrated fields such as | +| | water or heat fluxes must be | +| | conserved. | +| | - ``'bilinear'``: bilinear | +| | interpolation | +| | - ``'bicubic'``: bicubic | +| | interpolation | +| | - ``'distwgt'``: distance-weighted | +| | interpolation. | +| | | +| | It is only necessary to specify the | +| | map method if it is not defined in | +| | the file. | +| | | +| | If ``checkGrid``\ is 1 (default), | +| | the grid cells are checked for | +| | convexity, and 'repaired' if | +| | necessary. Grid cells may appear to | +| | be nonconvex if they cross a | +| | ``0 / 2pi`` boundary. The repair | +| | consists of shifting the cell | +| | vertices to the same side modulo 360 | +| | degrees. | ++--------------------------------------+--------------------------------------+ + +4.3 Regridder Functions +^^^^^^^^^^^^^^^^^^^^^^^ + +It is only necessary to specify the map method if it is not defined in +the file. + +If ``checkGrid`` is 1 (default), the grid cells are checked for +convexity, and ‘repaired’ if necessary. Grid cells may appear to be +nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of +shifting the cell vertices to the same side modulo 360 degrees. + +4.3.1 CDMS regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A CDMS regridder function is an instance of the CDMS ``Regridder`` +class. The function is associated with rectangular input and output +grids. Typically its use is straightforward: the function is passed an +input array and returns the regridded array. However, when the array has +missing data, or the input and/or output grids are masked, the logic +becomes more complicated. + +.. rubric:: Step 1: + :name: step-1 + +The regridder function first forms an input mask. This mask is either +two-dimensional or n-dimensional, depending on the rank of the +user-supplied mask. If no mask or missing value is specified, the mask +is obtained from the data array mask if present. + +**Two-dimensional case:** + +- Let mask\_1 be the two-dimensional user mask supplied via the mask + argument, or the mask of the input grid if no user mask is specified. +- If a missing-data value is specified via the missing argument, let + the implicit\_mask be the two-dimensional mask defined as 0 where the + first horizontal slice of the input array is missing, 1 elsewhere. +- The input mask is the logical AND(mask\_1, implicit\_mask) + +**N-dimensional case:** + +- If the user mask is 3 or 4-dimensional with the same shape as the + input array, it is used as the input mask. + +.. rubric:: Step 2: + :name: step-2 + +The data is then regridded. In the two-dimensional case, the input mask +is ‘broadcast’ across the other dimensions of the array. In other words, +it assumes that all horizontal slices of the array have the same mask. +The result is a new array, defined on the output grid. Optionally, the +regridder function can also return an array having the same shape as the +output array, defining the fractional area of the output array which +overlaps a non-missing input grid cell. This is useful for calculating +area-weighted means of masked data. + +.. rubric:: Step 3: + :name: step-3 + +Finally, if the output grid has a mask, it is applied to the result +array. Where the output mask is 0, data values are set to the missing +data value, or 1.0e20 if undefined. The result array or transient +variable will have a mask value of 1 (invalid value) for those output +grid cells which completely overlap input grid cells with missing values + +Table 4.3 CDMS Regridder function +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++--------------------------+--------------------------+--------------------------+ +| Type | Function | Description | ++==========================+==========================+==========================+ +| Array or | ``regridFunction(array, | Interpolate a gridded | +| Transient-Variable | missing=None, order=None | data array to a new | +| | ,mask=None)`` | grid. The interpolation | +| | | preserves the | +| | | area-weighted mean on | +| | | each horizontal slice. | +| | | If array is a Variable, | +| | | a TransientVariable of | +| | | the same rank as the | +| | | input array is returned, | +| | | otherwise a masked array | +| | | is returned. | +| | | | +| | | ``array``\ is a | +| | | Variable, masked array, | +| | | or Numeric array of rank | +| | | 2, 3, or 4. | +| | | | +| | | For example, the string | +| | | “tzyx” indicates that | +| | | the dimension order of | +| | | ``array`` is (time, | +| | | level, latitude, | +| | | longitude). If | +| | | unspecified, the | +| | | function assumes that | +| | | the last two dimensions | +| | | of ``array`` match the | +| | | input grid. | +| | | | +| | | ``missing`` is a Float | +| | | specifying the missing | +| | | data value. The default | +| | | is 1.0e20. | +| | | | +| | | ``order`` is a string | +| | | indicating the order of | +| | | dimensions of the array. | +| | | It has the form returned | +| | | from | +| | | ``variable.getOrder().`` | +| | | | +| | | ``mask`` is a Numeric | +| | | array, of datatype | +| | | Integer or Float, | +| | | consisting of a | +| | | fractional number | +| | | between 0 and 1. A value | +| | | of 1 or 1.0 indicates | +| | | that the corresponding | +| | | data value is to be | +| | | ignored for purposes of | +| | | regridding. A value of 0 | +| | | or 0.0 indicates that | +| | | the corresponding data | +| | | value is valid. This is | +| | | consistent with the | +| | | convention for masks | +| | | used by the MA module. A | +| | | fractional value between | +| | | 0.0 and 1.0 indicates | +| | | the fraction of the data | +| | | value (e.g., the | +| | | corresponding cell) to | +| | | be ignored when | +| | | regridding. This is | +| | | useful if a variable is | +| | | regridded first to grid | +| | | A and then to another | +| | | grid B; the mask when | +| | | regridding from A to B | +| | | would be (1.0 - f) where | +| | | f is the maskArray | +| | | returned from the | +| | | initial grid operation | +| | | using the | +| | | ``returnTuple`` | +| | | argument. | +| | | | +| | | If ``mask`` is | +| | | two-dimensional of the | +| | | same shape as the input | +| | | grid, it overrides the | +| | | mask of the input grid. | +| | | If the mask has more | +| | | than two dimensions, it | +| | | must have the same shape | +| | | as ``array``. In this | +| | | case, the ``missing`` | +| | | data value is also | +| | | ignored. Such an | +| | | ndimensional mask is | +| | | useful if the pattern of | +| | | missing data varies with | +| | | level (e.g., ocean data) | +| | | or time. Note: If | +| | | neither ``missing`` or | +| | | ``mask`` is set, the | +| | | default mask is obtained | +| | | from the mask of the | +| | | array if any. | ++--------------------------+--------------------------+--------------------------+ +| Array, Array | ``regridFunction(ar, mis | If called with the | +| | sing=None, order=None, m | optional ``returnTuple`` | +| | ask=None, returnTuple=1) | argument equal to 1, the | +| | `` | function returns a tuple | +| | | (``dataArray``, | +| | | ``maskArray``). | +| | | | +| | | ``dataArray`` is the | +| | | result data array. | +| | | | +| | | ``maskArray`` is a | +| | | Float32 array of the | +| | | same shape as | +| | | ``dataArray``, such that | +| | | ``maskArray[i,j]`` is | +| | | fraction of the output | +| | | grid cell [i,j] | +| | | overlapping a | +| | | non-missing cell of the | +| | | grid. | ++--------------------------+--------------------------+--------------------------+ + +4.3.2 SCRIP Regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A SCRIP regridder function is an instance of the ScripRegridder class. +Such a function is created by calling the regrid.readRegridder method. +Typical usage is straightforward: + +.. raw:: html + +
+ +:: + + >>> regridf = regrid.readRegridder(remap_file) + >>> outdat = regridf(indat) + +.. raw:: html + +
+ +The bicubic regridder takes four arguments: + +.. raw:: html + +
+ +:: + + >>> outdat = regridf(indat, gradlat, gradlon, gradlatlon) + +.. raw:: html + +
+ +A regridder function also has associated methods to retrieve the +following fields: + +- Input grid +- Output grid +- Source fraction: the fraction of each source (input) grid cell + participating in the interpolation. +- Destination fraction: the fraction of each destination (output) grid + cell participating in the interpolation. + +In addition, a conservative regridder has the associated grid cell areas +for source and target grids. + +Table 4.4 SCRIP Regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Return Type | Method | Description | ++===============================+============================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| Array or Transient-Variable | [conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)`` | Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Array or Transient-Variable | [bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)`` |

Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.

\ ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.

\ ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.

gradientLon: df/dj. Same shape as ``array``.

\ ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.

| ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getDestinationArea()`` [conservative regridders only] | Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getDestinationFraction()`` | Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CurveGrid or Generic-Grid | ``getInputGrid()`` | Return the input grid, or None if no input grid is associated with the regridder. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CurveGrid or Generic-Grid | ``getOutputGrid()`` | Return the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getSourceArea()`` [conservative regridders only] | Return the area of the source (input) grid cell. The array is 1- D, with length equal to the number of cells in the input grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getSourceFraction()`` | Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +4.4 Examples +^^^^^^^^^^^^ + +4.4.1 CDMS regridder +^^^^^^^^^^^^^^^^^^^^ + +**Example:** + +Regrid data to a uniform output grid. + +.. raw:: html + +
+ +:: + + 1 #!/usr/local/bin/python + 2 import cdms + 3 from regrid import Regridder + 4 f = cdms.open('rls_ccc_per.nc') + 5 rlsf = f.variables['rls'] + 6 ingrid = rlsf.getGrid() + 7 outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + 8 regridFunc = Regridder(ingrid, outgrid) + 9 newrls = regridFunc(rlsf) + 10 f.close() + +.. raw:: html + +
+ ++--------+---------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+===================================================================================================+ +| 4 | Open a netCDF file for input. | ++--------+---------------------------------------------------------------------------------------------------+ +| 7 | Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset | ++--------+---------------------------------------------------------------------------------------------------+ +| 8 | Create the regridder function | ++--------+---------------------------------------------------------------------------------------------------+ +| 9 | Read all data and regrid. The missing data value is obtained from variable rlsf | ++--------+---------------------------------------------------------------------------------------------------+ + +Return the area fraction of the source (input) grid cell that +participates in the regridding. The array is 1-D, with length equal to +the number of cells in the input grid. + +**Example:** + +Get a mask from a separate file, and set as the input grid mask. + +.. raw:: html + +
+ +:: + + 1 import cdms + 2 from regrid import Regridder + 3 # + 4 f = cdms.open('so_ccc_per.nc') + 5 sof = f.variables['so'] + 6 ingrid = sof.getGrid() + 7 g = cdms.open('rls_mri_per.nc') + 8 rlsg = g.variables['rls'] + 9 outgrid = rlsg.getGrid() + 10 regridFunc = Regridder(ingrid,outgrid) + 11 h = cdms.open('sft_ccc.nc') + 12 sfmaskvar = h.variables['sfmask'] + 13 sfmask = sfmaskvar[:] + 14 outArray = regridFunc(sof.subSlice(time=0),mask=sfmask) + 15 f.close() + 16 g.close() + 17 h.close() + +.. raw:: html + +
+ ++--------+-------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+===================================================================================================================+ +| 6 | Get the input grid. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 9 | Get the output grid | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 10 | Create the regridder function. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 13 | Get the mask. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 14 | Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0 | ++--------+-------------------------------------------------------------------------------------------------------------------+ + +**Note:** Although it cannot be determined from the code, both mask and +the input array sof are four-dimensional. This is the n-dimensional +case. + +**Example:** + +Generate an array of zonal mean values. + +1 f = cdms.open(‘rls\_ccc\_per.nc’) 2 rlsf = f.variables[‘rls’] 3 ingrid += rlsf.getGrid() 4 outgrid = cdms.createZonalGrid(ingrid) 5 regridFunc = +Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() + ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+===================================================================================================================================================================================================+ +| 3 | Get the input grid. Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 4 | Create a zonal grid. outgrid has the same latitudes as ingrid, and a singleton longitude dimension. createGlobalMeanGrid could be used here to generate a global mean array. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 5 | Generate the regridder function. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 6 | Generate the zonal mean array | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +**Example:** + +Regrid an array with missing data, and calculate the area-weighted mean +of the result. + +.. raw:: html + +
+ +:: + + 1 from cdms.MV import * + ... + 2 outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + 3 outlatw, outlonw = outgrid.getWeights() + 4 outweights = outerproduct(outlatw, outlonw) + 5 grid = var.getGrid() + 6 sample = var[0,0] + 7 latw, lonw = grid.getWeights() + 8 weights = outerproduct(latw, lonw) + 9 inmask = where(greater(absolute(sample),1.e15),0,1) + 10 mean = add.reduce(ravel(inmask*weights*sample))/ + add.reduce(ravel(inmask*weights)) + 11 regridFunc = Regridder(grid, outgrid) + 12 outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) + 13 outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) + +.. raw:: html + +
+ ++--------+----------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+==========================================================================================================+ +| 2 | Create a uniform target grid. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 3 | Get the latitude and longitude weights. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 4 | Generate a 2-D weights array. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 5 | Get the input grid. ``var`` is a 4-D variable. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 6 | Get the first horizontal slice from ``var``. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 7-8 | Get the input weights, and generate a 2-D weights array. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 9 | Set the 2-D input mask. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 10 | Calculate the input array area-weighted mean. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 11 | Create the regridder function. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 12 | Regrid. Because returnTuple is set to 1, the result is a tuple (dataArray, maskArray). | ++--------+----------------------------------------------------------------------------------------------------------+ +| 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | ++--------+----------------------------------------------------------------------------------------------------------+ + +.. rubric:: 4.4.2 SCRIP regridder + :name: scrip-regridder-1 + +**Example:** + +Regrid from a curvilinear to a generic grid, using a conservative +remapping. Compute the area-weighted means on input and output for +comparison. + +.. raw:: html + +
+ +:: + + import cdms, regrid, MA + + # Open the SCRIP remapping file and data file + direc = '' + fremap = cdms.open(direc+'rmp_T42_to_C02562_conserv.nc') + fdat = cdms.open(direc+'sampleT42Grid.nc') + + # Input data array + dat = fdat('src_array') + + # Read the SCRIP regridder + regridf = regrid.readRegridder(fremap) + + # Regrid the variable + outdat = regridf(dat) + + # Get the cell area and fraction arrays. Areas are computed only + # for conservative regridding. + srcfrac = regridf.getSourceFraction() + srcarea = regridf.getSourceArea() + dstfrac = regridf.getDestinationFraction() + dstarea = regridf.getDestinationArea() + + # Calculate area-weighted means + inmean = MA.sum(srcfrac*srcarea*MA.ravel(dat)) / MA.sum(srcfrac*srcarea) + outmean = MA.sum(dstfrac*dstarea*MA.ravel(outdat)) / MA.sum(dstfrac*dstarea) + print 'Input mean:', inmean + print 'Output mean:', outmean + + fremap.close) + fdat.close() + +.. raw:: html + +
+ + diff --git a/docs/source/manual/images/curvilinear_grid.jpg b/docs/source/manual/images/curvilinear_grid.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f09fe0d64c7b7ec234b2b2e3b798cbf1076535eb GIT binary patch literal 105315 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�U%Xb{X$A!pF{r8%bg_XCA&#c_ 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 literal 0 HcmV?d00001 diff --git a/docs/source/manual/images/generic_grid.jpg b/docs/source/manual/images/generic_grid.jpg new file mode 100755 index 0000000000000000000000000000000000000000..935a1de237e0206569c987e0a790e2d89d657ea1 GIT binary patch literal 86702 zcmc$^XHb)06h0UPq)YE5bX1xkMS2Gj5fSN4MS7DSAoSjwfT9wSCQ?EVy(JVuI)ZeP zh)7Q;Awmet@4szkcR%dz?9ASI@B1Zh?%d~=bDr~@bM@!p`p9Q#6Wk8@fHmY0~-S)GYcy# zD=j@c2OA3q6ALTLe}j;aUjK)ToQj;BiiM7bj^+PxyXpflQj+N1xJybR2)MyWLdr;T zg#Z8n021>5W=lc>_+J{yjq5qyq@bjtrn&y0g#mDbgp~9K8R>tszWzGm`gZ^sBRP|R zjMhzN)0Y&2ek`&vIVF@r+711z&!#cL_h0$PQc<(9b8vErh>G35b5~AYLGgi-vW~8v zzQIGoM`q8>EiA39ZJb^^ySTc!djtdq1&4q_!{Xu-5|ffsQgid(<`)#cdtdaWw5+_M z@@v(%#-`?$R#;nm#{e8LI5a%+eRO7a?&ti%uf-)K3jKTY&(`1V9qiHZ$tms(|L^=i zTqFR}{~6Z*hV1`;;v;#q{BNGxC*jgl zQD)x2Xu>mj%9kBQxCz(UmkR3Ibr#mbT~>{gf`V^@pVllM_TryWQ)CYSFIKo}%n zbxg}i2BQ#&T7|O65nS+0_u$WFKe=hU2ieW@&%T0G=ivIwt!?sAnwQmq#`==-@{Y8i zI5-Rje{FI0-AiX;%xy}$u8F}Rs5_&S!X4pH!PvOZ&$q6}@|5KN&u%BYPNvG~hvM#b zF}~~C*?#;U>8-uBmm)m6EjPU!TKqUb`8&V6DeFk^n7?P|muS^lL{!sZ+-c{&j(OIj zWKTr}CTk&w$so1VCfm!8k8!U8Gd7PJINy4|9a0F5ws4J&a=B#I!$=M#pj1-8df{P> zwFjkiSn zXL8MWdAqg!WC4?c5_P+Ob*}mgVul`o#Z(XAq=Po0Um0l9tJ}^+EF6|gq=a&sfig#M zeR0GVd(OvEAXfhLI9vIniJXhO_)6pXx;n>aQx%PT5_77K?w+>`Or*}y7R4{`h=2qK z(McXL$6av0XB=p}C+;CO6H;bCwvCj0V2C1HsFPcjUlKQtr7SJ(*J~;N_RdwNAQ<$E zP~GjUArFYq`U<*$bD5-`tkXJzvJ4xsQkC3BPNjB^dc2!6w_lC3h``!NIC4Lu-B0AZ z9ZXSCNo%5W>QXiyI0kom*5R(KJ0}2B zJ(mAtCz%|?(hSUQces?Yrv!$|T|N`?dl_7a<)}jgWI&K$;ir_sRYGJI7x&DCvjM;J zmU=WX^n1RjNg9xJe}@{by2RcH`ALvhc6iJ^8Fnl&(z~?JhZ5<$3s2w{%;INEJ&qI*h%l?LlqV`TRcK9L@M`;K$`7_Q1F|$Rb)zx_?a-Gl{V0 z-|1n&vgM&7Bp$w0?2tdPeB;Y8dYJLvUsm>hv1f1>dIK6yFh1u6n6ISVIYn#=}o+^UfFTr#2UcG@AwLF z`6kLave~=K*lM@d3ujKbTYmW^msfMx#uiLlo-F1O9j-AD#Tzv+g}2^V=Zr|YxKCt~ zWE-=*VE^#v60*-A+~aUr-RVQ{S-PLT5m;B(1H8%nnO7OK#-r(U%EtZ=upM(`(sQSmz7l0%hW%^z_^FeTqiR&lN!1h;wB(dw)? z14CH)lrD4U3I`*gcE*qeVbl&LIjFGx-g%F)oh zD?n-_AIA3=cyd32-RviE`44*ZLKw#w8m>TCCa!;4PFxq~P-*P82cKctaZje}@-K!6nb=W%PC=(n@6?@ZKmh|s1T9PyE-I}n z${Tse;ud0NySNJ0Sr96q*|klcvHB>F!wN9VzWsft#jk%tQ+@hNkKGj@L9y(5A%?M} zSAbh=-B*C`En5x>m}ccJE=W=j&u$bG!5D2DqURO}1$sWyd5tV}F{;|^VbFY}5UfH) z-Eg}`4-heJSBdDoKKY%P&EjetaG$=})8#aKqI0u*D*5HWJ$QAIi!e&6u zQG7uU^RzV6@Zi$$AU(;B#AvKE6X?(Z7HgnH@~VS<+*bx&=HKx9HEk*gZ|{UP7i`3o zsjFavi^URudvZY$ykWe2N`g5esn7H4-c5|`M?NoZ&Qb7_?yRTrDPM1qBc^G{LH2?k z2O$V`NFG3O(u$)O28$b^;O+}spZ#~M&1j|mZF_t0I`Rte3-+Y5c@BkL&r%IR?HWH> ztd$BBKufwvN{@Q?FN}E(7Z{H$bN|TCk4CZ!^F<9iHu@&3O3AB*3|s-22;Ozp!#ss_ zpFxGgHoxzdJpWX`x@?!2?so-{6nuA)3OFA~{l|>--CO+zeu}v^4Pd8l1TE}jlAN){ z=z>|xw45XFZr+n;y2m$G>?Q-X$gN4NP}*e*!d|f|(m>(}aGB3|J-$bjpo7`mqtO#cS&j)vl`ig~(zM#3*4xCl>+8C8hl_$p3PA2s%4;^)v6py_Zq zt1xng_m&kpacG`@%KJ z2v)#3F%@5FiFv+$%jKv?KoOzF_2Z4IVL3q;Oa3Q!?dU-#lWp+i$JFSLRNS>jY&l4^ zS12PBTF?Ks%ri2{(-t2v+;KW1 ztnFFKgpMNA3%E=h!2U?msa^W?QxGa?Kk~~9ly}90Ue{)lLIBiQ9#5MfFAEUaIW^QEA0uEShFASbyc;|+od>^lChu1 zI6)lJTo-VC_m)yID$>7>^;=f|5RCEdp&y+l@iA3&y~epv$EZigS*aRi!~L}u8Vqar zNtAj6hPd^bebx?iX2a~3yXEotafngR>UZiz@=`B_V76Z*I9`7U6CvmdKz#@=2!sBL zYF3}FbyqgX`}5B>a{24>V(9y&#YJ4kh2OE)a{h$Dn4>e^`wE~ZHn@)W4_YT0*J!Z2 z_uguuQ(hXFML5V{iyJ~hZ*1GpIx?KLI~@EIW?J4~1({Q;dP={G`uQ*XNMVX%^{wR( zBFkmEXqtAjx(L1#`((>5NcNgvIOBKCQfHJneh*W3)evpAJPKbS0EXYI$}f{^%8r8x zp7>=p!u}$98M?YP%YSk<4u}xZ1NUF361b-cPMDzuB9jIq9(OTlBfq+qQ2PYJD32#B zj~T8}y#3;k;3y|JdLvrqb{{G0wj*X-o$(6rxfelCct8}mrZzi(Q=3h7=4)!hmNYPV z6F;`6u?WHBxV75!{_0v+yms7fF(OB2`}WHr=-}y(uB7E4SA<5Kjba?}HbFKWls1gT zyE=4qPaS$MqxgEXI>Q43+(i#t5A0}+lKaT++)t0ycKVDJ>!VLvry>AmfAwY}X9K?q zG&jryUICJeP8c&SI3!U(A1bcR902mU(`Ocv!#T@nyesZyiw2#S;D1~r#1%C>%f7#G zZ37ukw}oIGGK5X4PIG4iF|yBOw}k^zk05bG`WYfW_&#R7T_Y77AX*w!*>|>0f$;W2 zSgKHbjIaI6X}Ka3Gy8d46X;>;DC!Bh)g_Jmq+oPuJEZ<#b`Q-jw*X{pnX@atk-m0h zxIyw=l^P|f%2=lZ^$1&8vK*@J1=!izrg0~Cy{!H4wc@6U()hdH3+oKH4orrP+;Njy ziy!ESR~&Z46yURl!z_PAe!l`x_O$TjY=w3bXM3MCbsx(#dkrruc#lO@uR=bMRznj5 ztLfvBEi|9#haB#A|MWeGTirf4$OLOiRR#nKrpo-WH3-?_)HS;CX*XX_^UY_c3X{d8 zVF#5)+cXVU5FA-^ci^F!Id-V?+uDxTQPbubuM%{aqiBtGW6!7L{(im}MI&j=^ zzsCo>-ZB}*UfAS2*0jgD+IDd47Xy>rC>FiU?9!^-q5ldpK|wO*AH3TY-0iTbxeKdzM&2W(hdNdk~lU%!T z#x0p_lc&i^b=0R&;Wj)cIztR4mA66FWmdgrzta(ftMWuS;;r~ZGoH~{d%wyyd?o$l z^=kOd8!O~5gq0qXzo2jV3%!Yf?PZkzJ-0_F_aaPEmM%{&vX;uQe;RyRf8!FE{=PJL zDUf}h=U{^6#)V@w`n~BbusjY5SSW&?c2VE8VEHMQ*#7dHX1kKOgr&n{bUq2VEgA4> z0`!@_s>}J>H|us8Y#590X z`G#X+kpa9H7Uk>!iap%_pgOs~&bXu8v-+W7^Rh7%+}jn<&DC{Bw7jhPQ{j~SKG%EscglolQr8d*p zKX;3iP8I(&BtNUFq23dH^RAAa`;DVj9@%;sxi99!KT@fG-_ZCKPBf-L0x#1FAm;$6 zCcYDM0qza#e?Mht0vc%jXL4qRlkr=9Y^0AI>eByBXDv`h+K#$w6THwbxNK zKz^_~(MT!?8+_ZUkHT38sSKs+-u?TXMmM{GtZuWw&Q&Oz8~~!h&j}=h9k)(dmxucLQ*h?wLVymMyk95$JQj!O znU+=)i*64TDzL|9hX_2SRA+sx%8ac8BSAYf7 zLgT{Z5-tTxfhx@G(!kR6&!30HF6cCLHaDo>Z7DKr`6~6;<>4P#2HMjq1{SO9;+pqH zrQ|VqzOF}xU{sIQPuuup*;k~Vfr@zZSnkqWzA3b{ErImMGPv!4Hs;A`{Fg*(_&B%G z)0;{A0cx#<7>8qfMK+8F5!l-}e**gRPJh92et}9NxZyWp<_YU(N+n+v(%Rs4`pA1A zX;e#dF5V2$5!oaxbSXGP72VOI)NlRyL9QqT-d^h)kp*w+TrL|E)Z`BPCWI43f{Ipeb@(!dq``Jhn(r1s$qWVjO z{OA`TA8LOIY563L&>&N#srtKQUXf6_`WM$&SLj3yr~AOM0KS_Fu+M6LLt!remxbhL zeE^ak#T+TK!&MnAe>U60f$xORv?R7fxUw(1&IvOLy${3+z7zZ>*828earo`Gq-@k9 ztK?UJz3K|Qi!{Ru$k$|A)s(H}%|cOe655lc$6o6fvtU}QnS||17vw=cYZ;iIE@l#R zs5jrGbn(=qs50pUUguDoP?)ygZ2nI3JUvGzsC;dhCw=sb78y?Bi%E9lSMN$sXeF4V z2WwuKe0`64Sv|69*A}g}m(mwrmb%p*_*nR=&j^02aY`SkD_>A?buiHb{5wNHF}wZi zjFG%!b`r~)a;RSa|Hkd%1JcY>waHJrC5362@88&algusDx zwxbfKpQuVxjkT@V{n(aoEr-8;K_by!=n42D%cn{2w(xp}s7MgTs=t5P^DxMWW?a-W zyv^p$i+4lQ&Hh8n)|`fa{eH#8(nsY&oBoN(Ap2&bOXf-ljlU2 zbKMSvPBowoNVXeXEHKxyo%gH_^V&vrDdYHwq*H>h_58u@8f0LLV^NUR*wz;9FI7eO zWSYZ+%XdWHZFM$$5~k9M>q!BW4wg(%3NHGT9X~S8@s3ul2jQ$eL-*b;v44Yf_uG+l z;$Y1+fs;-z&}C@KV1Ld_sqS38d>OSlTRC+m{{tU|8=e8b_K_q=Z$Owpjl}!$*Dfd0 zmQH`X@$0C=!P+)5o>A~qW8*{phuX?VToJ?jR6qo;8A>t>UMoe@ZE4axbEqm-wYEG+ z%y5^S%YFw%wdbAHEads)kdNN=Gv>e2RBwa|;}3|}-h8bENjg|36tj-#;q6H>ZlI+y+d-`s{2ZTw5r3S!i(-rMMQ712@9Cf*RAjB~+7n+P z?)Al*>>_X36D>J~-%SPX_?%=VJ2IjQ=$@dKuhoX6%8b(7QAGJct!(at&|e((r|=3;mSb76kl^lc1OEwg->_+x!2HdIV1P-4kOj}L z@nD6@iz_{;0pAMFrYj3?(+reh`T>h_s(Wm=IE z-`bxwSJ-=@me%~P{X7FfrkSC3?dNU$*;J9tUklM1!&Jlz(T0kp!-?R88E@gm{j3MA z8rv1&3w4%B(*5hn8uX_TA&6p1>|EGEb)8)~vGxnTV?v~{yUj{4TJ^roP_7Luk4z?3 zcPx46X@iSGv*VKN&aOq?zl81rbx>?|VS&Zm50DuA|i;Aj~nXON%|8AXe*{x6j~SV7B(XZNocLApp|v znQ>Xvr4E+74xi*^J_S#DBgfUQkAsJkPoh4-t^u71s?$Kzrw0Ku9I3iIkH=)|)ia3NHvVRNp z19>7IWsg00N}`ZkEob>qqnoAy0PZ(oA^E#Bky3eWo7!jPJ!$OCjN475!c~4*xH&r> zG~N?PYG6IiitVBOYqLINl3dK=IS#^$!Kb(Vmj3Ekv>CZUMKY}`pNv{HI=SbVE~+oc3I*aumwqIdt20eRpm~r zWk>#5+JTfem)2vcyfy2k{P#?_ zU2{>$B13+@F1u-_;zKs}r!P zh041WA{U?%3q)2TAZcrSnKM@aJIrB%AgrrtZvUh@{7%q=KW#1TnJCuwPist=!W2b8 z{Uqpw0jrbV<>%L!p;~w3VH%e*p2D^*-@E42S7l z4~nyCoJQuv`*FAb->R0#xlwRbthQ$0jyJC9Xxv}e%6XlWCrR(;6%4MG4`V}Xlp_wN)HD8<2epW$mmxe z*HEYgU&nqkozt5Gw%2h zpN~02)gBJgnLV5(L{+S~GrApZ^Km9x1@ZE&ii8#!1s3Sr&I&y^1{^^c5R7)Q9Hf84 zjv!0n@R0NM{!25{=@%CU$%OlIe4;Z>oU0<^Z(}!fWv&2f=6uZick0IafQ(&=*XgGQ z&tmqUpMN%QIdQ96TPA9qeJM~NDa|pV%_P0E5o67Fo#bTuR6T|~q;sD{O|spMJrAlW zwqtv765g548uKO~mP?=W4)?|sg((ukXa(wphgo!&Kb8s{e>Nk&Yn@~$kV9G;dAD!= z6ZmXHnhNZMXGN;;(iqocDiQRzeigE{vYjz+v(Gu;dy_>9>m_?XlG~hNpJ|w)jbOr*HR5pq#0~objqjJ{BZ>kgnewk4NzKD zL~X^X-y%*!80G9e5goyKrJ$q>4GW{{lmZo7@8<~bI?3|F13hs)U+3GFFC2foBH4); zL#V4SAhCsCAcVH8OVIqz9oGF;~WP#;LC~*2d@BBwI>UV1aVApR;YJvKT0xeMWN)+ z@*|Nc)We&7hP-tc;8j@`3?TVJ>apQ8$>LMk-EH3=w;Le`+x85W` za?e!f>#Ei0>vd9Nkv7X?VakTCYHsm3hfOSveHN*WgHL3K%%)`{vkp^tKVSnFbF6fZmGfaMLyCXPBhhKHcow=eV4j(&zP8BX5pe(S*{oi4Bt2!cwUvbF@zwy1=MHcqJ^>R$O* z-X2miZRm$r9f}Cq<)GXO8t} zyErdQK;&{459Ka+b^41ca#+}~$>^*-7#ou<;@bm&fyfYmhx}xFU;cO^HRK^y@ zfNigb?=Q+q^-`6L@bmKvlEAuScPwU?j7bMwT%C`tRCM@*sc0xitf}}jOCMiW_3(Ya zZw-nw`_LD*Q-PaSed)90y&RCWN~La;3Hm|DFC0w=P{FmNWbKV(WjAjDO{VIC8W=k*)h1}bBZMS4^%Z$U_;ac2eEtO zocap$*4Eao4gK#1Ncu^JS&g1xeFvrEgB5UmcQIgfwJC2QD>Fxox&_whDT~~>*JS5| z-^tw26Fks=@qK37aHpX0TBcec3rrOUmT<%m~07*7;EJi@?oL6rji^>n%0VgHoZ zQU{w+rag1?`-?#j=f0DnuWl!oox5gqpY~^F3tv zY6REB2h?JZn1^ym=E<&mt+!P3rNS@wH}Lzq$9>+y79pAXu=w2B(CDFZdnGc`CGoLd z_tq;wngHs-nYVRDZRc^ucagb=WB5d&g`zE2{3QA?@jNrX6m-#-Qfu$A;AAq>0wrJ7 z_x7!OWXPXs8(zg^WO0WXw*DSq_MW7#R+^b`9}5|>7xVQo{7Z`hX_e|H>qbmHNw$JrkN>5urgPm*FHMYe&A>Z_Oe zt|%IlhP`7A7+C4+HaF~GxDYoYc&xrXF~02IKD0SPVfnvQHc^n&5k$O0P-?wt*Fv#i z^Fyy9gj>P5J5Dm4L#0%{(}cNoQv~&%>S(qR)!Id~k+boEd*t`^rZB9p*+qQWGW*$; z)%>`hO^)vOAlFM%Mtue*b_wegr0 zs&p42z0hjOZ{z+(9zxTjoT1S$<*mJ4Oxo}oH#V`hgrEh(40d`~jXO?*Vl{|QGL-Rg&b&$R#b$`-bO`-DZeBuQ! z$kGVAo)}bXfUs09Oc$F968f^;i^-co{Iu4PP|^aaX3SnB_H6j-9D2(%@i^O2WM zI)A%esoU|k$Lm~v?4@^(i&KYDCDd>c8szG@f67$*v-Z zwz{?jL1vq(&Oaxp+3VnDv#Lhe1*7)*-o&Vz_?txbSk#iaS+&R1gQd~FO>e;rg$6-o;kwFUYiOZpt?=`9p2IK_$YFbpW(W&s^u4>b?VytHU6pYB`kgB& zsS;nxhICSx-dsmW`YGKLUoKCW!me6H%U6;{%Ce_@Hrnb&LHwD|eP3oA{C0^}Ekzm( zcKXI~skc;s;P4(%%tBnng7m2*4MMR<=YvQ?$EO2xv7@u^?u~}dno`gBSqvs0@Re!| zN6_0-d2axvQR?M)6HPy_42z@-)a%$e+<2AproT0IhILaY?4$z=jd`kv^i7W90Q0iE z;tn^ClnkDbxBu39hHDu41#kj-q~f9lfA)~$ONYWP3)4=slEbo+x}2Q6>p#l%7-dz*H>LG@hL#0~4d1@P}T7ttu$v+VyZ+&8@5paR* z#22AiOR$Zk1QgyJOEDbAm%YTEUL$8){ZC$+e#NNL&aq79Js)=*sn`}wJj^#%-qw-DgW;EZ(WkDWa4M1z$hdZ~ogZ{kD0@Zl#&G@TTkL(1o6tyl z_bY%4-ZG+e8Lzz+G#7TO*6py-V5x5qlrBse>6G%!3hmC(yi&b>DltHdj=g3w^<68c7PnGPC0c8y@7saCrq zH|C^XQoGU>OEu4d{*mQQf?SPG`jKx{e*}9xcvoDf)#$tQJmTOTHEW{t_UTUWCHtC;Z~6ph*VZ>s@AUL$qD^{w z{b$N9=R3`pl|Af_IW^lbhsia`ehYye&%1ao4^N^Z6~inI(T6uYZ2rJX@p zbN4OclChQ;v*>rW1JLiRm(J9H6f1rIkVg-yWr))-KBk`5=^i1xkS(UQJ?M68eV!q# z(0aDTdbEjhzm7lajX&eWcXUF185)pH@;!1Yiq-2>WAO?wbncow1Ed928>LeDo>af@ zzbV(2@dG!Z{SPBs|Gwir;&c>UR}gmAptX0trbUAqPkmdo^`{)2pqo$7Vr@C4@n{TBPFVwsMteq? zR3=_zKmdm9O%JQ=qX)Phd4xCs@oAW$d6t$ItYSjlm)1Fcy?>@Ijk(56Js?pk)qy?~ zEmjj~wvb2s;ZH^6aJ0KEr~+XF75`B^y(8Kkxnn{gPY9*o`-#;+K?YT#nERw()n9;d z#r*Z%Sh<&V63v~<4;@5cP3Z!G$LQYYp|3d@p-eAgmj6bQ;~^Is?&~g?^1Hj^Bl{th<6L6>H&h4XMgGOK8I7$hp> z)4F35Z3GbN;-=C3m`~aE1CSE0gRn_Tk=V42FnIKH&(X;Ku7y3)r{bOW<|D{TC?e4U zP)%xe3<9DS5(yzy1l{^h%y4pxn#q&qS!u$Z&2eWASZl!_EA`1R>+f&5zaPC$7JhGf zQQQ8RJ_IUwS*h)Sr`Mcb49Tz^B=R+j&%L#`SaR3D4s%tJdD{yuq8S&@KwO?Ff$NMb z_ITz&hPv07^_1H2mXnYB;~lYM!DSmaTivxrI44pXbkN_{Yo=M8{6g>aCn8-iT0;ETTei!y3#or#4Df?A zPQp#-cQt6iYN%D4c{D=#;~9HlnDctFw2%B9iCV4$-$vn^n=8Yu>)(yXVwe4mm<&%K zDL^uUG*%fkYuX!&Ho}Ue=GSATGL)L<_F{H~K85}YA6m}oO)&;(?7`6{yptQo%*L1& zSVBwpeQnHsVl-IMug1hFsC0FyMBj4;S1afLsGKD0yNc?^#E3=ppH(2>U@wFEq&sTW z0&a{sFmiBP1K#)TIZ3sxxV!cwpq-JW2OwGBc#nb#>BtGT$U@OwuOFxdLIW!CI(gUP zM(_@xO_9|RK7#WEEb1h07J`}Su;WZQoc~y`wpS9h$ihLj?I$p64 z$_qx9fAnSw1MiaMUfO!Z6u5u580x9IE;65va_f}jex9U>FDZv4ItXUJjkVX`Ff8*R zd!6SVm5?!^bhOE6bOm^f9rt%^7DGJfxdWE!p6cR8u0{=W>7A~odYql}7Vk#w^#|}2 z78{L>NTv1V4zaEO5WbdyEH4a(iUsqK(AY(x_h3ELg=kyCoWiar!};6zID+t^e$v7Z z((Z5$0PQVuK!77XQ3T|KDo(g;K-#;kTQ^v9aXwbEmfUpgW|^+1XGvS-HBWjYUICT8 z&RGcQV|`k#RfH#5Q6U>yJct-G#5t$cpM1-M;ULbNDqoY%L@kD%%*6j`JB)jSzd#ql zfw%CbgFSNI;wC>ovu9g@^oK7VtlD(sFpsHb$yNWkW1W;e&AL+E9-G_8?bwvL&I|z( zv|a#-Oi;#^v^xO{CXIs`J!-5OT}@f%c(EReM$72!HAXCKZ?a-}38cNWg}M$rgc*mC zRlNGJ(gFI_ruX%*oV!~LKP;Y7F!fT|e=6MP+~Bnx!0g(%GzaMyA!}aENb(2IE$v61 zHZ=1;%B_lw=Ox5E)sR%@I$v=L)m93OIZH5mZv z@1Y!cBR`5*^?TrF7}Z7zhLv?&eADAh1JXdtzu%QVA4D#A1_>OfVt1&vDlRJtI_S=r zGJ+I7DxlV5R@lFs*d9UG1M#NKkw}q;YtE{^NYWO}d1gV@SVAgBI@nu}#ec8WNK+RD zT>-4xu&_cF1(*Yq`K;H;uTpp6)Z3r)CXN-1#NLU#ZT>LL`RE0JUH1-rCtV z4>m1zzh`q(k!jt7QM*22Vt@0U_t33?ZAWQB7{2`*_|<%uN+noiIw-@{5>wZ5vsM&Z zImi<*Ok*I@J-Jwb_IjDo@?(>(UpIU22+^0@8A*e8ul>8uh{BsdJ|Mj1jP#E=l`zeKtjr0p(5Nwe_D(Gzn- z!xLSNE(@r~Wlb&9!p8nWYQd^#C&u|QEA^FsOuFCV%COpynxbvl--ve$CS_nC23Lr+ zI75-gM?NWusJzT5iASw8jR+TP@c+|oBu}yK8>7q<-sb=yRn;(x!y4p)Mr!wwAsMJS zIqutpHdSeK_)AqrsF)Xf@J?=@+9y|2!d(j1j178vP!_HVlb@BU&c91xh{^buEfx({ zQO$uLJ)CY1IeTa5^U&GZZAy=Ei1Rhi!i@ZHU{hUS7T(%{%}W|bpMDCI(l{6l-`sJJ zxm-UvqVRp2IY+YMK#;}+mu|Fm2?QbS*|r99^aZkX3kF1+ba`1{ir16mrBh=~$gV*_ z6MEfhT?ZyzL#jYwv+$*081hogqPM-LX;w;oHiUIni{(h!U}mar`t6wa61|3@<%A;> zQ5@ts0BqJsAUqc9=$#3yZ#{dO z!4xQ~S7l`{JbzGHO~sPW|KbeFg&%~jgTpX48;~Z61vIsGPcX`$+;hw3>HW<_P=$qU zboz1qZOS9Y1@Xi{Ig-P-mg!58Gv`r>bprMH($DK)iQb%e&+uyH@zN(-JbGU%4-x|g z#y6FSo8EA&#T8)K%!B@yk3alf|w6 z`C+Ao#0U-Adt<-tjBasXmTYcZ#Pvb#p~VEr&jho}PbaPou-O`QanM7%6^G`qM;VGX zE$&;np@g>boRW6UBPH|WS8pgC*BJBW+%l>m4rD>8+6CUh$+i zQaq_hL#E8`D0^7UE1ygrpwd73;<7UGwl11ZIti@eUlw?K)}tY7IMC$Wveq(j9W0E0 zUjb@G4|f1FPpTp8YrmG=mohWHZu2>$g?Rf4A8GM8bF66oT?heo%Rb@;{df%^uhqaM z{4}$7q}p|)1M5`aaYmt1`^_I*6aS2!Q?AJsfTUr1CpV4FS;(_#N8f zyLf5p*qQI>*S|goEtl`eD*paDjDgxfS+KqXS;-pAl~bp+215!xl=E`j@T$M9$|C7u z3EeGYw&Om3b_{>oY(7@JU-4^xo%@JNz)Cw(8UFzpEJ>6GJu;%Xr!AI75Taem%$E_P z7Kt&h^R`bhrydjZ;iod>e|mFk$mHMc-WySS0qs|Sxo~T!IrN>X7S`4hpMtI42osB! zYNn?XOO@J8J+p4Jf>st@keXAIe@R^Aq!WFdSx5c#=$~+eh9)_S>Hp|Jb;66e7A18F zEvL`l(P`d3YIjjqb&@rw?9;-cYks_KGWy=Cv!cW9Qr!MtdOGj#-3ANH5Jerg!#Y7K zgJL?EFAiVaF@(pM`GzWw#;7mL?;$@rdto2-w%*6qB!^nu9i%2X$zUNtuGgOtir5D< zF4!eCPDpGtT1E0R&h|>NG4hm>2mB^fJGoz0zBHy-%z z)p+_1g8>ur-N7LFJR3Jk4<>xpSeZjsJq=u z<3q5G@T~S6I-a z2^%ilL~kx^UBa3bg z6nr$aT_eAH1z@w~NX&YmIZpeg8rU+Plo4aVu%E41gz$Pn9jTZFUs~Un$An#$&O$}H zF~m-sXOgaKk*tKZcHVbx8*RXz?cDs^C703*HTU_m){ePzDExzAS7-Nq(@g$z)>78z zxl2~lMz;L~Ln$0%u1*Yx{&5r|aV(Mw@9bPL{#7dgWkT<0>|Ehd2-~?;S~0?zJA)fV zkr_(fFuq%r$(xPH?fimZJv-%srK#Fu*alAylVwb>Ldc)f#_IHpOUos5`{@&cnQO$A zm#&tsR)YvlCach#^!K+(*EdsDzB=47bxzc~JF+3$m@^{OCfMbOGsH?>t7p_D7*||* z?LotaXD5_qRflC)xQg}TA$fDA?89Tp8FsSM)!m{^bsl# zWwi{_3HYB6j%4HU(QVGIwmeTmc|=l~pYG?b zy72#m6DWIk94d<-aRE&sa%0TXi-P8}Ze;`@YaPwmiazb#o0O|x5un5%c6>yaSu$mX zRf=R4=9Bg&k$6!UmaPP85`Y5oxP{>=KTpi#OXCW!~$bX!|GAUUPt-QxR)rcm$I1S)~f;A;;qAt&L+1_K%lQY}E56_2IheD!=Z zcks`$+0w4=)P+e{$Fb16ssCkgb2310f3-b} zmb*@U6vm%K(Sm7agl3!Z-iKd`4j=b)k_Mj1TCW0tc>8b-u#Do6uP>~VCtwck%dE=w+`5%XrID|g}=*xFU2pWxWTpbqi=v(iS z!>y@_3{1lKlvhjGq}Ov=ycAnvbXZgR36sui z&q-4E#{tf%yV7up+%9EA(Vy#<1Vm_;8=QM6kEQIq8ONM1#Ud8esn#5~_u@9gs}3Y^u2+Na4R;xwsF)K{=9 zrlIB2hs`z^%(nJ#soJaXY}?F2#-lLl>C>Y}R-j{?Irc2JBpZgfE-$j%&O(M$)_A{y zVaaI7T>g;X=@#fX+KBxNk#x#Q!gSuI+vRc`_JpR)k6jx!IJ~fEPu;U$9R}4>$g8w@ zn8{={QXr$+Sh7ZK!1xra>MQ*C7C;RDAT?5$5S;y0HfrFdCm$i885H$UAmA^J%y2c( z<}~cz72qL8Y!DLHQ3r$mPh`DyP*ndP_Pq$w-MyrAr_v1~rF4o&F3XD4B1=ej3MfcO zN;gO?APpiZolBSOqT&h*-{<`1nYm}~xtZZVX3x$X&gZ=2x?a~YQ=Y`oXM_eq&LKz# z5`LESDPT_rUnP2qFC+VMCz)8B3LW0SQlDgSTcylU)7pjbJvGI4(K0#_nUp`t`{r$o zCl9o5Rz?4Om%BLw`(FMV#&0x5*I)jeu; zL^C}ql_$~&eZT!QqEq>2HXAk_!S&x4t?SZVleb&F371!OU7zB8xbatuIqP#bq4#3l z&+h%+eZOpcCqeT+P=!W~@)NPbA4`;(BA~rb1UwJb1m&u>O`=#6?!Gy|w1H7n%x^=x zjL$|TN56V;*V(I*9s<2RaFn#P?KkyHb#?|A8Rrze#m;lPwtID20^( zwt&0C_jt6Ur}WjBkCzoaH#-g;X-H8Uc;x)Bs&ck$3Xxs+Ob(3FbJwuz$0F56Ps%vpQwNCY54i-lwrsw8c6FMl{p`d{e2IeARH@|WE+G6uY|0II)nR!$2t7Y! zwFz44*+(wF44EX$Z`~K?OVt(Q7WgI`qhZ?j~3Dl9%MJ{!SlECJc10Bax2SykRwOpr^|tOKaBK5mR_F zUyo~b`aN6cxNa*-xn}6hxk&;DGkfvbBYd!5!3n<*+JM|L2+dG%m$7qdc&d++g4Bw5 zopm_5iTO)Mu1_&X>JQzsXUHCV*F@r2gFZx!#sc5uFOw?g0^;A<);My$-USk}MiPFQ zJ=_yvKzAdZoT{rq*mdx{I8z-z)5Hr6UhNyWetAdRit&jD>tmB)t><7(3}?1PMqoow z2svr;iFzK*K}+jXpEObfM;UbvrgMi~IF12$>@-!Lu08(oCkb|DBo0Z)k?yeaX`k)d zOFr|A`shz;(9hEF1by(G&Y?_2C5Hf1qk+b;)}Xpn7JUI3{g?+yq^*2iasWeu)jQ z-$+lFU}1&s?iX*fYlt6(2u1s;a~?X0VS8OWZ`&o5Rdzbh{Z&F7&=zIau`Ty|pusR# ziXW(PKG(N|PcJ-~#feE*2EFffZ&BimFyK+>!=-^MCM3yRNsgh4iS^?7jMJL^$i6^( zNBg8uHna4HkM9TZ+T2)1B!;I~$OgkC(8^I?8`NU%csze0Ys%nrn}MuFS8=&5p~KVC zM(l|-?D0d95g@{$RlIW~GkURL`-1BDT0F}~%>R_xlGueHtCid}VgLOf(O|wzg9kl+ zqj|7IKth}%{&R4!p&V;6*v|Ab{q)WLyQL1MtO4F(5e)(+%LBmy%KW|8_Dr1CPgy#{ zL3eXV0d&|0h&u+X+q>iv@?(x?$={Is>hm8)ZkNUd@AM*`ot1RH*_@7a{Z#VDlLZ`V zSCAh)A&iyaB!pfA7S?}VzR=NtK773Jqu50@(?EK|;Y=nwqny8PJDc02t9&UB1W2kP z{V9yWD-$Dg*1t1$Zj{z)95|ukQ|HOEWtXCLJgsv%w@2wj6F*5+?Va;aSTQOlSN>`J zOD+yrIhCTpTQ|iY4`yj;WjQR&G^_1bD+qiTG?U^3#}qdX1eZ-HaWD)lwO#@zQI2JV z5{=s0=>N&6T^Bjda}L;Guab2SSnb-+Ff>(|48y6}1uqdU#dL#aAcJ6NSZVXm(+X zTHHmwPla`G#vW4GNNg)R&yal$@! zaQcd*S-=^&m&4-*^W-Z5kA+5N8&5h3&@Q%UMxB%B(JC5-F zLe{zI6gj1CPe5wR{Z6NHnS@t(GQh7bn~mbGiqRmL$c++`2|VQutT-ZcV0IbK6rHkI zUgmK{y=J)UM8dRCx5ASwViEvpwg396{C&xjs7!0pzba%J^9YGD+hbdmnD*R?)#6k# zL;W1V60;R^(EVVBhPS2I7SsjD)(PufU)h$Y?dRDuK;!-JMe28kmJ}oe*k_157BAF7 z%HOx8);)@yp-7Toz&4=%yi?$$w?fB7|17oP0ZMZaXs~$=GiijiR0GVD)RisQ&iJe5LB_TYw zFTmI@j@Hnzy{U*RK1MRnLH&Dq zzOEV0LrwMWmwz;*Hw z!{5-9Vn1tM6JJbcT<<48Oe>{fBq@0n+Fzo5B048NCwhni{#LH26QCS29 zF|z#UFCXLFo+=?F&Z9tQ$ZjN+vZq1Xt$N^aQf<(ngQgmlAVTQ&^Z-i=gIa{fi$d4G zaev}DN1wLZhaQXVlisNCnVS9wBBN2K!u~0vqDD|)6Dk<2n2;O`(5q$`Q9x_b-;h7Y zw*P@B0y0n%ajFbIETYKHg%^(`v%Y=DS|I;o0!}wO#hg(7g-Wr%bkU3%z?$IcW6s4x z+ni^xvbDo~->YOgC6L|zTYFc1x3s!fcchr<#Be}*Md-oFfKA(}YQV{TI=;I0=X{86 zed=h({3%|y*>P3)-_4wypGt@0O72e0N;}xh5ryUrm zJ@wiHvs#U&-^aQ)qc_sDULBFV`zdLNg#J-5}8oJa%usImDP z$QeYKvd){ling8cy6>6)fjsRzpdHKWuncqN^Ab+;?O0cVDWj1HmFu3Gq3}z8z;vc| z_5>qwm+N6+sB>EeRkjlQp7sf=G)xCyoPXYnUMzp^T{b`H?w!j-b@P^HKp3N(|Fyk; z-y;sE z(K7sXkqO`{O--Q#Z|S!Us*a_;Oq)X=uULl(>*F9iOIOLA=z<@}6pX|`USAAC#}C*@ zLwQI7LY1uF$8w7a#HtL8S;EBq6Cz_3g=_l(f{Jn|W@&J`a#N*mFqC{68ca?*(iK}N z+i1cuKxlNaxuKt}uXB)=h z8BXI*{HK6Z#YmLz#peKr2Ny=!SfW>n2ZHNW1kRD?DhUIh0paNY%E8H`SE0y_F{dMN zO*tkvs4%e`>D@5dq3HVDFH&l0N}2zL8}YEU@k5W(wh0JcW07g;TBt^B2mFk#Dn3vD z=0fl@qY>-LpMmaf1gUyr4KZ|@=+WqKHzO0%FCTsvk$bcU4x{fd zVQuawGX~~~3?EYIr5gHL&mYfQ&!0D(iGM;ib*8vQ9;|BcJuM}#5xJ)&L_n=a*dudA zHG3x8uza&)9%w1Q=)3M=YX2k$BTV8Nuzo3tpYy_i@6zBPjTs?`#Bx`jI!a?rLJ8kO zJn6eq%eV9UjT6FXZ1yBeQWl>{5?n-kyA8lUevF_BKqA}cMGv}rz9i1g5l9;<|D@qH z8+UW*$6r{Ay!&26i+ETKv@fXG6vom$udaspvc=zPhGTr~S*DHhfsIKu&O8l8R3FHb zkShJpU+(0pFhwg0sj0>Un-__jI%^05v-4Nax(|11>|h=8Ud`0DhAX0u$x* zqwMZ{S5CC53|I(iB!#g6rJ{DO=Jw9s#&LjGBiLE-rp3-U+JHRjW=!MkH3`8zSi&8B z(Wn!pvKdgd7BxAZynzmvw{7BGK7cRl32>!lCw6e9K4L|urEIbIU$7xq7g}kYKQH5S zQ$s}J&@b%r>x_l!Dq4HeRuEw7m`4~CIt)JUY~#2QGIGls21`C;26C^o8*dpUGt)bNBSYd>DIiS z4b&R1P<#;Ib(E-mHQ5E2TlSeXtA_GPH6C4QL`yw0Or{IW%A8>E!?4~$Y9SgU&+ z`gkQkv4;s`s@|2--a*gZn#LrTUyGg!f<=@Z2qY?qe#uc~VcES;^cg2G`v7~fZ9)jp zWEPIAb?Q8GY&YU!d5yZLV6 z>z)%C?wMT5ZC?`aJb#u+>XnEurf48LaZh&`SW!0T5U+thXuc=X14r8y9ZomO7^9ZhV+S52MDGut}dUU`qvaQu;DC3rDY{<^f$S#R^ITN}kjh;ocJ*rt+Wj!y1+~1uS z3h~hWlfP`Pm0oYaP?v&k@rrR2==0jE)uQ;)a8`Jx(Eafr0apsTLRa1rP`WIR&jZgH z8O&n6_gd(ZZuEra{V(E>+**wuj&gH+ZewguPo7nDjvvWywTHH>$>QY$J@u6dx-agJ zIR>1xmx}@?tGva3_qwpY0Lb>7$1O#-3GG z4(!~Lap6yqGzx~u)oYIuw-le+t5&*5^`}!b>68pPy{JZnC#o0!D=U3R7%wt%(j@&K zo7<%98ICwpl1%^nBY~++LO;O_5jR?IV3h|8sF*Xy{TkqL_H*a;m4M8htMJk_lRxxR z1PQ(S!^=-Kcqqq@C3 zy&)AuIar6t=pypfETBgNQ!0m`E;zlmC@uuhxrr&|Q^PrFVYyu+=`(im zhSP3QFUupIBzd|zH$GQ0+giPw+oB8zWnH|{!mz9I7oLBUzcx-{bMTVZXBOdZGdmbD zZ@!QgjvttO$0CboGFl5&^OT70;N>!@fUE`!zcT*QoKN&4e6~-rFRtDy2Hw%XMHj~J zwaJMIDF2?c4ShD4Wf)X?be+=eMe#6)DOUf&HBrZ$JXLqu@Qh3TpCn`bO4yt!*5_On zmJr7BLzxPtJ7LF1ZCJJJRgb6S?c<#G_q+O7%-qASyR!%*ko|3))tyw|=w+nVnrB@A z3wSFbM`yZykEOxBffW-JqilDhj&(7g3Gmp*hHP&5_Gac{m`A(URqd&T#K{lM_)zk%BcQqb9*v}ce} z@o^Z>e64Y171qkk$cIdS$-jkXluv<#=~fov`IA8}kc*R~9v~4e)V1}!y|OJY|GKeu z!n)Y~CRcEUF1V|AF9!HG@n}*@acaaSp(GNoJ`gFr0K3gBC`FLrfA&+;|jWAl^IY!9lR`oMHfi+`wF#m#kh5TPXIGNLMh(e1AG zKvK+$)_K=TylCpeaDI~Vr8~C~ps|B;`YZ&f5BL9K-lL9Fb;e9@BcnvH#PCRFoO=Vr zQGVVf|Jh>gcIGp3Prft)ug_KNx`Hn))g>n`eb#LoaGbX#2m#JcjQI3W$MJT^4b)TO znI=YrOhuE~t+k!}iMQ_qAMKL{k_>kG)zLuV@c7k+G*#Y{O)?Bqv?{pwXVi|-%hNE+ z-p>@`zigkm_fi`W>pzzS*W$D@h%7!+9-WB+pg;B6+Y;cvdM(~#fO(T0r`^?sDN2-6c`$AL zA1GmDx@Bct)KK`J<>v%)pHKZ;`xgY@_e)y4Y7vYIcU;{VSY&|B9Vhl+mqN9se1vn& zj8~CqF^*N8KAmuQTW?Yk)8NDR>Zi&$~RWtd5C+vCh}{MqaW3L z-G!|OJWE|}&?}}QL3a#0C2~H%aCUBcDvRyhstrFPjsP4zcQct#k;y^@57$UgiF^9{ z@25c?U++*0j{N!nM6SJj|@Et=R2iP0$+E8toU`&b89dB1Vx_J^O!DVEo?F)uUiBCGFL7~q{V z$BJZ05{x>!)B<~{Jf@){Qfs)K@qz@B*yGVVP9dO0(wQ&I`P$E4x1iXjV?X(_#mHUl zgHN+=GT*-D$B^8SEh^7KW$Y5#Zg4d=+qJ4L`)4`IChUiIX0sLqvIio=Zws3Z^%`9m z$(~2(`lE}|lqpb$wEWSpO?GbnF~lbli{si8tsLJoF)m_aM<)-P#_oT{?*v|w@&0{` z9_@L^geqIFYm2=Xc92t+MGrSEoc@Wv^G^y^;4fsSNss>8wzqt?^L*o49h|iRfEN?x z{Sd>y3{V_?_E4}@Ti(P^2wTC^1Bl&w)CY?~86UK3I(6l~x4cfs z{%bI87(H-_k=*-5@vXmP+cSf&SW{Z-U?G)Lt9FoRZd4eNu&(;R*jR(eJS|o1gU77eG((qNEduI4n#agm3qSBxIO@yCQd$Xr4xg#fr zGw}?mJpTtOW0pBL_wbO(lCc9KqH<=++qZ(^>L}zzFP~HM~Y6 zy)9)HzQSC?T&^p8+-YD1ii*=TTc{CoeQq2V)k9Q@WnJBuoeWY?cpbdd6|)cvsTuc8 z`Sp0kT@gh7Q4r4@1mdLdLx($}D@V83yqw77LSUp0Th^Y}>(_E~vU&0~zP#&$uLL^m znfYAXJDhzf*<18q+7RM_u3s3?GOrr2n9(!3xkP|Y3>pf;zz7?3@ogF6Ox#T56A9)A9O0DCq71X8l#pW6PJ*V4-kz)@>pAKD9_ExS! z9)(AVen`pgd8VEzy!jBcsjrX~YaZ_#KPmp}1Sy7Ai^B!)MEBmB^^MFt*j(BdS0U^wRB+VQRd z*OKr+Kk4zlSxBQ|y{ms(JecB+%L7c_8qVIf71IU`I=d;J*|gudHI?dk&k((R;McxQ z^9pI7RU-{m!u^yw=On|1lwc{ziq4k#GOsYvxm^W&bt?P2sVSo04dox<6;vyl7UQY2 z8^_#e!$XGKuM3md=dgOCS65Gs0ISPVBA0xJ#|{Z){E*m?`r8lO?wUYJ95v{~)}vR9 zpnlX4!_$g!?5_8cQo`1lHRTNI-Gr6<(pxr`5CwHE|7FC;Xy2LA^j$E#E4~7+R_^Qr z9`1-Rx%s_$u>ck0HN!8+xtOW0Z!dad63rB>dVaa)&|Qn{eP{U!-uyz{nD zlYvd~d4zL#gVR(!JWdP4kZCgzT4fX^yVzlQj9jL!{={#vM5=o6pbJKbZ5RQATN8X- zY{J+)0+(_hx!(3X)AOt8{n2`Hf5?!FP>`33?JdtmkY+8?Qlo)4?rIpDRSLPTj{_!H z?ea*j*;<#vQ{9$A&z|FD`}aF`y~TW4NqQcBWZEP8yT5uyNJC|=Y%x!4f7W0gDc0GJ zkoEd(4aw)6D?elC=xc1xRYJMzemnNpu;gVvo{LbrDSGP&>O*^PG9b|v1yvqdY6Y?i zn9ve~ivK``7a|9``F(lT$l#5)(qTt*woA4pi)&rfAn}X5|dUT=ct4q{(i`qVq_sZYECjd5<6?chaX>h(K&OD*PT!r8Uj5 zv+wQM9)@6!xiz0fE8s@mQhF@8FOcDNZKSF$b0{amR6WN};vcU3FP$CP>tI^gEcJ5m6*4=y` zdxzpq)3|)4L{9o=_21vYRkfkMmCf%z6@TBr5;>_l7bMz3-v74qb*c6I<*+^(;JdGW zDH~)K+@f!RUshcvNJlMFIp61@qz1MVb)u9799@hj{COg=-H{H`^M>h!6OQALh*Aa| zDg<{kE%*)8D+53V0GB0fp^qk#qWX>+y--V}dGO2r>6XLiQq@Eiksqgnusb^3lR1P% z@a`?yNSEtHvV`~f8SFQQp%IP8l4bjaa=He4LVi34>&f=N{c?iwU)t&xc5h(kTwiYy z3UzR@p=+xl`Iy6`LCMvmcikzZae13q8t<7Z_@L4_%QGG#3wH}HraSr3t0Hy;b-RF< z(XN%Kp3}xrUhN>*GC^-9?@uDei2)&s`42So?{_H73%eZ^DXRY(i_9 zM8H|$RSA|lHvN2zPvz4!_|5V98dE<(KHmXzQj*QN1Ge%cjgCm&SoIw~oz)}X*>{n| zC&cwNyF|%#e>lMQXwDddy#GMSaz^rY0rPdlYi?P*x-A>}Vb;7X0tf%zix61xG5~i1 zz&nm^Uqq?l;|z8vOia;kO(-%L+3}-qU3^LGZ;};6VB{&XPwLp7FnnKWPoRJM%O&w< zdf<+97C}@-p`g`dDDvXKhRx4F^b*_)kg_HCQWm;1M**jcJeC_{IkLH=3k>2Q20i?{ z=e)*=%g3w-y?FRI6D7@`G4o2#yGaroHBBP=YF<{J-q@BlsXp~dxwq3 zyor4H{2$&&fd0rOV5oK~W0Arh;N?4kx!r|2Mx8>U_1S5N^zC?YHZi=+@q04!o23i{ z9a{NLUtnlIX_iOU*>1kVL$%IXwuvs@*V5kw@Ki!ix?%28nO zDdQHSY(ruol4vOa9M}FxZZp9*6iNwepHk`Bf~F3oJv?7JyD=tuALL`bqV96RNsUR3 z+XY@tE09gLA5ghoR*b?xh^t_x0tfNfk;WL;B{5foj`z~{K2{{#3RY(Lju}H09l&8Y z(BUY8;i%6*3APF?61OS3+2Cc&)Ce21JiFzQY(8J_{&!zpA>5-Oo|T-Fc~Le5N@a~{ zNR<7e)><;(Bf+Nfvw$bk<>N$gyi@&;LFK4d)_eDJ0E)|t4s=^wL>N1kXcQ1_QC7=N zddPa7<6J_-V^92%KN1jAKo$#&zrWH_ZQRCZA9PoDy+&ui5zFyo;7dn40zV{E2I+2g7#o3&fjOVFuTKf;r(jyn_vvev)X^n zi3ppy8KR_ZJv0TQXN}gU0&(Qzs)sLWIZmOMzW#M2LsLeTY^@K6d|tKXadgmNNqtyP z{H^}8fpG19Ji$l&*s@3Jd&N+FC>)#Igg!+Vy~ zqO{Yz|Hdj@!-Xwenrvv6_DAOmDY0hGJH0vqy_VOf!-XP(W2;vUO%*!cKKe8aE*;6+ zh^Fd8P?O8l>+rUXjn?p%t>iP@59o_iliVB50m7T48|-KSj6f>F)__%i;l62Dv|Be2 zlYr0%NQz>3at&k<`PJ`*)*~1A2=tih@7JFOb$37M;l=r?)8N#x&O5L~TXRcJ!CB}Z z>*8?vRrmYiV*KZ#bV9URT>XP16N8IAyH|koDZAsVk%Dc3>w@yL*MBV^)pve2{%f_A zY3DFS@=GA&!-|&fve6ooqA3x>QJ5U|(iT z{JML;UhsFm9J4**=aj{ELS?D$j}A_gd}mdVA>OhP9Wptu_dP{Md06n^fLzv{Ot=ogp{`j(4$zJ$vt_LUAjh?FA zbcFS1<(RnGJMOUWi;V4IEQzp$ElTef*3L5rnTmhTh3|t1+CQ|92D1us=?NLAgGl%k z8QLlkENX+d{MK4e1ldFll1=B0}$^(?NV# z0a>OkYNX<(7LRczwtYtLk^J^-_*a!O>2tM>$tLDIjLPZa>0WrG8ijHYI>ZE{t%`?X zC`vq>3+Swq>m!Cta?+>l?COzp7xo4oV%S36nCGVm`yY$0IiU$$Z5&f2RO6W-tnP zgy^#_iOrl%^(R55Y5$JNB=OnW3kC7>ZkrH7B~A!ZOkAS4|GugadNVCJWasw9rfx^? z{DrpIUXKDz^H|ikl`n*Napc6PUYY(aN?EG7oM$?v)_hi0I*vDH?>_ik>|2l>tQ!yY zG{oThWxfI(-49k6fzdhQUSq>+;O;vW+5gi3^ekSQ)Ec}J^Y5_s;mOnI=@j1d8*A!u zF0s^c`PD_^a5&hIstN{B;M1QBIksXEt{(Xp%3}2+Vizb!z4u9(EyL-)vZ9!x3wNFf zHVo5tVBGG8C79ZF-4Xt5q`m2%B~oa{!MRuayY}ln`Y%apmlLl3d+B%wU({k6v0J;U zX|-$E`Qaqa+!BaF7hM|Z8uG(~dT5!4qi6XqPW>oJweFboSY4$RYr(5&I(VfX+9yN2 zs{SOf%ea8X0+QdU?b(^iprK-&2{If1AIyRKHm%309GkRb-k!cGf#ak0x-S3ORBl{H zu^;{SP0ZBd_|7X%X~bE|g!Dsvb`UuXU=cO9*m$tMDnH~J>Q9eE^r@yIV zQ;6Cs$UNKJ^ylY$AvyfZE(hFNaFAOi5d%E;KQpJfsZG7*|zj@T@W z;b1rufETz(kj4gHdG1B&bpak;Tap(GtvMd=4GvbfpJeIgmznpwEz8rTLpEv-U~5G? z-;+M$1Q(Pop!mmOGB&?&S=a35>tD8Z!o@Gn&&xY9cDW|$_`Z?DI)lgXB4qLWb|n(a zF_lBh%4FL&GN{l{gxKe`6FR<$oG$C$OP5H)PLPrUvD@>+@@1~oXxhn1oNQMQ)(;$u zAoC5WLa1V6Dn>cV3$sxak0BRS@Jv~wI*xZ|fhqlj7N%K4>ffGxpgQhrA&PCKBEk9% zEp|EP!%8+MQ4S97%~l&ysbnkAo$T>{@5kwVpV%}T8e3;tXB{J@(Z*32vcV-=AfzbC z2&Uf&GV~0g&LClrWx1)P`u`_E$uopbF-QTAJ1#7uP^{-mlvY!WtAn=V`UsP8A(KbF zbIy}Q4{R`LJ8zrgI2Gs`9be z(wMORJ+1E7BPY^uHT1qXm;^r45Dv`0Tb8~+Cq zY_8Z?=6Vg7FwnWl{%V|9pUELk4xlnFV7yY3-n{;9#`lzb`|=U>{}3kx)WmYTjD1Y9 zo?#E+BQPoxffPBbx!)T+(+0C;1~jg*b}Irwxk@~y?kSFXTyBy{oda5XPBdX8URJA? zDZ4pKZB#^4yGG$pnttFOme}6L&Rw!~x5Z8MvZ#tVUwNwYPj9i0>W&rb zw-XjG+ehiyw5?x-5K^EVntgZ3L`d<{1l zWo1l(l-Z63?$rJnZhy-wvuyvW9ANHq# z2CE^P;wE$u){YdrfkNIa{h6X6g?qba>0))QM|<}zGM~G<(v7h?6jR{Z)kUzALz|LI zi13}F1V>ghVR;SKZjkZsm7m?T@aoB%GA5plJk-SE6GocbqUaAL!P09?Y-Bh815w7` zv13bj{wyM7szyJr{7WIIX)DcJb-h7P(Sb1feM71El&CJ-f4f%+*x=&hJ8864l32|5 znD9EtRTntk=Xd_Gx1D)oCQC%(_Q+%(Bz`RLU$)l$=gg6K8`zFrquz@02XQ-w`Z&XS z{t4^#C+^h8tKQ!OOE&EN;zZ35?*}JypPHHHg5|xONO8ev&C$W@us#T3_cj}c>O25# z(AzQM{|O^3@RTU>Xjzewjeib3YSDE6YRE0c4O-G+me!EwKW|P_Z zS$x$;DmzW!wR(}vYjWQ~r^55P;zQ-vrEB9Viv6kN7XxBfkB>zIJ6KHoSP|(ATDcw29z0rrzF2j?a#0?^O z(FbXj)=nd9qLiPYa#yEv`J7Lu_trITl4~eR$ufO^_hj-(wPs3}2#S6i1>r4Zse|Ql zmRObb!Lk~`SP_S{?LKOwPvZ` zp>?(L^0RhpS{%JSk7*T4Og|?QfhQ!7{R~m+3@?Hk1KjK!GGCkq4Xn<0) z=ix+89o+j1+56Nj#9P-q7o=mjWFHT5y?S(2PiBp2Z@>f@cF!U3D>cO9Ldn+F;T<+9 zF>yIZ{rT3qoaoD*14VuB1p6wjDPS3QCwZISqfibH8D&+%mJYD$l*!8@Wzj!cGp7h> zbZLxkBP4`(tUeS=SKWMTA_ZOF>q*;YHU|=P1m{T;c7xGLvxe5zExv1_!)aA7LVnbQ zCs}RLLT3eND!)s-$s?v&g5y`R96b*sF?7Eh!#S_HCel!RHY#O@T5^&CMUoh(J zLe9O8ydGV|;f%=TGn~FRjuM9$#`6;X7?RYYtxXc9Vg1RSq_3`W@c(KR^>lAP`6xTf zEk+dsub;HhKxf_35=i=OB8BJ|Xr_t3!U*P}-s;uCi#1~+ig>xcw_(BRQ4_Tguqk0f$p z4+Q?|F4Semp~})m8d0~!ZAG9BnhI77sNQu`+Y_=Ny$I;87A&^%#-lcCkUmie0qwrV1-W>NwG)LL->*l?@p~rXYv0oDPhLEyq|s$TCZmH! z)0OoAVRL+*9*!$a{)>_rPhPmflSMYgshCar$8W&=U!TZKP%E$({ohdyR+zNN-{5#h zj-DBWVc9C=jmqkI-uEkR9)(YbrTAmck;DYlx*qsNnB3tIHL8=t!7j1nO%Y5M-|G}I z;|#5}p)(8j&WzMGINYW4&W-r1Tt@8b^bITWC${eh7m=jD6~+>%|& zeY&cBIVDo`VdH(KO@dnXn?In}83;>s!06jz%sbTw^8)DBlRC;ehKU~9pU~>+e%v>^ zePY!YTjDaq!9}U9CY*@C=D7xcVkm;jx#UFh)YiO^zd6&cKo>>3X*=azp8~}ve7HX1 z6Ra%~3)o#Ldt@rYmJ0bg+h)#+)3H9IHl!JNtWJ{w!Q>rYMFDQ`U2RW#!slQ3mXI?< z**G=qF=IIw}UerFZ%h;{YRhp)-|GcS*z^c{?z}5qancEVyxX{iY z4ZQQePpKG&5trXI-?Defzh9YtJ@>Dg=&3r#h`J(-6+w#xM5Gw;QEfo;E#U(m^ri3$ z$Let!iWo_wVDd_e&`V}RK@+*X%%|TphvRoscQU$clr1oR{YaUaFis~gP7Vwk{H?fg z)~?}LStN?)p2%2-rIcW*XJETUX(m0iE;|jRP>N%mk@y{suMt|Oi@~NjWdEtN;2*)( z3n<|t)mf-3bMJk0_ZIp1F>3&*Pae*wg5fROcipvK?Ri00K?#L+MXJv$l!W|mx^3Ki zi*oofQR}VI&hT;2CEgK|3TsyZcX}4;^D`uk8e8r0?HT0ylU1jnZCi!>s|AELwy_N6p!V)&=LyAZdk7s3-dNr3EXE~ndo!4!9(vp>Pjry@HGkH(! zyncMHywtU_X?G%@?qEC3F;#oiJgh9v!Kce&X~_;0;53UpzfcXSvMayO?FMW^%SRJ> zjH+x5eEgx3Rhh*5x=E@NJKAfS3bm3tGnpY!^|%?F^Xm_-GBqKUW3#Ry$72 zZ#w3%SmwF&uSN9>kSdyj?sawOWUz2(@scw*r|Xr&odz0`n&5g*&<%rX@i~5QnUSkN z#_NF21s0>&c8vDtmrY%!yzkmKHVxK<58tC@97Yq6q8gA|dw9^-)evmo@T(oS#@2Uw zuowCSY?G0s{gN7Mu^DkfY<}wOu(N?32i^fIHAa6Uuzt(zPBW%$S#o8qR-_%!P?xc( zGvoQ_5kz3I$)_I|V>GcWl%7G=dW_lpxT&s5FPV+=!n#r(!r-broN^~28lePoFHe&t~c zs})r!xwc*m1ZxDV|2ezrOVYLA6KL1}^HYxEi)_%}@wwkzESr?*sl((xcPB#Z;Gkq^{zwW0 zm}UjO7w{#?JUNs5*4{x875(nXOdk=9obYHSzRyDlxcx~x5^woBXV3qzL7j%L$$i&O za=b3rvKN3|V4|dw-DD!%3H;UmwW6{b;CA(N2;a_$?W4lkpbwwT_jq(DMCoe0N-J~x zI?Xr3-#ZZ{dc%;(%Py&mH65WQA)B{F@M5!ei}10w@(ZHMbiO+q8Ubs9ZDcaR;-#N` zGFA=0%$YX!Pst8xrvB_qNlrBV1iH2q%p}fKoOMY7S!gqp5~&k8197L}F`P`;hW`Py zvYs$KwHZHL-WuRt+q50$D3wwwy<@op)$%gK&y?cPkh_7Bg-t%sDW3~~m zQ0soHtL2<}1v=9k5yX$V&FSH#N&sTa^hP%YkiEblvi{r_0(G*_cFWwn_mlh5Og;61 zlsEZN;?LLiP4yQjy#X*4LKoS-Xy||q8ottZX~I~>0jzAO)x(v(`>yeSV=ds*0pE!M zAR8=xH9WFM2#9QU6l?l|wn}L=;#@LlpZ{a&#A|8iK`SGc($6nWAG6U&BbMskDJ2Fk6TKKHZ7wq6boglkVw7PkI4HxSUGgT{u^k|6;C;y&i3fVtUo0MonFWdm#mvxS} zZy57H&|wba5Y9L1h?hBoj`J4{Pr9IWw;29 zL(o7=Pvmp`;1EZQTh_}aI|Gj4;Z`eNGl!eH2eF0_PfI=N0nx`JLTYc4oNVAVsJ7U& zU|5+)&NQlz&S5BP&GQkYYK`vD``6^(=h54^^S_OnA{`UK5-E;MbFxaO5_Bf_Cd*HA z7sFUE;_0WzC2QcU6Xp5kq9&C2(1-i>&`DH3jw=OecO!|lyxC40RQS=uQMP{SNYRO* z>|of6gO;Q;)N!R*b|-Eg5bjh8-P6w0KKp4Y`GP-PkBi8;@_38>j^uPx00TY9uS96f z_LziqwYQaFy@;Yr=ML;V#4PG8t(=3IBNwU15S=VP3g|Cr#7Dnk!>9*JPqye}3*Jnd zHOJa@x-ACO^!>xD%?kd@SZoyKMi4DCGGNCY6#4^y3891%Qy9*ZtFJ3_)C;X#ukxr& zQ&i-m*4VeE)_96XK&{S|h;B&eBkAF&5Bm{L5x@qltF0Xz9FM!|_IKd1lbz>A@7r?x zZ<>2l{gHOSQP}*2>-oLhq&5lmu=)19mq@&p7W8P8KTv1bH32-3+5?HYb-Twc>gl$G zsru(Ovq2`@a$J9lu&3`yJ79}f^FnfA z7;7q5u{U4uco$L|YKM379|E}&l^&(ht&%dGJsl+E!DQ{vgCzBcUR=ZaLy3%mp*XNY zB_6I=(Ri8r2-uek zFX!&jIy|57~^mug{_V(EpFEw~A`B`=Y%=f#UA&Qna{xu~JG6 zm$U_nHAsOHO7P!Z&)$2jHRo^2 zU(Ce*2f~AS+!{ka4NjOY^I&WX5Mcfymy()P#hg=k@h8Hm{rwBgGxujC`wwVC1*XDs zmyL*Fymy5Gk1_Gb&l(%k-6(!DM`YSN_c?Xt`nCuvHxtY0E7!R&pE8L(u}ucCk?kj- zg+@le>_$~TWRR@dSSDMlj)nPIN*fT7Y4T6|ncR|3nze&PPM|@I6I%BvhOF4BkD{07 z&;ktit$rtQc+(B^4F0BRPw11Lhq4~vZxJPAeou4KvFS3x=m9xArmz5(=z{?p2HVhG zHl5W#N1K8dKIZHC_a(lg+3p?V-!(N%Yfbm+5}MW6u=rgo(!%ghSteZtTSm0?&2qAm z1C?vjCVsxgcG23#q_#;~wr$F{zd!-*m|FPY6_}>>Zy=Cm|(x-|`CL=CYk?o%Xz`h?aAJ57!bmr%Lm~2g|baTWht77pt<)r{P7FMG(9%mK;-4 z;Bg(EUVQNwxNAZ_@9ow_+zUY6`Yp~Qu`H#Ii0~MHmBwn*HUkfp;)V@`g`V+#v|8g2 ziVX*v@K`-sJKW#pdwRBJd&W;*&>8E1aPuE@8(cM@TBE9-!)zr?ebg=MABSjDG z4-B+~Ae1F&2c_c@j^0n%4MZpnUT3jq({4RPr42+o{+)WhnDcaB@27bIRFttI*yM@M zrY!3zr%nfjI{O9)7dP0zhKpd-+7@YtKFnjfT=ys6sE^+sReaUuXc`eq6fAN@&3d;M z6`K^68MSUX59HPWKO@~TkYv)B3$z^`PkVVB<=On>`gW#o2G|^9AndD7p5>}` zk3NzgXQrkRkT$$)BLcISJ(vkm`}wO^=s(aZ18@Z1&==UW**q!_n7WqDINb$iuE5Yv zQFlo9jb%;16}Z*X`Dw>G-BQ8?PLz-89AQ+7htN)wYs_3kPkNPN zV{TBkT`(s@0?m?6|K-YZU0RyQ4-fHse(2tn ze@oguuciJT7_VOy%>3KLx3`sPFy@wU#O!wa zJpIsP(rdBY%Y~@}6m2ZML`MGkTF5|>x@fVfnz+jl>sL-{_1+&1#M4IvOy{xs^WKvKrh%& zEv&EU8ZL^v`~15yPchqr;pT1nOzbBAt^$`il`9{j&o1>L@soU=Ay}gXr)i&l9kgh7 z>@mivR+$eeFy0qg`))n(3s5a($Xf**J`Y?O?~wn;!&#kn(f!o^E(j~^Dt~JlD($Da zIz1;sk50inoI!&9Ul7b7bdvT0*8+7K=PxJzmz73*IRQPbfr!opwp|)PfnJPInC0)6 zfDYb#ku(6i@|xk4tPr~J{0YXc0js`T7MmKfY!b3O)%pJBQ^ZLzRVdSIIRYvP0`>+Q zT@;-rCSi{s#Dwl1+VQ!cuFofhnC>JbyhoD&ofJLv4UiJKyBMF!coi(lE+I5bM!Rs$Yb4+0#xw&)-igMk^CE)XA2yM7tF6H`<#Kamj8Z zP_Zj17L4=w0mF4t<7HPz>@L^LO*!ND^2utVr^Bk;=!26#ED5wd=R*k*j~@kM^dU%! z8Yc;ge|N#4TPtV98RCCI4{T%yzFbHD>=kukmW=?|IBkk|e{1tfWWLTC$owo6ocR_; zCr7RDen6cyS)DZt^mAdT_Yr2mh4h{=9sCd~WKYdOxn-GfN~TF~72X_%X?vXrJ6vo4 zoyMdk`m*QUDmiXb!>oalZ3R9Njtaa|H#*6qHURaq^L4%Q+1x4~YWXRo=0iI&EA))Zu1RK z5}zcE#IQO(sO0Q_p$JkU2BCn1OBa)gCV9OKqxJF^AF$z{WheaG zw_G|*8InaD(KJHexBmHRvktjxpQ+6=M4iqAug8% zlfrlRmCUmMlkvx#Li~z#b0B)$|OMv$;eGGa1 zv@dd4re{M~h(ia_A2;rt-WAyRRXCm%jxJn-4mNIHAz-$Bn1-?h%$qATcx_xZkN#M8LATU0Isg8M zr_rG8mAYUUCFRk4RfWaOQlJCm>9&a*1JrHzVMiHE2bwIL^Zu@P$+mnbc8aZKINpTo z0TVBR>!MhTC-G+!J?Luu!YDz6VJPt77$*hB5DAi)S`(d2ui9FWSTd9dby3L3-a%1W@E(8-JtNwyM%_ zd*A<)g)ymb?i+h@6;nG?;?7&#r7DgQUJ62&uP9Zx+I@^OT8+xZM)mHSmrLC9qy2;3 zGWf*jC&NF{!@FeCN!y2rKK z_SIbmOr=bpyk^H*>jjD-b|+F7SmZx#SI^M4?H zG=5*Oveph`ZMVO-i_EXEs}xvN!S=f5dwthu$uu(Uy1Dq!*iVloYvF`JGJ^tvD@!ss7%aOj;>#hf9z< z8?=yQ?9<{3sc&f-S)SCH_Mbo-XKNp9C#dz0trB9Zl{Id4Fb3ABo|>K+z#CR$ zZd7LDe0_E6Eqv=+B+=g5=5ZUw75RtXdh_#;Bzu)E+H+X#A)83AxCPuh{}B)Z(ep9%iUO!KXy zM==a#*M;=*pg(TYcB}a8OsNgu+#b{Ca;HPjyjFb%-0)0RQgrlMGGF1nvb&q(Arf{M z#9dY8`oA989?8KKlZDEycVT#b3 z{ZJ&C^YqNFCMNvIPzk=pOEX&b+?9IEC563&l0}_zeR9jcGiS?2IaNgJJaLL`=#j|t z#$oPoU9GgYzIarNrZa&oy+Xj0ahvU)PPfWM!hH32o6o|L>985%aKZ4ytR>&Z4&y0y zM&&As$p^A?6ZDB)>hAkT+ocwkyl4bp+b{(_^sCYqUr);jOvX<*g?IV$_?Zcl0c=6{ z7PCtK!ExiCd?!UH*7R0V3%N}PlZsO1!?Ht@^-nJeQ*L!{WfmkFHK@#7Cw+DG_l#3Z zf7)fZr>j-}wcVv(2KEVdh!BMK+*)Vr)XqH9(n zAKe#Px92jEhmT1|7Iv9$X4WzSyEf`MzdNZnW%5nHvY z&;rmBspWi|W{A|-q?6-J7DDdy8RC8#caV?e+-3NF^ltwaC<=ENLXQ|1xDK2G* zlIa8o+Ai3-Z;`jTSh`_SM2eT;x5W|epK>(Fgc$l2wU)dnnHpv@84kjuPNN8{TKRJv z^An&8S+(9A{mX)@r+0czGK1QXN=e=MCOt?QtaDeyiRwAHq8RRC3}C~=(f*V3d~P@Q z*T0Cbx;7H$+n$<3q6l1B7^i(}u@5PL*?#9)Hh@19f+h213iq4%A$x@QE>bM1O%iLN z)4vDHAJ=%x6L|`lmG}#~6?VFVJoW-9sFG%Zn>^gwH0E9cD&DVHzJS%q8fhnS8L%*HijeCJzMH=_FEa)rSGyn7Bnuty4@8RJeFS;_Sc!;o?MaE zdxLMB%Q$-Tk+A5_&fq|hL(*U(98+~w)`liN?9?6DR0X8{oXan=MK$?7iY&|D)=6Ir zk^hRU-)i_7`jwAuR!+MTvm6*5Am54tZcPxf@C>(N)rv|N3tYsOmCpP)cat7=bw7gQ zmrcX_;?M^{gaVA zj@6xHeb7+fT}ro3uSh*64uV#Dy`=icT*Pjs8Zm_6`=Ool3fG>wB3g#QlsG<_iDvq< z$ggj*5s`r|9y@F#)@^8?VDC+-QD)g3*%H|(C#H_(&ekYEbbmeY1Oob}u|faB+;m** zN6jT4tn2ob2o#DYtQ7BS(yEcMZrZ3NFPZ@wUbT9sy=xajvv1Q zC|r?3cgdF|cRu=A$D?3kuiwvB6v+#qEGBdBY)Ys1KRno_PZStpCkI!i}wc=+W-(Va0K3{rRkKtk*J}Jii ztT$~t2%jd_5Bl4MCfGR-Q{{L1OrJIVjVIes>9R-HD5=KHYfK{OYGFicNQYokp7U*p zd_^xUR(}rIMTOv&b1j12WIq~gxE~~2Y=p6Yl+tmZ(<|O73WB#+smftekbMy*SB)+= z)v~W`y0q=>I+BlWw3#H<`}4bJ5|G+J7-!0k&sTnQ*m)EmdcUn4y7vZ^5qahngHsim zPG}pc%h$b6SfsbLGs^qS-d=<;IU8pktiCeE%rR7>yHgg^?Y$ew3RN;j9Rw*`R%%xR z!R-?T#hq)G7V?YS5uTP+cS&~CWWRggQA`(Ezz-BLA#%WJ7THP(_1D%&c&IeQ6$%X0++KM{5j3p;`$*K;(f^AJO*9&s zC6q^xlv1?aRDOu4#1!pqMc7tZ7<%s*;T*jX9q!URylbjZ{|_Xo`d1`9Ns$un{?*6qq;3?40TgKVpjq9TxuIJ6_rx4QD4~nUtd|EI3h(RJ9|p@%XX7Zw9%;|HjNw}!D;nw7remW=y!Evxvly}YQr2WOWx9M;Vdy8$UxTf-%e2<)rj zGO)HMKdk&OA^KONyQc?;ApY%)KrO%n76*>rjZZV^r~4}-s*c`ZifTSDOS|^~ir{^~ z><;9idE+M%?&00YWU}gGjOawWi7YO*DH^)#+LnJ9u3nW8!vHN%m~;K*^My zW|t%M8cft!m9*l9zZp*oo$_efFSX$1DVl|4uhd$93^EX=tPHE4HbYInk zUh;Qrhxd`&VmwNZDA|0B(V|xcUSel0Dh?;RyC!DugCB|_qaV}D+rFTC=&nD;n@Euz zXm=iL;WKQsmWKrFtO>PwLyF2`bUjmW%ZD@{>yl@FA@ib|Xo3s#|_Pg+#_f_RXiuj&=JP(`*5sKTZOEoK3BAB2L*Nxd~w0QM*FMVVCqBTyUCiR+RC7s5H zlLzHvzl-GaN!@U<;H5yP8X?OWkdfTiZa&sRlDJRzc#6eC!>rkmnmlffbZu_)#gwJ@ z_V&qTeRsKa-Bf;Zk*c(q=mYpYPc}uMZLQT*xl`6&(8J@F&yu`DAk{f4auCkf=mHm# zE706&b)bD8;gLsA>UGv4#NWrm&N#IGZqoUr&v!4J@x3z2cGUSsEJ*pa7Uq1{jmBAS zi>ejl=U;+-vXIOq!=myO8Q6HTllp_J%d%xAk2IVqgm7U}ltsAMjMrijh>0ds8#R&G zgkD=Nc5CexuZy-em2K#kk@3G(z0YBF4Vak@ct5X1k+!)KodRFE8oRZCUQNz$AWBe1 z5jk8Na&+;x7F!;t2ikc+!S=bU_VAu*UaZB?|Ym!YVrA{vwau8P&dWuY~H9MNIxYB9q(gK(3kx_)cN53Bh=Six}|QlGB5_ROZgwj ze&S>Jrg6aUHzTyQIIr4){98QJNT?CAW&&n|7KcN8M%cN~1i{idEJn-HQ#7wS$?YvG z&UTZxcJ~~!_5}^IPW5>?YX+!&zdiH2j>H<2Ky~%9-z>L~_=_7w;GBsS69%P(F{uC{ zuLQh_1Ts6!5iu}p2ehH8$SO=}xvrZ`HatsZsWVU5(sB7ijyS{fw@gLWXT7f_H()1E z%>U^T%mFAz1mrt?`e(ESqCZ4FKllN!^TP*~@gUs#I?B6R7!~r)XCRk-<*zmK#EY)E zZo@(xnc>c^yJY|82$J?sz7pM%KbWO1dO@5kJ`U)Gev5?QLbQKbw1`+Uk=?Db4`qjg z6NbZq3TNN<9~UgA_XBi2S2!M>5T^X{Ru^jVALz*<^)+%P^lTM2nK)Ks{qIvm+*N(D zu$@Tsx|wp=bHcD-TAb6zaJKG8w0aHN%wbP7!d}ROaAsd04@gL9!YLNJzx8ZNn6_(?fSk*Mm^s=<5v2XGcVG-O^DS%uZ#*qG^gPP zf#D`M#+RKYO@1EI4A-Umk9*&nBZ?cJ$QtK%VR+e*y<5C(gLzveQ@?SCMA zFlUSJqP|4@)l#AmO|oY5Xz-5>KaW%6{S|Oi8GK52@S2(JI)bY=dLJq7uqej+d6Bov zn7B>n+~>Q%i+qs+xFF~e2*--FZJRcL2Ga%4#R(l^_K9iEqn5t9QHxU6OSmg4m44h@ z!!|xtnX%oaBe-7R*?cbcX$aThY8=g&f0|=^S9K#hrWw{plXF6kVwF z9XHHGAjr^sb?(@h%=I5OE8`+3`r>nG zQQL9KJ|d=yu2l|@Dl?4ET+~7hz25SZTMbT`pD|rkVX>6NLrhxi8N0gufHnfF)7iN6 zf3-kapM1Z#MN2=@ZY}uGG2M?5=GE<%tQuMSWn=-m6hiykS}i1;Mj#Dktu6jNQW*{n?}8 zIl+_$K)e`Fot9?USNPUjx}=*j$Wg6Z>Uwq;%SkjZJPEg7Jz^0_e%s>BkVhbLU!Zr2ee8Qoi@5qMCta1)*g#Zm}tz{-M;{M+@@-GGLfh+eHAAQ`3nl zRJ`S!YSqXIQu?f0nSVTxj3yUx%f&1G_NIRIAh;wJv{+!+MN41;ons+uRI?0fJid_3O6Q=FMeBvJAg+` zD6^C05Z22L485#+!#`l^b|zvbYMx&kc!jK3HRtXl&sR@Y2KcpGPDx!{!^<_MeemrUzrB9ecLrwn;&s1aW@=7$ykn ze0L^PnP~@1eH=i8a*JMhnf(TJmZzBQVpcQ9;T`4W&`81iBeuRVpW;GDmDTSmZpR-N ze$NVd0M}~{)lHO7pB!T2-_CnH)}?Bzz}qAXq@VI;q0VWcO~coDG=LgV6^@*)tHkhV z&9{)ro&4Ta`S8w%uQ>dQg#gsZjrd5_#CtFe({ac3GYz`u273OVgR)k_{`&dbK6h}; z($goSje+ZOKPF?1h6?UHR#DHVU_$2w%YfHn2D7eXdzqa*fW|ESxc}=HDEbyDHfarF zCO#ne%AwJ}a#fw3bjR0ef;0~=VB$+{3HrnNE=7!tfy)%ZPy=vOI|twn&6{bIhecXW zKa0D))>}%=qy#;&r+XmCmUkMsYiR%u%2hxOsd@uuG^{~^&EXf zi{#G&k)mkuDMKMNVL)^T(@n?sbx$8Hv)m?adI*uyCf!%!iyHktLbRJC5GcZxL_TWo zIFb8JBiH`kYc&UC5WdSXBGDF);y$>g>uuEq+TB)!GEOGnk>& z`++QAg8Q*Ncsu}R`|*syE8T?5`Q`KLcvto5k#Bn{2}5cT7U^~6GrNH#E*Z=OG4JPp z)rV_`GwpORNj^y~u5_;wP|*Au{?_Oj>=rG2Re-{Bu&a`)Y~}gey^X$WA?VR?PH)sR znRkr%rjfMcKEqw=!MH&}47!3C?ZCF_s?F~ofqP5Mq9DyG)MqXRY_jT~l6ARh)6Ez6 zXcVj{iFq9q(C37hu93hd@gcRS14>4fCBpOWcybyfX=kUC(mJnG%~2%L>hNq@OI$|Mbt&TR?OW{^Js8|_ zm|}OfB}So2AiU1rQ|3Cn#WeXqdub!I<0oFG=z;B6d*rVKN#4>PqyB3uYm6}b&j7a} zX{UczaZW6Gdx{sxk2_diAitN0Gm_l0G9`yULFiw7y)mJuN?_ zOZ8|lZ%pPPDp@W1vM;BUJb~OI|loUWPS{6I;+GMOE>2TxGZA(5nmM848%NUD% zK&+QS&$sjf7w$Dfj(v8Qsto2&;fVFxru)tQsG%!s`TBM9t>A(fv2$tJuKw{?YbuJ$u$TM*H|#6l=bw zZKRH=-Mh?J`mE#tn|KJ_7cvv0%J} z>Cx_xlT+G&98}((NFVVDzYWXQZYxv-ICr8}9 zJnR)Fst5|!NA)Jhre{Io0kHX6F$vu+9hC=-mDw1#&{)f}WVW&Z50hQ5X3w7zwt-Ee#Fx&Jkw3#BClz3+5jx|Mg!YGbC!I%XYZWM z@g>xDsB>x{Wr%~^JB8Ts`kjqF<)P2x?mA~rkx|J9wet;*MLR(hB`|;VOg{&SOpTO2 z+9yVOn*x0F)CQsSue<&Squ7=0Md6vf^`!d7xKuLE&t6$*=<|fpKD=jN!iqB_pcBwG znnw=$&5-AmtJ5C0I~t?P;p{3Wpjgg};CQ%;qZ&YhiuH^xJLv<56u zS>VT&quf@8JX4M8xI$Enpj-MXXR!VKbmy(7PP)x&BE$#c;Kx3$0{J7JU`8wtrp^x) zXt{C%Q>YRjIS*e!>FmyrVdrY0r?i5dh+HXYzcm^Q8DZnbJ7H16OQ z{ZcRW)^=Fd{sn%*%f_CM=)0y;b$zRN)j8KGp$9&lm8U93gK>eTca_Q<4|{4{WWVT! zo9z23G*b{eQ*d==Z8>ozZrDKd@t&d6&5F#%H07GY1wo?N$LN`e+CZoOKrt4)%$r|t zfY68x0HN+9I3*a(^gi>2gUFm@(2j${x6A?gI%q8ru#ShN*)t+s#Q@z%_*MPk7Z1|~ z{E)k3Yf0_fMvF1}<=~Yj9Sy9Mjf;cYuo@9eV?mXnEk^q81Keam+#8}ajEJlCb}_Kj zui;K7Dln#;k+}V6De#YAe0cYh>RXb)7Tq|k8d3_i=%Tn3pZz{!W42?tCDHaQgyK}QS>XpU2BQ`5lajcqY<*da^h+g3_Y zG&$WH4;zKb-=Zj`0p_|Pqpty6O&Q4h94C)TXTS=_?<8FsLOG*k_6%1gC7AV_HW`kx zucQ83oW+2-Uj8OjV6-aH(KYIbfj<3SDjW92CflRjiVg9wzQ~RqJtlksS9-H!_Z_5n zN$~({Ft5t(-*qcAGenVRJ_44HcF@zYbP~YWq~R< zM9I>i@`zb}rKl?vG&yUvW>Bib^I|+)woRNhN+=VI>qrm-BVNJU-m2YC=8~X4M^x5D zbu$org~<4W2Lm|2@8jJvPbsI%J)w`mWdBH2b}0N7_T?Jxwt5b~{z6Kz+a*Pw?SU7F zHe9vY5PF(xArz;x_i4_LtmR4+yI`1>tuzzN)O&3_j4bO(iesUpI!a?1@K$ znc^FYr`+sOr(R?l&2g^hMxD%IQ^SKJ$&VWy;!NbD4QYt%Ui}A>5>GGD%JbmGN$Ia6 zyUSK~$cJVO=P`56%k(I{$rWds;2C!CN^UG${kXTGnKFX;`RsC&CB9M}w7H`8K|JDS zIR!%Oq3Y4`N0=Yb!zW>LR)wRkrNWUUAF`Osz5w zccgS{*&B5pCnIP>7;$AkY2f22nhI(3-D~d);X}OF@$+T%^?SonrYhl*fdGg04is&u z)b`YF3>P^q4C!F(zah)4P|qZYK8$)0)d{1GBD?8O@T+i)TE1?z6GF5#C;zDPakxR6 z21V}jLj)6%yh$peL48$hj@53Kpc3PT4~}=B`K-o z9t;tKj<7PQWWpU6 zj|tLf&<@8y7JKOJhr^pmMVYV636aVyemq-zog$3}PQH$@zasd?Z3@$O(zKbl)WKeL z#At!R^QZv16|V#~fhg%d0^kga-WTP05>KV$l`gzy#+xklj|w)+*xmHqx91tc z?G%5PZ^;x08iMCMpV@U;SDEU~Bt5z@JRv+}&G2w$L~!b)vmN~w0L!R{HA>CPB_Ge^a`8_VjIc)iEjgLAd{+)5YAzjP=MdwlD8JBzT6E) zEkEf(nPfv`iz=|Hiw?prv=Rl$rVD%nvb7HyC@J54+#yVuQs>Z^QT|-7FFnuuc%)=Y zpHZkXI9Xo>#CF`@_n|NHo?*HB9a>3$p{2^HY!Rj})>bmmUfx%qzP##RyV#0{lCF?D z=h^6(QI7rFsT(B25mmo-45oBFJwLH0@^nI4tK{8EQmWfar4z5jOXY0|jmQsaWOy8^ z@?iN!)HncOcycX!z!;%43b@r0b$o zK}*P6*M>5vlxb%kpp4Z{ZA&_&G$^wgZ!S8;T;qAxbo*&bCNMk@Kpk)Gc_ADf@Jh0ezWK0~#pxRw0A z@o&v2v#edMfpAlegw_$uAJ241gF5MZfGB6(rln?x=8EzBIS-Ac&Dygjt^cp72#m&8 z^igf$XCmhUzA}a;Oc1YA$z|EBql;HxA<=yJ*-ZG^EN?yytMhkP?asiD6G9(~Ghii_ zB0`Iol{HG70JXx^OOF!kmiq!XyA=bsjwfr&+8)-cE?#<@3ve{QjRD~vRwL^#7m9iC3vzrxfa{I5Xpg*FzD^2|#X(;0 ze*c2NK3y@2-9xqZc@$e%usmsQ?vVZU)Y@A8YxM&4+Q8j>nu*?0xFfFGfEp7_%IQ`e z+GVy_TPq!hJDlEWl7rmze9@dtrevJFVU-Zq&(Bor{M{eUK4dy`Gy1jL9OW>gN{Vs|?sib=``T^kr<%tW z-{I>0=#nma+9mnw^%&>-VvS$bum4qsEoBgg%YxSKs=EONt_wVuv1PG^E)0nli>unS z)Tt33wRI`ikY17Geqh4bO5nr@dG+wQhs}D4^RnVqHl+M8BmE{m&zmuwq)Xq#tVHXF zoj31e)%<1gkY0AjE!>dfTg68XeLWtcR~3F-Sr=DE=LW)`R)5pJd*fc2k7MIgi6vRY z;#OD#ep&)=VKAxn43Cj7QVBJxu~;l1wq*fZ_LTF@XB5bYe+s$^QD;&n22{*zPjA-E zFa{o#>xOiLM*)0jvOoGXt^`xd;%qv8NMb?NXhjn@_@Ao#1smeIZsXlFMS{>4%Qx+z zgR%_Th+jquJ?$?_X7?f~g_7>;$GV(EPt_uFAGtI8`9bA=-&DMK zQ1k1XQ1Q-NLn?jK+eyHWbtQz#qk_u85&wZsGmxTB_p}yjWvp2SnZuAh$!ny8=3=MZ zZT>$U1f!spz6k!5(zB0_+s)*CVlCn!Ep8E=adkthHTUz<>rTtoLc8068CO5fe-PKZ z_6z-P3UTNDXg9yuOOJgs4|@wNFX=p*-<@qS9~uo6uLrL`hp+4Bjw{%u3%+f~DT}t3 z($CzUG!?jeV~eA%a@Om2SJsX1fCQ5t_0e>5d3qzoBNJIH?UuYk%4KMH(F3eRpx-zxz$}=wqs~eoK0D_u=0hL4P$S({bo2SQ^Mn20&ffh{>j}&8 zf0|1`24FuF+eW~|VhN}f_`&e<@|WK1N^56NYZ6h#Ly@}tEA4nwu@Ylf0yNA@t^ZLiDcz5BUH%q)kPtG_sXK^{cc|rg8`Z& zl4CfRWl;>U&Ta;)A-U(0JiUsFeG=u)&h~aZI5*n=u~Enrp|{m?$Mbf@pdunhI`#m?Lr!_}Rw^JdMMo%%ft9-Z&;bxZDYcR#bD&mnp zp?3l$%x_QzIpY3MWpc{p#{5H?%TPpqX=(0+)K*kDUO1|<>x+ui6*u%|P3^aT_?-MC z=`{1JQV5=ZE#I-#=(ZL z$VhhVBz_|3r6e5q2{=pcInW2g27L_T@R;m8(oJX4Qn3bt1QB?%sq8}|5&4GSZFqad zQ}pEMyuZdn_p^ZwKJaZuM+?5M>Cd+$&;*gEVF$5ibR4gNf3M7m7lAWLrPojxl+>3# zp3hIlRr9-#DA2|KJqP~g;k8K$^z-tT8*$CDjd}XfzCnz?lIKZ0bZ++>q868kXpnx> z`XE+SZlLP8k3#&f3a&XyEnM{PXkVTs8dAA7AX?tg8855J`ym+N`VHu0Q_j~(K3os( z6%Ovdp*9Mhhh9JX27A7^Fibr~GR&Ul8pobt$D;IfaJc*58_3<|di<}A82a6ofdD`= z$llAm?Z{4R5Xb>_eoYYTrSMa@av+%22Q8iK@R^v?Law z&P(Bc^*5U~2v+BLD+|-X2tyuLpaMtOVea4o56>Ngb|8Uxv1mK0{#W)%yjF8q%@SQS z>B#BwOt?&4OkXoN)Qf^)^Dv7(Y^Ucr;~7Ed~|l< z0f~R1T52+n#b)7P;yM7F>7V9~8z4rfTrdYd=oUsxLi~odDXovFS`LO#(F?gG>anuWUACve9KOrGmV&%Dy(A zhpI}=%fzX{sr7eOMNNin7jk71o^^I~0R%^pj{~Jn09+*X+@0I=KaePg&s44;s^)wU z9CKAFPU{>%2Y~q!n4B#*qD8$r3L57iw#l1(O?rib+YZUv9{babQhhn&t_cpSfy^i8 zGHMSkv>n`heL+i?$Jy5g>guq`j-HsYPOajQAhb^Jn7=-GXSca&(oj@48e&kV^KI)qJ%wO#!s1|0+up z^U?9k=3+WRx>9w4Ep@(YKss5>p}H$R~M7S!@Lycaf5iGy0$H&h-$7inh8j9F^}5m^%Hd;bC+c zncmKPsvV-27Jb6W{^(X1Ym9DY$H#yR^>=>f&%0i(6Pl>V8MNC$dndzp|J9}5W$Jy) znf*bnX*`}O*>S1HfO)-Vd>-$1E&|g$fX8{<$CWu{mE^>}Uv~mYPLxYF%9;Y=UC!eC@^v0H@y66+JP49A7;xMPUJ^EzLe$WJ$mwSQv(;xzgB52+2q>XF}(zVF1 zz_3!gEbgVUC#wjvi@4nQKAeUA*yk1RMF%;e@IN@(B7!VsMv%{)YUu|hmXhyY|{z!RWD`90iq89S$e!7l>^|N{fAzR(>#4fd^yXH1CdUPnUky>|>g+E9&8Lb;59fnY{mZc z>c)wCc~MmtJKY=l_v)ame|b9z5xoqUnU{-LHQ*2+L;!(`Db_13*|;@_;czoQlBrim zXCyI7A@o+hQX?$m?sN4*NWI!W$li$ZLk?Q@mEBjPbx?#JU)LN=i-pFPuQAoUsI`@c z{#8Me7Qda3j)|0hgxMYNdJUeF!A$0C7nJqOM0Yg=+nYP15G+-XMmMvz?6{DLpS?Km znP_n$@A1%XVUZbwTM}6}YkJd3yDhhN+Ug2KpSm1$lwlXr{kCU+Y$*J0pIWYB-B5Kg z-Qawy-&@pkUe;jsMcBI{CT}AOxSx+_sj|z}04=1!Ftz-m*@an(JDmXfd;)nL`gevE znm5Y+5WO8+2eU@j5pG$UYq;<}a*?f|ZLQyUw8$>vU*z`97EvhwllWQWPxK|Lg?BOY z7c*@a($9|=l3T|ZsYIY7{XMdKv0lRxJy^42pLhTPIqMDcuDa`!5?@b z{T$4g5+uao>J2)lw+yv)b3MpGA#;4EIDh*zepvi6=FypJ7E4rq+ZJzYBF`vyWa`i) zp_i+~aR4&_Ae`wBAY6v&BmH#_cG(tPAgX1)g^!n7{C;H)>Pq1$Wr;NKxbkS5BIw=( z;T$Y)NzY+j&;~m-BWYgtE`bc2aBmlB2-#F|A1dK!XjobdcW6(|yI)zipxYh=@cykyhB5*;J3>~5b2(=x>lp(ZWHhh-Xl76v@Q{7Q{{R*Zbs+d8H+PS} z0P`rj>$;~Ar^E!>Y&V_cty+-YIHbj`V`pTq4ko8xGp@D$AHv=4;y-6p;fJh4vy7UeL3Q8|hBfa-tq!T361VuUtAVdg!_xxsOc4p_lGy8&< zkQtJk^EuCR-`53k^+PujSN%Uj)XKHJW>b1?svp0*I_HW<(Qus!YU(@oqi(V>HiB!#R@ZzdO5a#NqCe`gGYW7OD;tsat6^V2e#q;6YJ@th zA9>Q5<7KoL8mp50UblaS3ZI&KexLX{i@G^ld|~yvD*E=(t{{^9Q{$cYx1shzy|M-BbSc;NdiNGIdf2Fimglp@WOy1#zPKIF72&a+u4+ zi_V5-nhDBXN(DC_KjJ`W&@xBuaSxl5*EEug2gj9(R^i(MQfcf^NrM*l(sqDs%a-y! z={SoZMF7v z6?V0${h>1?=k46`L?OiTMTlu8!i_FC!Dv3?Ds?>a+D>_}uhCWBLy?)N`-X zbxTM5pp)}V1*uHS$%$M zZ1=}B2;19N`)pRdLebk`BiXVyzX`(*?}wJh9{Ri#{11Lt$?a%0mhw5j6= zG9|mFGXHv7ySpQTO*{%BUY+R5dQC&xWgQ0ili9gyuyz)$i#Hr#DZ63b#j_?Tzj0E? zPJ6Q>NogQFaW?za8mD0(=){u-FFKfiTUmcI{~nBgM8VQ7qSLCXJJx5-cGX?l?SuK6 zjaU}__)02wJz3U+&Ygwv($}|tt}kx(!~{x)^S412S%nrPR)UYJf*<6a;JTbYce@Y^ zQ}lmBKTRY*@kA+&Tx#Xl!dR?S*6V`NDRfr*id|(X_9}!dc{|tEXx(yi+Q~O}FF;z` zD8C4zkp`IduqAU!BRkY{AaE$Fqr^IKD9B#%2Yq1DxFLTbX(|kGrm8iX^{=S{XK;W} zdmg>S#f48Qbh}VsbB%5MOu{TSt8pSg4*=7{zW2pDJO4^${60{Qe~hML*26Y`#jtDS zT$wM4L5~o=HJX!4EkQGnsQKU1Fey1&^EpMCFu>J;zqT?FgeK!_!%4<@ia%G4ERIUY zJSwHE5||uu?sSEqw?#@SC|Z-6{%jDdiUN+q{yZ|gJx*xYlNdi>I4>?61oj+N^k@)x zSRGVdJ94y^>jBRay+6Im;}WKF{r?Iq@m|T{wKcKAaUn8pmZ}-{C7P~Vw{{sb>z^ur zKHC?~>^0%OAMhLGL-LSQv>E3*l&ivSuF5^rxS!7qL;Mym*^TmYuU4nCc`>N%5k|Km zwccknp-Z-6>&qO`ElyCy+4gL8iQdp2GZ|u-BA~8)IM4d~_OTk#IKXbDJEvsDU{=(0l50o+0*3MT1T9@UHNn8NimM zM(aD+F<2;S0#v7*aT{qW)}I~}-uw^fnv?bGokga<+=iwb>)x2lCgeSYriP$uMCmE}ipR8*x6lp)r>iQQIy(OK{Cno1eRv zf<>&g2sWJ@wJf<`JQ4~z?_%#+eDt=yO$en2Xvib|-NXqaX%I`&c$e0udBT&L-F^8w zAbF^~O*d{Tnm#)sG$x?_y3ATXFF2tOP_5b#2`*&OPWx7@H(#yU8Go*o^jHx{kv9GH zP0X*LpXZ;ki8_cl^E&@V2pl4Vbxw|UZf(H%$5hu;|NTMzI&mP>`BB^xX|2HG)aT=+ zX(J+&qHQ?WL?6RjZgcMIJPU`7UsX8yPHXKv{&7Z>xG8ot&{W1#Nb!JlhrHG3yD8mz z=>B|Pq`U~>#(8A1Ur7$JDT$e#TkM6$iVElxj7HhykJ|b;vJcQj+FLy_wxsx6Ou}cl z=9a#rR&#gy-e2_;gLLyqJ*sLRk|>kUso&Xu-d{fsSLf&qrSrVuB)q~Y42II-pIOXy zbKp}9<`1Il#GdM&0kx>&KkHUPPSNX{t=5l8hK>GJvDl{+H6EHyn9qwhu~Uo!Q`Jvd zFp0xb3%)FQRx>k_=$B+Xkr5&j_uo7LMfQ<)!Iwg@dIOebBZq2zNbH&wo_O%`PDRZI z>?wO0o5n@flBscnT(@7P;zl}7f-g0(olaU^K133dgBUR+w+7JXwO^q%6ws%0e+io3 ztecv%8Z6cZeCnQw6gN&ylb7KaiZ}TUSF`J?zu+*{}-9a{0@PO$nZHH{2;2SY%6$EyM_q zc;2Sa9-Oc?bt>0{`kFr_lm7JS=Dx4Q6M*TXKgll5NnMPg$M~pGb zC9{mNTT0AnZ77Q71(w$w_le{Gvi_g)>HD|t|7EvmJnK&0X0C&M*neM7%$k@OLpAU5 zc=`ok6sJ}8uL9b^>vwV45d`iEJYdD5X>aZ7Sdje_$Mqj*swrpVnn>V{#|H?%5^a;6 z2p^b5Iv&Y=M_HjHWF~2|OI4}E4m4dbhM`Cyt(gZ?byb2rYdTnGanSXIl8XF zg${<&`vi3$Nb&nm=R72t2NmTPvoMc%UClkVcuE)4B;<9f&4lfr{qV^rh2Le$E?UMH zo2GA>;>wzwDKE1sLV40PU6RcE$hZX_R_t;-d7ajJ(q6O;!pQ^=_M<%Hz|}@FMr(iCH^9QD?|{^4_JhP*v);@ zDh{yPoL_>;oZukyq@!Evg&~cN$9EEC+>+(=pyqS$4@h)>|6#*3aep zolz?sO3M*RYWI103vC%e2{TmeYfp<%on1{3a4$DJKtKqWufG$Qd zs{0N;1*2Dmpu^AG%p4*%EEX-e%pLOp93DAe^}7czJF?_#2AvbQAO-j|oc#L9hBemz zL(Mi$JF&DeXB7qBW1~{lQfEX6t967??X9qOju`pzZ!SH?(qp32&}+o~p%lt`VE;`7 z`_83)^H;94ngio+VzdG-R*x4x)utX!@k95hr($6R)X(r4*z5sr#Z>^jf1A&*hr(_{`%Be?bozPt0`;znNuKT%E2k4;EKFE7>~oL z_2)6+N3fs&+W1Y4i*uW{<-X3*zD9oKxD1}8QJF}|x*cF+Z27bx<8J{aH8oyFV@{Tx z-7wLP+_O`&(iYX<-V-mUWaUX?(KUYiA1(iy7%lVd8No)QieCqgk=wTX-&4-bf!P{2 z4V(*~jd)V*mX)oTP2l4aoRyH24T{BRh4S5<6oKXv6J?$^IKspx|6W-CpG_ggUusQA zgsbb70$gXVq}A@w#(N+zFT2!S_y^$Z7XMPkL8B!-r!$x+5)pL9Kr{j~Ja@|`P&_fFY#-|3k zMmsuXsWSK3_2AUEsj4e_df!}9AOTS5`xQ$K2S$@f$yrrq;Jra4%G+VH+}OCIn*O$N zY2=h9eR&G65E$YYi7|co<0D);9Y!kKe$lT6!i#FOA&=zrfFZ?5d9k%Vh8agS`BFVn z;9rBjsOWGTT5yf!=9q!#PyVgiU)RNO1(l6KNjgo8xzDx1seZx$c6Saef05wHn`muo z@qF0KpWUV~gSPMuWl*-gR73DC^x^x*7rl0a|d(G>w_Hv#QR6S4e<}qW@)BFnjZF# zvijAffGO8=xAMbmdAZ0I8#z7p^*XUNe?NSOC{9&v1v{YRo_>%`x77V3@Zpab9Df~% z36lj1XOSq?a9lrk48=DHJzTyUdv>|XMcvv1mc^IHZ?ojdkzPb>ydBl7^S-Cs50bLe zU9o!R>dC-_6QI#31U%a0--^RP93U0ZQyENcp*ObJ4oeze1C-{V3IpdkTID6y`0Rn^ zEK3Uapza@SVw(#ts_$IG6pQMW5>?vXeLz$by(7Qhi1L&@^b`x9ChzH-;D3d z4{2FLcD(J8UYFMPoPs%Y5Cxx~%<+3MK6P^UWb!pFKk!(vfn^>Ey-P5_`85ITOKTf< zf3`=S&A^~qyzzw)?CHOxq`}UYTc8Ma+mTp+GA&(nJB1=-rrB~ji9msa zSk3;WqVLbnqs`Dm{{7hWY4_5GFmE}{@JeU2=C{ytTDj=&;Xja%0^vJ===$*0c{H{U z8Nz4Xd!E&vbe^pcc~-Pr9(O2F+W2v`PU+~GvP8eaV35uGM0M{Yhw)X5geN3VXS9C@ z5Rqm#u&lI{NdcJP=|fcpFbXkLicd#PwkLYJlJA~NiMgQUX-D(j=s*@@$zaBiHf0D^gH(GT%=(SC~q#=&JJDI4u_i&8E zr3U*Qu7qzv+ueq}8noPqy5WX(i$8}LqU^6Ly|M?Lju^y;btRnkpc*TlZ{GlG7w^yz6z8)$To{Z# z^`uo_nt58nvTU#&`kw<<-pL z-7FBtiFe{ACJGU+Dq^WCwHU&U4}_6UP`KHOqz71^yXqy}XJjt(>qwg-cFZTik{(Q# zz(luH!;ALikA!YPNdplN!-nM|U-J^EBpJGPr7 z-@0k;uNpOlk|e{98HInD-lGSUpR|$=e>;=JmL#p+1sw`nKe&H8pnRx@93a!%4Jb{- z`Ru1q0;pT&Tj$GVsVf^`1+S>oYJVx`5AO>`K6Cwce&d&33L?IF0DILJ!hKz!O5x5H zl34`qez-_5^H*6opBZBOd!UEDHnG$t4?7Xbpv!tZY~)%RbRFUoGOf5cRf?0@e7i0^ zFBpUID6JU_2(DheF8cj9$R53BNH4yS#&?_g!BC@9^^%lpJ*K<7N7C8xwx$OiiNhouVlt2qy4&8j|6u0qAt2PcuiIb_Al ztS-GKwxCBYVg{ri)Lej4PhK#@7LUMg^;!bN+!1jJva80OsFlo?CTzB(*L5FO1dV z9hY|R$RrzAgL_Y%;ERBfkMT&hjT>~+@j>+@3H>APX`GF8Ye4RH2 zP%TL&l;ZAXqoFSP)CX+N1@rccVG-+Iaywe$yn|PiI%5=6E5&ca+VX^uKKU{Eja2pc zWX#+g>Ub~>@^H^g^mlAgwsu>Sp`zI%RK_4KX4FLC`$*W70_0|DgB~tf2?MmLAxU@Y zZn?Lo~lSCqnLbibMBis}q4w!Tx|X&K--Cm$t@{6DGLHy50?2*tqd>u47U*{PTG>3IR(8^ig`nhC{~U9z8}a?`~@ zC!Y%qkj)Y&VP<~vLdUPq&%o*zkH<h z*Ll!C2j7mF~oSYp@-dCFdQxirq*04Lr2ma+N;LwJc zh(n&n=sAd0fY?#zxBkx_JeiwWx(|uKtXmF~8&Z!~b;l4ch?H)cRoK$G+M=8!F+SU{ z8+RP}_pV2$u6+P{DE;I@GZ~V!^iZYa=5m|mcc$TI*7TRoVq?+$LHdZ{b9@SzlpsD!r7$iDnGdBuxZA&HDHK&*&LP9p z-IVdg_ZE`lO8N!>lL&`iDXiP=>tX)lV=$tUaePFc0BGcPaV3g{SSI0B`IlZK`g1Z1 zYryo^j_vA0`r%L}WnJJRjxPIt!+~9ICdLR015apW^U(=W{_7>_J z1ZhJqDR^m&r$5YcV;LRrGI4gfZ%#w4w{Rn34Y`aOPQu;{OVYU;>Dad~3Z|B2mbVI8 zIDPis9xve-U^1s6{uEAS>xl($6o`Wc^bh(zZn~oIPJV|t=ThL64dT)VB{dR^;y&lh zo`wmE%`|ISutcdn1qa&X#g$u`gORD`<|{n$>=3s>uffQ$%3=`Fj)>lb5&+f;viio~ z*7TL_!JE&-C9wmP)#VXn0yKd$q%vEQaVYLcrg7HNY+!D8TfE%u(jmC$e!6b=dG(TM4`-~B1n>y;B=)15lZEme^OJCQ;Dzd6ocM5CeZ((Ncvis&l)4c*iWQRV>Y|x1=hKch#F~?5I)1 z!ix6IW2Wb14{xXM1#3R~hZ%sL{A11h>I=JAl=I-{<#}-L;t}3 zM`^p}RZpG8M8j|5-=~6^xOt!Cz`6qR_UUj{QAA=f{%h%~8#RXIz~IXbdE2^pS>3we zNfh>W)}Ii=+~1$tRvJxL! zVdH}e3`9W~rXGJ>&%liUpq`<7aCWUVx39CPZ1t}6K8kJVUwK|1 zF*Uv}s-)y&Uf2?TOPh@d_#B6UHi@(f%TaqsW+pS_46s?(n$?GTvHWkd&T3&uLi6s) zzB=VX6NHmpKi_ykQvARNPctF6Hd)1CT(CEJpiaD+gWXs@9l7Dcc@B9d(m$yfl>7S3 zq9tdl|Gi_LjRdDElBL!`n<$U;lXd-QLE&28(fb=BV47OHI`x%JZ z6(M+CBQ86ESkA`;?d3pgs~B5iJdfVAbVNDZH41iodLB(eN(V)GrM}a2dV<@q#GA=l zx(){mandn)G4>=iItTbD)$5Q8kxHA7zQ42V&8jR`Z9t;NKtIIYXci_19GzbQF#o7; zgS1V@41HqUZsdDt-UfE(`&Z8!CVp>nRE|=C0!PA?Im_|H{cMIn=uR(4Nsq$kgJ7dQ zvz;wUDu0m{L$;;l^lXvSJJXl<;|ZDE zpLO62{z?b=mLP{y(^9)f(DUYrn8RQ~m9!QG4#XwDSK8DKO2_^_)8dvoQg+3Os$=<4 zD|`MPmtQy49OtSFgK}4@X{fVF-gJO;CLG=Wh^cRfDaV|{@&5L;3bB%%&q6Elqri9f zGCCVrEa)wDF&SBn)jcOgmzth3PrsYnbPQP+T~W5%{6UH#jX7#mquXT)+)nf9aB1j? za!%^HN4A+=yClsi@0IN#}O0?A&S4Flf2P- z`<^Xe(+xKYN}6YLNq>b8!-h_VOml;r&`N|cE$ zHWB=iRLluk?o`6)3lE{>Y7vF*et}b&etFJae?ROiOCu`V)5$K`K$~!HEU6Zbt4lH- zt`r)uDaolAw$48zFOaPsywDL99)C#6@x0m$&q^&9iDe!DL?7s-FjXNK(hu09`zEoC zSVb$9-kQ)$5AsQ^scHRZg!rWWX{D6EYAbv%L=0CJw+WRwygVws_tj&PKPALc_sd!G zqXnk4X(x5_^E;hE=PJ1EIB#r9|IO{7ta-RA`iBU6u;D=97i!mUmbZzXu?IYDi^Vmo zlXDG+sYDLjk^yJvK||`*9b4hq>ZUcm&5)C+8^$bYZ7tB*n*hp(|NDFmcGD8%<_&>6 z85b82-{d9= zndK%^eo~Cre$mjn(8Q^&pXDj~&J3uCZ_|X=f1^K0XM9c0(2zN7rFtBIqwc>9{eZ@4 z-0;pb4`lEuD^>z&pBEfx%ad)?@a*b1#W+b=B8!eN57*ch_ubuYWo&H?dd=a1%UqM5Yh!yd z>pHXBs(qLb@5jx*By1;kNugx2Dir7M@fEHG=A-SU8_}Mi1xX3#uFgE2g0#(34`J6V zo7(pZb$h}3R*l!?K40k$eL}f+*rvk>FMF%mphG3u-}emeJpXB}UY)IRo_IT(;}f#+ zNH&F;VB45OS%D-ylW5{hJ=&VF`&wC{^oB9ndm3H2||-eHi0Xn6m$sikplLL1oD>p_8@LN;V%G zg|9SA4}$T(gm-X0dG`Ea<*gCLacYnv`6{+N3el~A57omdBpq*dVvnkzjMp(A&W4@8 z)9BIFQ?xvS3=hyfBT3jM9(O1lB?XGW*R?k+@cZ~U+^c@YTLDF9=mzA@%my0(m(>YzxB z(9@+AMts~@7YOsj_vqoj;z$R%Sn*Nl8h)L*R|9t7Yy<3{SOL!_h}2YkO1Imm($Dwr zCNh3XH-n{Y8}EctcFXSA(GC4g7n};m1dCB0dQ$F-eBappb>^zB1DnSFV0HWH<2c0| za~_Ok%8I$6y}l)RXWV*h8*jX#D>ydh!t|T*Brt}O`W@uA8Y*TJnGk@J?E5}Y3#&3) z(2i@&z58q7rPYq?PlVG+t<@o2w3bCCk70eruavKyWv6Ums>SX2>?+tf*yle`H1hl+ zRg~oq&ZQ{PXX5=M)u$0`xW0qLx5%(M3lM2BMt^ATdJb_;axj~#@$leRzr$#2(K$?fEaP+!KAp1@nRIGc~Z=tP&%(MqtF_tPAJ6-{g;dBHot1yn#C39vbxNw9Xqo)N%# z)gv3S)pL8SW_7vGw{lH404h=z^G){Mbh&k7+6d1>{+KYbpTp+W&_?chI0ZHzAZ$_G z0BaL6&q%l$TC(NsmEAd0_U&wxyvOo(fKEsAG2Hdh>d!q$CVuQckRbD>;dQdV+GPqv zZm$t!tjPd+CG_zb{b*l&Q5G*lUGEujdT^9#Jm{45M%>2MJ&)F=b)7&)vhG*`HRW{#VBU1It6v&`T8_ME zX<78uzcr<|g8iJg8QW`g!ck|!A@Ya(5s3UOG&Y}DSq4Y{GSbSo1GtSQ)Vy*okN07{ z8LLoNYj+~18`)# zftk&v7JSB#q8cDYSn&N}u=Kp1vhLr~%MX-5yt?gbau6uVrvve7&_7RgJgBEhxbG{) zkg6Jvs{+H#qUD_bye&Wz$m!P^FnU2fXa&q5PX4DFF=9VazzmKbM~Y5~>K56lDup35 znvqccRQ9sk}D*3#)^I1LbkNy;PZ)1n-*b(8$ zgKwQ&*)DnVBbBWxqO7WZC6*Xz^!TCHbOm`|Wkl$@xVZcZ11Wn0@exv=l$ag{I8h1A z&=?6AgCtq@{F?(uqR)aZTIT=w*0r{qMv=--y&!$pA{Aq_Ov;KVR8~TFiS{dMb_3&k zWV>lDXwbCTOUw&_AZ}C6SjcNat8w0l?8I#uf^>@k>^Us&PhYn%RL>@5pxp=%5C0DXrPsp>CzR&{yVmK-eYTdES|j34W%={B zctM-|skBVLc6Jl0u+4{eNDn9Ts64}N?&n%V$ zV`21O4h-}*hP{$8{;jXVJ`O}`Ws2XL}S5{V0`7m31K~RI7jq^#UAH^20@JWfl<^#a~f|2hi z8^Q7S&M)uz4Oqf>(AIK*YarL-ic?GUL`{h5- zsN@J+E5-G!FW<&xUJrD7%lcks^-tLRc?>Qzp_3o21Gm74tFEsM_*qtWIMmNi3ZZKS z(+@<0x8BwLGya!O#PpmewZSKqAP+nZ0& zG`zm;8UISY5Q<^2O1jSax3oSeXbAQv(W4N!f}K^K~xVs}i3?huKU^WcgkQ4dbEtF7}4Dm1=c{wA?KA zX3lc4Cs~;klM=no9=$cl^=RR3vy~;d&q8+jgpDG%&HO`zY^uN~mwS6jzpGjpe?UTR zFLiSfo?^`+#BO-;g#;qZm?xB~=J(umu&b>6Hd=hM$64W)Lh^&tHk9Vc@EBd!em`(3 zR=!&dU@EUAR&>9c1-y_SYk?;Z2lH zSqbIFQxAmPZ|H4Ao~=Nib8sYOXw*yY^oJ=IZEcpvb<^3d!6MOGbt;7Hm$_Yz{UO3V z=|MIQj!CE5?^p7Wzr(J2WnZYTv0QEG>0Fn-Ro3IkF-=3;(HL&+u=00deb*4nwT+lT zYWZy!)#pzV>nCe5nx-co5=$Y=q5}jeKx?3X^#*^conke=VUpjk$UtjRGtO#j71U*O z#82@hD@g*nyi^&Nno3L#nqO2U$&Z(ZN)AyyhdQ9YpQCJ(eC0Bevw5InVw8#XoqJC) z{*Q0JPhi?6W$iTFnqEE;vSSKv!59wggdE3J*9-t!d;YG!osgT4@ru*8VnB2_F550t zTTdL@VoVHy7(;Pra6&=x=)i?qWiXtE?gLTADqy7?yA}4x4ep7NOfm&XQDhwHc<;Uo zsa92)j+UW?Egn(u`CJ*R&KNU2)t3i4+or2Bf2o&|TYVSr@sVi%I7zq+ra~%@#&wXgIUDp&A*&GIPAn)SSj?%lfAywrWh-BY`h= ze1ttL6lP*uA0i2xR-XYby3>(NImu1-j_;2vwfI`wG@x@Ux8rn#BMz!7sn>bJ(?!?Z zh=FttnjasDrDP!(b6yN?fQByMy5%b|$g|OC(o5%RcU5G8Z_e7YO}d#p+jckLuX^5v zoTs)#cyMFn4)!Shx|tumuSiS#GiCnF6Y!R1)t1*1DVr6!w|{MpD_wV2sE-vp(3*YNIT3Hc(Zno1}rErWub!n5yB)rIm(N-tSOC1?IDWz$n(~23dPZGCakqF%VOWM zP-);~Z*sxm97avc&N$y5aUVx|FtVv)%C37>qi9Hmj~;AThUE^-UFW_EUpbc1AN!(! z6ToPMVoYn_hsJlS;U&L;*_cy&o^7oJTke2S3USI3sVma~KE_{pIvTSy&7GW+rgPap zCC}-6@KR^*X=1V3h&E-Dp;K$_)Gq*+5GRfZRYCsTE55N1>-0Y!hAcq_I$g2T81116 z2>TB`+c`LeSBX2Vd%JwDy}R$jY$?`TatF1Jbj6~HLv$l`;e+*W*m4c73u+0}->i1> zS$xb1)Il<_&`xdWgZzPuBLfEUG0=(<_dn-%%(IpTjYRt)JlOMW%nznx9pG}KZ}+@2 zamd>-_|^}~(a@;ba7vX}1jls}{6VQ(&n>u0<+8ap)jEPB`@N0AwCwlBId&fjU57Z@ zBwF2nCa?W!2VUVP>;t@g%ka{}p`4J1YMBCouOxpSmW+}Z`VDGCd1tBr5R&;I2TaF^ zx`meETv)a65JrOb_x#=vA;3qd&xSfR7V-JvZeCl%+;m`Dx;Y6s8_$=G0P(TOf`2=>cS1;o8TywY4EYZIA$E!=|h|V;T3FYg%(qMlkrX@C~ zG#0LLbCW_hTv8NSpS4$_L$^PUd*Ci$?0ANyj_&5hS6KpaRf5I0HA}l4({xRhnj%eS zl~H*;s+AL{a$#Q`Eq&<-h%{@*znIm_KHzf4}P5;r;;tVzcRP3Sd)izI;AW zZvBkjW<0F46)c!Y{J{9swG6n!b4PS@yKz(dTr|#9-)_lywrZmMXdHYm2@9EqN zJjgTcbL+mXBw+WJsK=Xa0(b*PfQ7gUBOPkjN(-vBu1&4D&ac)bp_W*g(7N-00?Plx zs6J_#`sX#Nb1<~RqR-#ei*d1fM<5=?p{P^hB>jCeLMi@467|QruK7AIgwIVVRKXTU z9o?iaqcc}CTh_54;na}%@;)4bWI=%;k0I}L=xrOk$F&<2Yr*61hiRWTFKOkX*Hnij2vU%$l_9G3*n&=GGb!s; zjmY2e7POmYzM$^Dbe+eShq`b>W`TUn!*UbX4EH0LRO z6BqRLOH!_&DJgrb>tM_hd<1kHuS-?gfb7F>0+&d0wB7^FF63u_hOEoX&XJ@3bAuu; z{!sFOpj`Zu0!mu<(X546pl_A$kz;EETpEi?yNNAzx|WA^lGbzeccU} zoLvA5L8|BtUS`B3ult7btuLG3^$_yq<_mjQu-QOU+^zZs{|^Tl4rPN=U|1SCc{^FL ze+)b26+(m-(~>UEKguX9PrfU9q+{O|LGn4)kIPYlwm4M+F)+J$Po3?+Tl$9B9>Bxg#SkyiKH#OafC@*}=Z{&O2ZDI>Ih4qt?`m%|)x_Ky2p zLMg!A!g0{2lg)Jk_hl87zM^MjnSaBjimbn< z8|U3#L!rOWCJr$TUX4$SK zt*-SjZu zLy!&iMVg*lYGhUEAoe4liJFr9^F+%WYA@<5xt(rttZKqmtXL5eYP)st>ber8;~@}X z?)(#%rOWSZ|1oW0^MoZ*oy$N~0N=97%GASPL(tpo_3Oit8Z@HL6Mnik<5JcFgUfh- z`}@XJ?BovKJis^6KSOgj!n6nI?r7ok55F^KQzYK0YtGam7D$ubZ~1-OAKhSvQ)6w(4^Y_-K+5oMbCvF9?nr~Ck-JOhce?gdMh8jU1E#0O9oj@(fVrrX|T zR|;@#&E$y?loY6cXrjrHuDeOJug-lRu6~mc3rh;NCOi+xKi#pTt3?kneXs} z_tdSeI(p20y$ZS9^8b;N(ai`;(FL|lA$PkoDp2ma%qdNXhp5T=w;QGV=|Trw(#h2_ z3lCMOg4@(@GZ+IuuY~T+K8ni}5b4HX#g`(XAJm9DwZWx(ho$a$ z_wkHH`hiJ~n}F=RjTYg|3sctX%_ExU0j#1_TVI8O z5ajsj7g)}yL0i6AL8c`!zVAuM$5Z5nOs`!YXDM}>kC`{X zsn+_{dq1|P+4bmT6Ua9O+vyWaMB=^D?{0US%r)&(NdAQMUutBFpt=#*Jqmp#{ST}j z2p6c7iDNY5?OzT$=qHHps#E}RW@FHhXxBf49a;T17FvU8ZeyCebv`cwnth%hs6fI| z9Hw0glEIYsd)|R-*F|3pF~xcMmWmpJ5i8bBN#~!#GXxa8>c?m}4cNgWlVq4~FkWr5 zE9g86CsE%mh4W~@Oh>6QAWc^c>ld@g?sYP)KQ2^A9byP^dSlIB_b~)pqQ*xg`Sm!I zgMYqYp_4Nd6O|lFqWz7+MvEdLMS{pzX@v1(1~0F3;&VSJJZx@w#b6a7btOm8#3JI9 z!8mV&xz1;08ykk0?1h4+mNu<)h*n*Fk_W%hdmMApf==7Z*NHfFuGw0cnI=v?Ts5j{ zmr1cKLD_-TXMe&eYi-8o75lA{caKKgu~wl`Gx*T0kZkPD$Y8fnOfPc?cRSK*z}3Vr z`awZ^QyhP?169AesmtUoJISzHQRDf=`+w{>361~?sRz7qcaQl-@O$I@fwEflPGD`3 zlhEAwC8S2k$_i33>=>=3Q_E_q^(yf{5X^~q{Y-^aA3K!^Edyq!wb^AW5~ENtw0Tid zFym_w>0Gz=btU|63Epw5Jfiaz1hC{zU~-dWv=`;56pZqEZMH1xTbSlzEi{JRAN|*0kR2;fs^8YJtJF^k*O9 zc*C6&vz_l<+zW3RHVsp4oKaRQgPG|x&ox3-m!8jyXE@1cd5IZob;nnN81i@%^m3mp zyt0Z%1#n|G}!=vmc_b<=1(dY%XlM7vBVN z8vG0#gFLjjg?+cls1nEc=RZ)R*$}6w)f_uII|i*Pi4%@J=AS+G308tso7SAJiw~B> zqJLEW7-+_@^K!HBumYhuLlrh4MXG`ifG7_KAlbhjj52J5Ar4D8;w*Qdi@le<`l@BcTY?aqi$KR) z2`6c|7W+4tLIb&F`*4o5v+4h0>pi2I>Y{J&Py`eZ>75`Tpfsf;p@}pRqoDL6y+oR{ z0HI57f(imsq)P8ZAoLE>d#DM5(i5aa2zbwP-~WBT-1{M)GDgN3C+F)g^ zrqkuzLlSgb0Lt*}G;q!*NMC|^1)(!98q9a+dlSc43eEF{LK7O-xqdZ1>1+La+T+4Q zy#+`TjC<0R0^WT7+zvB%>#76_EDGWTc=wDFd?rRuisjLQ}yZ_LrFBV6?5iWR=|2CdAN%uoc` z4uJRl6?Mh$dHhaoW8$G06iEAp6$2+xl;^RG$4GUh-OX# zXatK^F7xLwrHag?EbbY-z-wzCjrQrY+##;%9^64rWRoX!antbdt019HjsST66+4a5 z!@|_h$610juOgN~h()G|&o(rj2@1)I<>M$iOh?>Weeyf+71H^qQvi5U{b|eqO@J2h zNn@b#k(r&xD1Vnn`S3T%-Y(zdFX7OR?Q@^v6x(Z`5*uUr$_e1T9bfRA^U z0047r;I2Hs&=yO&DDt!bykcC9@~c++&K@R_NNj*rp!#yH8X0i0&bw5zk`9K&bA_9EgBORlpB*aL^cW89j$H zb!{|n?&5rt7;UqkRl|?U0Iots-0c({23O5f6%axb@IruZ_Eo{H3?mGuvlHIn?Je0U zSL2KqD3UZFlJYbq;nzT(?GOSZO9}Qa%6>h_gm``9^m*Nm@B3IWnfq=0Gh%O9FrJ-= zif_t4<0t-Hu@mC){McvJ6$C+7j*-sHgNRLys@=IWognJ#2HwyTO(TJp@Wt=1j*>`p z$`>K(SS5+>0FD0AinXrd?b8iOb94Du?DAyGA3{MtQ$a&Af94|aHsI)7X27g+$PN!N z#pQ-0EG~1T$LV*{y2SFG_#e>2$yn=GO`b^a#HsZ#xu=CH#SN^_N9-d+$_N3wkCAiU zm*#1+Ax*6NsV>hnsh1%cl3XAP_;b*65Xe6V`4v8L>NF+M*g@?gNtnj;XOXQ~!i_9Z z0JUXWY{Sq|mURl8&8&6H{6ja!K`pX6`2R(;jX(XCb)k-V6HKpZt&-SiCPBS#g$>_& zEukW!(c(^^+fZe17m5Z7kcN;RZUdcZ*VhCeOfsXhq*;iQ%Z`K$aQch=_^Bzj*CREF z$|2*k<466w((XyDYd6p%J^w(g$1p1@%_6ZkD6`^vmFVh+_e8YUWIjfhq^peNFqqH= z#_{#X#e99CN&2mmY%0H_1_)a%sc%EZ9gSf)?pFR%#SgxFU4C~xT%LF0n#3)5fhMjv z+OrZC(3q4`ur#nW8WQC3zKg?FF=HW;jQfwJ7!YA}sEYUNbx&Zuzw>}L08kHIhnTu{ zI*E7GTh}!r!+qjZtE~N!98Ey?o<>uAyBbls0TGbaGwNeOOEZ|}GPsmu2HmJfZ+@_) zoi@`u`qom%-xb_2dcCQ%bs{ZVK@=4m+ zgA@V1>4Ps^)?r-FDIG1<@p@T?giV~8#`QL_Y8k6rgYunbfs_s85x>t$hVnXHhr!TYUpRpVle0ucx|!s;s;$ zFLQl@Y+u&lpIR|A?m}Z&==ErGYWN~6@}mqmb>F=4jX_g7-4>kB-gsm86pnCi|dP z4Li!F=L_qGNgR@HeezqgAivrU& zX^_n{5l_x#?xjbJe2+;7O?3Css!Cp+maGw7%2dD>?#krRQ?#JwP49w52J-J4!KLQAR$7;MZIoCjlHEUee zT6Zqj8w5!a{6lY3FlYv%g|0=@Qmit^5GaH*#80-`0W`&%K!~7xi;u|3t^G z?}OE4jUrlX=yE>0@#W_;H+eF4w(5f4WLvp$9oI1g*-Yh9T&u-QJJ&!JJQ_MB!!4p^ zY&V@PA+FDwBVw|VDlBAiF^hdgo}6vRWzBPf~`}K~Zy28YH6dW&YcBZrS%DyS;Tqx6~?XhQ` z==j;ox7yXtQ!??iAy1oTyjz!obfL{^qO88D6}3;I3q(q9hn-M_%2#s}Z{h}$PQ2%R zEdbR|EpHN-kq{hGyCYnX-w;YKN%wbCatM4OGaNjs%z*^B@YT_P?@gFbD3i4;tG6P@oQR4z{&O9*wvE^^k(~0kBi_PkWvIzqSyTM z5{sDEHXb&Eyaqv*`+N&$*+es zXXMP3g$4}5f2LHEwK_>R6d9x%=4c+*kLH4dLB?kMWzA;`YRdScw5t-*&2 zR7$eSY%m8*`5vC`9grlq+ap&83@LXH*|trm(S$W@g?^8BGVZLqo-~=lHp>L1-bEAaRQW1OlQQcz z?HmhR-pxPVmb}q@?aY&nBZ#0}gSx0w2v=equjhC$N25u2xDM#1j#7DdKEViRpM+;Z zoN*()BUqK2+c@&*t{h1*@xk|?T2mML2x;S2=zRO{TqiH4LP!a|?r4e5U~YU!lDkbi z?x3T1X~%GtZhA2)vu6Cpcim!n*mP9aO&0zf>%mcwSI4#B2Lyh=!X7L@FtlRWKAqTE z6?WC?nI4r$cP+hM>DoTY-7tF5TxeG7&2DR>1_>Jt%uPT5kZnp`vrE6{y22K{&-uI_Q8jgF`$gApDTOU@p!oa}qql>Sjn^DsL&=PD3viIXHd2(D*pTHW5kj{658` zDhr@qfW`m+kIngi3mk6jb?>do{Z8WGqiGrjKt$i)N5F_EQ~`;&=PREN27u z^efir;F-;F}&DxHx!zKNfQ-CLZs6CIEO}YFF8{|AC5CPe?-_s!$V!jb+TNZV_7b zmG9%<@JjpD_iUOPw=c^rR3h((a;1E)A6Dzp?g9A&bw%}}y7mmjNGJ(G?ONyrblT^R z{ydu%?LC*Rzn48cf1l*@*2-XWJOk<5ZdKX&j(MdGD9`U4&@{GX&Yea~@vmXi`^SHl zSBAn7-+|$XQKyg#smJx-*YoJaaqbC3cl_DY@7fi11lvMm%kiR}sR1A6tpb@@R3Z}& z-4em|f>NJ+57N)R#H9tB5BUeW0qc@j*R7@)#gtQz)2_P785(*11sDXr3eNU^BRY58 zKM(h|A7=UbR|^5~KK5W9m-F0r#K8O=9*P+t%2Z6taN^f&g68~l-PZJMu{n75hFK9^ zW1a(z_8qx|lw%7J;uAhv6<@Nq0**$x+WQCMSuxQO5)ydW-s+-3+xCs>L>+w0?e1w!s?V zEq^6XypDh9Y*8H)AT}qvGp8B8vV#o#9#Xd>Wd-> zIbJsUuLH%b2>}bEwbA1drX9-&$l;!~htG-^WI`T3yf2#kdCSlswL+<O9c<1zR z--??M(cj^;xcLv{)>Wc$>e^brd6_h|rii3DTsdRq41N>pqi62*_LB%Oc70glJU z{qjuo9;X|x&LfF?KhL3xLTb@e(C7(&^8CXW-VExx3`ekjb;_+f?6GhddD0kRJcCkk zn$Jv5;`Nu%Cx#(e_;l0guN#4>RsIkcS#--HCbj5m6`Fdc07s5bCg(Ipo=`DG79 zS`zE?{(*A5L}RZ;-&)lyRpi#ubxT&Tg>);rNZ$0P4p(`2nyvMsVM^4ot)nGsc#K?9 z*VB_1FaY>C*oIOz=h3B0yOWv|oi4MgP!=0ddJA}buWQljkb}?t@}k92vW`y=>f%S@ z9`TUBouYWH`_7J%Y#E}58}C-(K=2nNGZB2zdsMb94I!B#*~*&F{mjN9?IH*CChKxU zI+ZC9nl*&z3t{IRI-EVKU3}h0i3O(ET!|4YUVy&k8aj>7O@rM2_<=!6H8XMJ&gxv0Sp89FGJy(gU zjU4M)rMRL7{$Nv}~^!IXhQBSB^)Tf`W*6x-5UMhb#Z zX-mc(A53wVn{C6o?q#MUT&_}TeA!joD%s7Hx1Y#qjRJJ45`ud^VCh^>Px#pe$eB+n z71cYMCr?-sHO6v%n~vDF!mZjE%Rzp3xfQVAhzQeaviAdHaqnQWLG3>X&$Z!xvsH52Zs`;Hv+_OOxqL zAY{s_V|W|l&bk>~QoFpUkPH=X`}{XQ=NOu(I-zA=Y<^?NMX4%Xp`x*IP0{%2^||)K z3O_%Nk|;sz&P6W=cUC`SMzJPkE1hYy?q!}k(WJ~0?x>Et+2*_vFQ1=trh{j=^O5D& zu$^(00MK_T4)OoU7_uP|qJCfg<=!`JC?p-@ zzRy|$z$e<7fFe07NDI@EaC>_H%|UK2F6NE+!JL2z4eRiztKhF8>MhE@Q7?H!>awso zUpI;ap;2kR=e??*f8sT+Fomj`Qk$Q8EajB=_#ojNFCj*NUrQ-D#ye|NLccNY0*Z>v z18nzx0<|?gcX{4%{E=96INySXb5JCP$mN#7t*amp;J*$bX^d^ff3D8E>jI-G+dvK@ zfFIm!S8i2!Dp&xXtBD``TC=t@!6wkqws50A)p&?geKS9`?4{`U-Mf%Ep$LF?#6UE} zS0_T4@#?0HGp}*==(|(LoC?wxN-k*ZZ2=>>d(%4ncfE5MK_SAQt^7W--3y|%l-Ot; z3MBhxent3(q>PM4+tMyGPSThBb zK85X``jZOT_cyF45u(cc@c*P`3`9ps*cJbbsMtv$6^~ex>D?UAlIv}OeUCb3sRz!S zqGb27Bj(-qc{>_2(OYZ>V#VrQHN#(1W)hfR!+FEiDB6Q@=}C>%i|IXR)_1{zrW(LK zY&Di1Rm9%>#7Hd@Cr#fk!=~fV5LA{o+KdrMH5HAl&J#TpJK@w8uXIe>n)5cX$zi>j z%1=`+a+8WToC+8M$`M+-GUq$3Sm5eU2wIiug(mP;!w=5@b)S||BWz!=hh^FvFe7k` zaHZ|Cz1w2)WMq9s%_+OHhk9`Vu^`M=_$b+8C1Rm*-mM+`v|xkU`(|B5%l>-w4@_fz zyuGcJqMbWxQ#bgvlb>d~iVy#5->4MIHEF&;pzay6D=U;8RezEG(`H^D znZ08Y%r?HDH<#**DZ*x2Z2#Ctkq>_w!PxY1qZaipEw!)BBpzt1=@}_%p2f67oX!F) zi`>_5OZ0;2@1Qyy8gV<7KS(_?9%t_It#YNJbojn-g}RLI-^OMEtVJ4p_GL6NvZ%&Y zMGw5%*35^V4Ph@%2$q?H({;^(=^%`Ga4TKaOt*Mzid;9@u#4{nRE1&7k$~+$^zswR z74!Lu6Ar`tWHs1cy^kA9hQZ2ybM%VAz75>#XVJ+Ny7+y-{;oDH5$Vz2*8Tkuu;Wk> zMewF$Xo*|f;eq9{k_#@rKv><$yWBrh|Jx_rHv6A)M`XC2+1XMapHs3CMD~*Kq0|y? z)_wl#R3>}B@(T;PIKLc5UPqnvNxzVP%x3Mz;s>B1304cR;O7+Td;|+UOnpuqT%pVP6H; z?VB@Ii9SBVWgnxnbE70q*i9|e3L7#PV%==jxl!@lyC9^>!o1RBZ-Bz?uVAK7fJ+Hlcwp)^_i1>j(PnS)X@N1kWo`0(Jt5| zoS#ovVE+cC3z|@Xx7Ew)$q~dIMsm0_6Z$ILTwhO1%ePOxZhj!!_x-(th-WJ5$FRcT z)VHhgTt=dhC&r4FsGM|U!P$pqNrpLlVk+Gz>tO_c!2%Qg(eBIbm$fMK6 zyGM9~!A^1yfmF9Z?m+Ekw#p`}6Hle|*;ZIogaZ3#d=mK-22>m%yJQw%+m zk3bHnnw-Flm*@sWA8YuiH7K4Z-6y2frOAjR2xWB7uDw3_Nxgv=CGjLi_m@_)9B8r$ zDowJFykeg8v7#HvTm5~?n#on`&)}TSGI%-;KBIZ;Dzc|3(uvT)O>JQOdaa^!xNvgu zL^TZbIw9xkVE9a}DN`{EW*0XM`y?CUq{A^UMx|f-KFp*kzlkmAjwLq`R+K58jz3$E z%Ko4-*LyVm{t{B577UxZ(f z$G)c@ywleE&!DN!Gx?F)V=kk3q7Om0n8-u$+!&9wqLpx0=7C46Pr9F!G)xSOr0hnY_l{^86Imx`%zFazDtnJC_4Rxe-Kh zW-^H|D_nJ+17&UNP4&;o?}*b6I%yB^sTKx2rxd%;r!OHssGt8!`yY(3rR(*=5|e3S z2U_7QtQede96ev&tIW6aFnOPLU4;Su-wdml<7R8gvU5G5w=ajvx2-8oMt@xN6dM2eB}nI}uM=cf zvqy5k3^cjwnxqdS^$AWNw%}&wv)%ypz&iZg+V$_!XSxj|S05+`!UP$$@zfE=`mTye zJH1ZS%jK+=3sa!pB4Tgd5Eb%Zxb`pK8~QA{y=KhHJ%1lCC9M4pP9mmA+3vhQy=+L) zawHTo^4;xe%`%cqf{%58BoY+J+0vVE&_%DQ`=ArZE*ew5M~G+c7!czeXlKM-wQac5 zqMg#wEFItAZsYqe3fT8Io1CIH<&;fyKUuro5!qS~RbvjsAftUk;##T`8r$_HqLfZ9B7dNy08BM!9nfrQ4mVa0(e!9l}!|XkV#C*QPY^l$g+@p&_oyLWpKk-pn z*aToT2L0irLwjLz>h0{Nhz72uJ3Q`-{n0SaY~#^{n8er@58ElU?btxIo#b%=YvBkT z{QTqAX@or^9NGn>Lm9x|PT2=NI%hFwZuxFrL6+O>rt3kMJ?nz(8x$k*sOj z+S=8{r)6Ijc){KjAr`;3L}F5i-_C}bLZsWLM608Zjcm-Ii?Z$o}w=bOUP~B}Rk%UqT z{0fhM0{CHIGe-xa?q5x8K6&N5#CL%rfIOm~MvLAY};pXQ-Q*n!<_RrPobwLJ%h=jFiv4aT|@Bn1{D0eowNa&{_1;3gT>I#MPt+c zX^U0egunj*tl!vup#fbN0BIjt(Zjv4tBo6aoLIL{)_EqYPUo(x*|7EOXIg&_T;1%D zX`W)oZzlUZOvjd98~;r7z-0GCsnXfuawCpI$bN4Z{r06_Fe#T#C{1$~uuV(V5@<*o zxRV|00B{#8z_B5e5E=Y4#k-BhLiKYETawN#SLqL$W*UC+AF4kjcJlmwn>;xi&1{A# z=?9n^db6vkwHAcHK6C)(3`(q0lXph6>vx}|q4BtLzGGsm>|2VGz7QTY+yJH{7Gj`0 z@X#V*{#N&|OGFo4`Ymo9KXl$r9TyPcq6?|4G~3~<64jDakIk0qRc24_H_eH2jCgh- zGkUp_lw6^TOm1A1doO<5Bkbj8{@3NHlq-$+gk8$6p$^CICk``>Dtp<%0ONStd+~(2 zJT^;h)=-C>WfGNSswuj3Yn{b5^g8$jffZ|+f@j=cTQm&jZMfhWm%8xl$xKRV4c_w) zc@r)nb?{|x1u62y&HR7*UPJl1F*$c%*d@-C^Cv`6e&hdMGO5aAVOjKHbo^D1v`9^RH1vWi4VpQ8SzWVp9qULoh%XZT-12#|p5V z7bD3H<~sq%l+)PHeEngl&jnBK@da6HVomKsqgWbE=6Ye-ThHwgm@`JKg8u!xeUS<3rgFmWtfb`s#stpF&WfXgs;Xq!k-&G%{0D77PFry8aR4cv!-zWxt)^#-s(&J!6!s*(~BJC z_-cN9Z@K%09^&p>tX!5lp0?&rEsABj@b2N&H(8a1aTm}53XD7JX(x%=loq?kdDm@0 z$KTiM&g{>yN3lZLL#dAFJiy3MLkR)c`Hj%M!*vT*%vjro5}l4a_0C+ntlydYS97J0 ztWVNk{7se?MilTSv#sikBCCt3f{1Pv>4+O+SOI8-< zbt`_i_{AKzX3H7YG|o!zep*z@-V>3QtS;auWecP?u_OW9Xos<@><#n82NlM<0rtZb zj0@(4zbiwZNZsbWKSs4fE0K7`3wH;=hCWt|yM_UG!aNyt{e%rfqa%}KE~XTDNQFhA zAP&$U_eCM~DdJt+h!O5Iqhx8jG@npnF^v|18{V#!5s7fq1|J_x1hWmWRl8JwY-hWg zFa`G0BQGWkG+S*q}`n?RW z1({^D7G^cOU~$d)>P|iWY5H%=?tvctssgV7l73t5*uQF>;=O#ow(Rq0R_xQ&F3X7z z6oP6A$=welv%I>}h7Zuj={!Xe;!q-JzIuL`M-)XU!K?QLv*UddOj&ydaLe_}&H)bP zZs(Pw(*f{OIqN_S* z6C{bc3CTkQeIL(J&BwfYQY=_Me`^SIW@aGe@xvd<}>dN}FUU+uLodV9qHi?bC zv)+-cY%sujh&mykdo$cuZVs;+ws^?Rp!w2A=c~t^oJUFAhP<|~6*5TleO-e|2=0b| zs!(3!D)cAu@8Fv)_&bFLJzQ@VAE>=C8jezqxY7Fg-rro)Wso7sjEBBLRuY^L>7LNZFVH6kP(G&W#irGoa~#Wls$9vuHJ_X1f51$ zhPVIT!BCSHOzVArEO+nR*iIfl-ypZK_j&m0s)#m!6xILXbiBM7N-|+2g7@nQ5K2&H zAs`>)@5~r-&|al`UEBZpgV{CTX+gR*mc%z`{q6miT=Vfn$;&FiHbAzNLDX0WbB$Ch zXSum=HcV2hi(VQ35lBd=1P$r3c*HOVBLk>de_9cd?N5UpQsebk5I{~UL8u7x`uyS|mh z8lHlslq+rDKl*=6|osTT4!+${ujGH?;oig83}MHM&QI!Fhr@klV5QxrWm= z+opBqt@c;F3ZTFG&{30HzyMLMyGzIVMG+F_GSD}>tjr3 z)%9Qsj~&o{{f}xHaH?ky@#DAX2znhZU>fH@$Os*|(}&$N%5SX5iqo{*N4)Vb#u3_W zilJU>EcQU`0?ShO8Ct6+%7XII{Oh@D=}IG$@THeCX^Wq`-#-r5);dI#4rD_d&z=OatZ%KC%?A4BU=Kjw|KhF|Yc zcjS8X0{dI`3!Bb?yzJIWt!Hz`L+E+^1~}G{ntVHobC7IA!AO9@a7>tNUcBmSZBr%| z`zi`>j|n7se9N;-4Frh*tLOScZk)(+6P z_*a~l6_jLfY+4tSl?8+v@0LJvk1dAhD&T)BGasy^{3b*14pzs`tH8MVxZL7L`Go=_RP6)4bG8OMPB|@z1}e^1v>mr_K6(+ zYC6oP4fOQyuj_l62Sxts8z(`i%|il_Jvl1rW{nN?Gtwg30#gp*)DB;|o4kfZzx@m< z)*q4W{Gmg~rszbrdk=55#QCTOFR^!7?QDb&s>(+v&gB-PD`)tu?qPRMIgJZd)q3Nm z!z&ahivtX+-vQ&|@#q}E#+D1WR@Qeix@_;}&*kD4y_ZI0Aa33tLx(;j%gVxses7_W z8_5H%5(Bb4tjXP`bg>ZIuiH6yrhS5pUQBs6-4|I%Jz1X1>pgifB5yW`Ij-bFM`9UYYNbF=wKoe}73oC4b)m zeyd@4S_$ZPsvqN?C3=<Z-r>I!kmAqS!h6LRML>drG6bgp$Upxey^?kL@;ox8L$WHUTJhtge>d>8_uPCk0nx-M;A-C*rE2Y zajtDW`w^fQ%8e6eFHC=qo7CPv_{o20Vbapr)}^#K{o~kY*NO)b1k7_c#=~-{+wWM` z!52@O9?!W}e@zvW({5^h`ADDI=Z*~xq({2wXVS~q-ni15tEBmNSK~Qc_4wSqueO-- z@0iT~({cUDt#GHae#U*)Thec`Z+yGvd)(Ov3J|QvO{)@O*W2VY@dMGvYqvz7KemfH zU%X?ybwd*W1(85CXxGKY#)paquD{!rJy;UH(G@T|R*Oxhbuu)4R$k!D!#{H%QMu2u zS@kioUeSNJ&cvQWfAjvM{jTu}gaF=kJO(9;4z6@L_ls?i<8Z5V6v%N9)Znz&x{@z? zR9Entp^EI9$8ft-2NUu3*Q>>V_77gzN)GhJE8M5Z^u?kXTOE#_)l+;LZQ&pBrKZ;r zTm2ge0NGnLUsU^B96i(PdkG+=YjCZ7#`Wr()k(_q@ZsH_bBnPO`weO{g_G+Qwy6$L zSoGEkzoSTYzQ5~F&=<-iS+25q)clxA!+4)7*c^93Fz9|^P8jdcbf_=d$z4Qq2y{>G zolplBoBVPxwzjGHv~a+6h|vaO1Cq*2S5w@vv@HKXx+wj*^tmImr{yyRrG}T+tEF(s z0952xpWjF^v}JS9m%wCT??(rfneyn|7pvLW_ura`u+J_O&hH!8KdyD2X zX&WUFa|5x!A3keyr`b-%9rbsgTFAXeCb$s z3`n+iO$ir0?xR# zcV_N>(_k=P()!iz#={cMIWeIl#qavG6ckP}L3EyX1jOBDz$^tJkJR%rN47P###{N* z1ZZaXIs0(oGsIQhAIxck9z3e*DcGZwaesbUC=twKmPW`0m`|3tk2;~~v7~6TDU(as3&nTQD}=_IN3|ohO#d!_ijnH-(ZvHFnu zR?nG8f^R(RRf))9o;!K9Sfy05DC2}rmUtePxw@|$57AHVZX*qaaGtv2j+Hs_R=wGr zMrpr{@lmnmmtSD$hC{C)pTZyUo;Ea9ItyVxqp3qJS2g*)q`>~w+3jM4qcx1s{%uUQ z+fV4vM+TNd)5mk(ubT5 zgCb5laa%yHHDvnKlpH@gR|+d67#TM?#+~W4H-ECdcr2y)YDP0k$HJ>IRgi}LEuA|I z2kzV%6)(vbij&}G=lRn+rCj=e=6pI2n=(FT5~A5 zlHVM@1?A4CSGOB3L|iyN+%t=yT2}w;TGS%ob4hr8KLNJw0{R=@Yjv%%ofQC(-SNzW z`E6tT5ifkmgE>&{4eE{(rxaD{OF!07k2_!6*bFOM9eS7!#Ipt`_t*iU+vhltv?yM)RDBS8- z@vLvU-+%z;oNlwNm*FAx%NktNci;P$b3$rY>NG?7A6q`MQNBfpz#8>hNEtQbfbd*u zLP1ZOTngF@)-oTJZjg48Si$(j5Jo*Bf1~gN#LSRSEippszWn)<=4voeed3DkHv=q~ zFYRDnCni_>vGrSuW2UaksAhuEei=yybk(<8Q81GhhSujsNuF7 zzA3hO`9O}(JBJV|^X2XKRa4zEsZL6}$PKGg*dj3PEbrnl#}TD)Ut5~2sEvyf+rBgz z!AO^uDm>pr?bt1PZbrp&6($WEQ}SjW-vj+U8wjCnSA=i7TK@w@uH_K|`Xvz;7L;9n zEd9S>;iT?qywjS35l5O$1aw%gsuVt-AhLXa|#M3yV3qLEI{mST6#M!$LyzF(-oYvdg)0dg& zWpSXtLcJ=r=}9u9E*8GiSnxaI1FS#gC>GEH12qJ+J=p7Fh;I(`+2^nQO;pakUjVSd zZan6SYo?<~Tv-Ti)N3gSCzc}As|b=uJLejmgExIV_zV*MdfpQZ5Uwu!mPeN+BXI*^ zISu%}1G_qKIdDPfeh{m{?9~#m>RPNHwGS!1v$P!Fch3r0`qS#Mv}sG}YZyXzHIhqD zl)zd9noS4aCJ3T8Opi==*oc&GYuyv>uYzX7mb=>De8?{NIu=A`MCihyId`Glt9{j+ zqoS+u;IVCpLb-Hm#j5!kwL587*5~mBelKaK-}(H}pr#-<^p?noQx&hLsAQhE&+lPP zHE<*du0_0C9lv(0k6;8ISsB2iD7MSl+fkp~r@~Z~D&8(gP-dN$F;lW!)rQb{v+21$ zd{X9B4*t}{WIa<}L(V{TZWsqTswQYD%l!jQsuKX!=sWJSe;{$#M*y=)bSL;>MwE=M z7_FkuqtP;zLfS_m7^?Po_az_BKnW?8CEDyyPLW z($`B}-A~L$&HDg|OTY1*mW+}N{{E`_QAR193JShkEmr@JOGV+L;~U1ge&2_2s4q8u ztiVU2>NBUjz27FKs!Ix_)Y$Wuf8*yCaR^mL5W;W<8$!LTxV>G*W zaZ>Zx{PdwT3WKeku_6wIO~Y&cw5GDTH``T~%nINBm&r9<a%B{24v`iX{~i1${6R`Bu#;nRqppO_R-u@Y^73!4CS*!u*VXZM;r)uQ5~HNuHsAKCrn}#9o$kiaF-)O z)4qjTTeNlr*7cBn6|!ARp*gKSE6Uw~@fcvmYHOcCQF?CK2s5zdtKBT;sBpPe!|Bzc zCGaIwIjX{n72ctTQ;s_?E^`~LYw72&sm(dXYT1U?c9B9-!S?!q{28FHjQ8kSZG`kf zZ(6!^;4+CS(^un_E@-U}z{{v{+}hsvZP~;><7&a&{X+Tj`(MBP5nDm4m=4Nd3B)s8 zMGntwy8xU|>>;e&EF*2c6B#!ZBhLTjabIJ^kwOfAD9ODaB;?@_52HJ71#_c!sWEid zSM&tZ>&#(KCQL0x90iaG=y!#dl5B_};VRdi%i2f>Oc!wOM4_DP$rt<@(=s7Vz=OjIN31oD zhp?vCUzlw!p3)pF`}u$GTuM84H=f-)rWHJUIpbzqKfRY1n3a|Bj6pa>SFv^vM4nsZ z|3-zioqhXCD7rW9yn^E_W*s?oN8;;_4II<>Df70EoAqcW|IXtK2kkCaDqZHKP&#G2 z+#V9o+IM~!?PFnpr3^bLnQ%yQkjx(-J(g2W^2&hKOL+n0H!OO3H*1AW9hB zB~F6jR3H^9eW~2W#~tbTX6d~@d||1sy`T!gc$p`2d9z11_cUV4b?VxpkB{xTt*d9S zl3l8jD%&`U=aug`9*QY0-59^_0^r=6=fxXzZl;%NSqHe<)U-YLf!KZ={8-T7b>!ns z^S=TTtGp*bFlzf9Clw}Xe;F0Jk$}_5K|Y@u09>MMe}{SIvzu+wQ^|)luHSEmkxx+m z@KdQl#-bmi>hK-!yj_E3#d8FvAws2U<%jYkO6zl|MX#_Fe#s^UiZ-L}4mxEef|qLa zGZbM6qrzaWNp&?niy#wjwqEi}Dbr#fsQQufx7s~FR9PD!nt9>*2lR&|65GXoE6cy{ z$e@}-@WX4+@84F^+;W-J;H+j#d9E|CT0FE4O$w<`k1lAB*w9SD?%&%rnUW3+;_u~Q zZf-V{XxfpTv$QdnEp`JtqUH9}jK)Uus{H7xU}LCP06NuD1lRvnu)ch8)u~0i*_rD| zbn2c~sTuUz3{}NvNy#TQva`$AuNiYmPEe*34o?FJqj>Q1F(ke~Er`*H7IOh$Q_zdr zff+QWbtA&^n*u5C|ABm)IVBc83|z6I%*IKHFL7%CbM%rP66BxeUe?wS z4Wb>VcMpbb2MJ-*qh&g{TrBAuno&XSP($Z5J=rZq2QHJaLbfYOD{keb_YRHKsl0UtI!t1e1Vr(gqsSbe~&x zd_yKXJ#ryJD2jJd=0%ADB81-1`EMk*T=(98bxqqCl5!> z+_9pVz8K$h=e(xK1ITrWk3~MOXpzBEjX*k`cXffxcx*cxZu7LrKBQbTy~XEqM@wTQ zkF)K&8VyByT^0x4dmxioPPHnzP8Akqc7mS{&MKTJ_xK(1W{FLQ+?^h%M(V)UNtifO47_a2R~ zyPAX#HV-%5q+*`Xz?orxJ`ixm^LO3&2As;MeL-XkE+>b;xgqTT-toTTz+K?@TslA~ z4bTI1apn=d9C16y`^#{S{Zxg%2HBqjiRQQ1T{i?6f?a!U<*W0`!KV1&M9hk=_Vfw2 zCa2k@rI)+)n_rUV@)kdswdBc4e@jYgYN|r4x>`B_cQOkhc_6@uDA+-_uYzHnE0}^D z5*|t9?kgVeDy~U^m&hEH7wg@CU)durFc8+(5Bm;z5#TEXDL4O$)}b3(S?cOY-IzS8)^C~eYQ6>Ds-`g?csV?wyf4bag)(EnY{0NSW`UK=5o zOe)d9*J^7aM_X+`jrO;`Cj_J{Lr{4+ci`=wXvtYqKijBt;(y$SV{B`I%F?t_?`Ucm zdYC8v+Vb7=G=K+$Buya<@j?;Bgyi+CuSHHR4i(}D5L&NT<#{Ed8L8m6@Bi%{qF!4Y zWNv0F5UUMt)=p&})I37%TTjupVSI~OMr`LXh$anSpyj2)L76`hdK>Q1Yd70(yZE(a zW18?mXVLmQTf(=$H|JPL4sWJO*7R4V3e9A^dW9IGDFj{I&*QPmyBhsp#a-(++vyf| zt+rH_y0&^ds-4s=Eg@a53#HW*RZ7)hN`p+qrJ6JdQCcY`2t`#fjX{bKC0Ys5)+NZ` zlwc-qjiPQDA`Wrw`8n2^FXs<9ANG1bzVCkbUe9_j&wloIDfNd|?mmM)lX*`VhJoIV zFc?r9m}vA8d8sXu#C%)9Iet$?O-ibZs}TrPnf%W|WzGMPq{dmqevG0akMeXwHA_YgHabmwO9eVj&3rT zm1Sb^N7~T?3JI;H%dmEcGX83@2ho{rN!{_Rm@{V_8GIN?b5B_u|{yyTI<89p3krnew z^-yWwb~Wi~wt~dsjl`9+g7WgyC3<`oPO>wcYt3V?Vzm97<%U6#4}$Jpng}x!rdle5 zE?qv$qf!zMgDD9Yo1z3)M14;%zB0~^;_GQ{2_wzZ#OFaIS6_-pmI*o2zC`Ab+=*c_ z(x%RZK`A4K6j_-U70dtb{&Pk}$maqUkLZrJlS}!63rJF4OvmTLE^OGH2pp&GcZEy^ z{|YKxBp`Z%ZR=PCwj!J4RdnQENt{TO0HV`}(IO0(_Hjy?MV3OZ^M`;!bYKF#8-XyTjbCvJ|Pg*}e0+ z`nS(Y>kC+euMCG+azw#m;zv2s&nj@Z7QqxJ3oJ?5UjT@9fDTIH;b{L`jKP1!7Bnt} zLkz0;{R&y$il>bLV`u+LCZ{>-jPUuS!<=S?K1<`?a?&;f*XJCWqeY(wy%{?$viIWTEm>t+_X5T zt%hk!hiN&q$K?DS=rlnE-g6lh@_=x^lQLZ z28s`acrVN*c=+qPlJeG<)oF3z=x79$4-d9#p7IMl%F$6nkd0ygkV|YlCihF~at~z9 zcL<8M?$`G}#%GKTbThZtnQ_9Uk=JC}BLh$*LHD0s4Lxd>Z%5;1EMlZr4fkCE@>W{V zFj1FY8f0lv-ac9BF4(d%YIWt&ik$*6*fpeayMc*f0$nCZKBpwlLQ2Wl89Q+ZFHOT~ zyRZRpP4lIT4$!d6$;^R=oB=?{=&23~UtSc&I_QL!oO>^;KE5Zs1y}^Yeo$nOl;Y;O zTdu*|y6X#ZEsGmlW`?w1M@SPk+p%GN+;vg9acnnOwigOXKF-b)nXk8Ln(yQcJ)Ze- z^bXQ(E<>HC>OxPsk#`>J?X~XAxB_}@2vfp@dN!{D#j5c#y3|NZtBB|9NZy+r$` zr}!o#5MwsRBSs^we2!j=s}g>F=NMM%W|y>idmb!BNd?Om0}K~eiOV*iuzF;ta?yrA zr25BBIah31bLnu{2$^-P*Vtsi&+V)KpUF#YEvifSaKzU!JN{p2>lywLnA?D`8f{n> zUB6L+xK!m1z0QA#pdg(B0Fi$faXkhsn=3&H6kFtQx1mCNH=-x6l*MXcH8n8IYMo5m zf6oI=x82XA9C%*w276i7z{ME@-QV(4rqtcuIYN}+TdeTZ6f%ak_FEWaRjp{{biJPw zW|tT_qtEZQ>@(;RC*O>B_~9%7AD`k}1>>b}00!AkS$zfqRf-hxk+k47ltr}BDbwfm jD;sZ%>*+{^-0}c{=BrKLzw`7z82ewW{XdS<-~aqKj|Fhi literal 0 HcmV?d00001 diff --git a/docs/source/manual/images/uvcdat.png b/docs/source/manual/images/uvcdat.png new file mode 100644 index 0000000000000000000000000000000000000000..75c1cf72d8c2a3938c550b1c938bbf7bf4957667 GIT binary patch literal 37672 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 literal 0 HcmV?d00001 From 441d972243eca8e61a5328f49ebd25a448668765 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 11 Oct 2017 17:34:37 -0700 Subject: [PATCH 017/239] flake8 python files --- Lib/MV2.py | 2 +- Lib/__init__.py | 2 +- Lib/avariable.py | 68 +++++++------- Lib/axis.py | 87 ++++++++++------- Lib/bindex.py | 2 +- Lib/cdmsobj.py | 68 ++++++++------ Lib/convention.py | 8 +- Lib/dataset.py | 214 ++++++++++++++++++++++-------------------- Lib/gengrid.py | 3 +- Lib/grid.py | 2 +- Lib/gsTimeVariable.py | 2 +- Lib/selectors.py | 4 +- Lib/tvariable.py | 6 +- 13 files changed, 254 insertions(+), 214 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 16ee25a6..6cd37605 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -5,7 +5,7 @@ import numpy from numpy import character, float, float32, float64 # noqa from numpy import int, int8, int16, int32, int64, byte # noqa -from numpy import ubyte, uint8, uint16, uint32, uint64, long # noqa +from numpy import ubyte, uint8, uint16, uint32, uint64, long # noqa from numpy.ma import allclose, allequal, common_fill_value # noqa from numpy.ma import make_mask_none, dot, filled # noqa from numpy.ma import getmask, getmaskarray, identity # noqa diff --git a/Lib/__init__.py b/Lib/__init__.py index 8a0c7e76..23c2a595 100644 --- a/Lib/__init__.py +++ b/Lib/__init__.py @@ -14,7 +14,7 @@ "mvBaseWriter", "mvSphereMesh", "mvVsWriter", "mvCdmsRegrid"] # Errors -from .error import CDMSError # noqa +from .error import CDMSError # noqa # CDMS datatypes from .cdmsobj import CdArray, CdChar, CdByte, CdDouble, CdFloat, CdFromObject, CdInt, CdLong, CdScalar, CdShort, CdString # noqa diff --git a/Lib/avariable.py b/Lib/avariable.py index 2e5619bf..c2e35720 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -40,7 +40,7 @@ def getMinHorizontalMask(var): Parameters ---------- - var + var CDMS variable with a mask Return @@ -171,7 +171,7 @@ def __call__(self, *args, **kwargs): grid: if given, result is regridded ont this grid. order: - if given, result is permuted into this order + if given, result is permuted into this order Returns ------- @@ -264,7 +264,7 @@ def _returnArray(self, ar, squeeze, singles=None): return result def generateGridkey(self, convention, vardict): - """Determine if the variable is gridded. + """Determine if the variable is gridded. Parameters ---------- @@ -416,7 +416,7 @@ def getAxis(self, n): """Get the n-th axis. Parameters ---------- - n: + n: Axis number Returns ------- @@ -458,11 +458,11 @@ def hasCellData(self): def getAxisListIndex(self, axes=None, omit=None, order=None): """Return a list of indices of axis objects; - + Note ---- If axes is **not** `None`, include only certain axes. - less the ones specified in omit. + less the ones specified in omit. If axes is `None`, use all axes of this variable. @@ -471,7 +471,7 @@ def getAxisListIndex(self, axes=None, omit=None, order=None): return axisMatchIndex(self.getAxisList(), axes, omit, order) def getAxisList(self, axes=None, omit=None, order=None): - """Get the list of axis objects; + """Get the list of axis objects; Note ---- @@ -489,7 +489,7 @@ def getAxisIds(self): """Get a list of axis identifiers. Returns - ------- + ------- array list of axis ids""" return [x[0].id for x in self.getDomain()] @@ -503,9 +503,9 @@ def getMissing(self, asarray=0): Parameters ---------- asarray : - '0' : scalar + '0' : scalar '1' : numpy array - Return + Return ------ the missing value as a scalar, or as a numpy array if asarray==1""" @@ -537,12 +537,12 @@ def _setmissing(self, name, value): self.setMissing(value) def setMissing(self, value): - """Set the missing value. + """Set the missing value. Parameters ---------- - value - scalar, a single-valued numpy array, or None. + value + scalar, a single-valued numpy array, or None. Note ---- @@ -569,7 +569,7 @@ def setMissing(self, value): [numpy.ma.default_fill_value(self)], selftype) # '?' for Boolean and object elif isinstance(value, (str, numpy.string_, numpy.str, - numpy.string0, numpy.str_)) and selftype in ['?', 'c', 'O', 'S']: + numpy.string0, numpy.str_)) and selftype in ['?', 'c', 'O', 'S']: pass else: raise CDMSError('Invalid missing value %s' % repr(value)) @@ -610,7 +610,7 @@ def getForecast(self): return self.getForecastTime() def getLevel(self): - """Get the first vertical level dimension in the domain. + """Get the first vertical level dimension in the domain. Returns ------- @@ -679,7 +679,7 @@ def getOrder(self, ids=0): ---------- id: 0 or 1 - returns + returns ------- the order string, such as t, z, y, x (time, level, lat, lon). @@ -687,12 +687,12 @@ def getOrder(self, ids=0): ---- * if ids == 0 (the default) for an axis that is not t,z,x,y the order string will contain a (-) character in that location. - The result string will be of the same length as the number + The result string will be of the same length as the number of axes. This makes it easy to loop over the dimensions. * if ids == 1 those axes will be represented in the order string as (id) where id is that axis' id. The result will - be suitable for passing to order2index to get the + be suitable for passing to order2index to get the corresponding axes, and to orderparse for dividing up into components. """ @@ -807,7 +807,7 @@ def subSlice(self, *specs, **keys): def getSlice(self, *specs, **keys): """getSlice takes arguments of the following forms and produces - a return array. + a return array. Parameter --------- @@ -818,12 +818,12 @@ def getSlice(self, *specs, **keys): grid: if given, result is regridded ont this grid. order: - if given, result is permuted into this order + if given, result is permuted into this order numericSqueeze: if index slice is given, eliminate that dimension. isitem: if given, result is return as a scaler for 0-D data - + Note ---- @@ -833,7 +833,7 @@ def getSlice(self, *specs, **keys): #. an instance of the slice class #. a tuple, which will be used as arguments to create a slice #. `None` or `:`, which means a slice covering that entire dimension - #. Ellipsis (...), which means to fill the slice list with `:` + #. Ellipsis (...), which means to fill the slice list with `:` leaving only enough room at the end for the remaining positional arguments There can be keyword arguments of the form key = value, where @@ -876,15 +876,18 @@ def getRegion(self, *specs, **keys): * (x, y) * Map the half-open coordinate interval [x,y) to index interval. * (x, y, 'cc') - * Map the closed interval [x,y] to index interval. Other options are 'oo' (open), 'oc' (open on the left), and 'co' (open on the right, the default). + * Map the closed interval [x,y] to index interval. Other options + are 'oo' (open), 'oc' (open on the left), and 'co' + (open on the right, the default). * (x, y, 'co', cycle) - * Map the coordinate interval with wraparound. If no cycle is specified, wraparound will occur iff axis.isCircular() is true. + * Map the coordinate interval with wraparound. If no cycle is + specified, wraparound will occur iff axis.isCircular() is true. Ellipsis Represents the full range of all dimensions bracketed by non-Ellipsis items. None, colon Represents the full range of one dimension. - Note + Note ---- Only one dimension may be wrapped. @@ -1362,9 +1365,10 @@ def pressureRegrid(self, newLevel, missing=None, order=None, method="log"): ---------- newLevel : is an axis of the result pressure levels. - method : - is optional, either `log` to interpolate in the log of pressure (default), or `linear` for linear interpolation. - missing and order : + method : + is optional, either `log` to interpolate in the log of pressure (default), + or `linear` for linear interpolation. + missing and order : are as for regrid.PressureRegridder. """ @@ -1386,7 +1390,7 @@ def crossSectionRegrid(self, newLevel, newLatitude, ----------- newLevel : is an axis of the result pressure levels. - newLatitude : + newLatitude : is an axis of latitude values. method : Optional either "log" to interpolate in the log of pressure (default), @@ -1642,7 +1646,7 @@ def isEncoded(self): return (hasattr(self, "scale_factor") or hasattr(self, "add_offset")) def decode(self, ar): - """Decode compressed data. + """Decode compressed data. Parameter --------- @@ -1912,5 +1916,5 @@ def order2index(axes, order): return permutation -from .tvariable import TransientVariable # noqa -from . import MV2 as MV # noqa +from .tvariable import TransientVariable # noqa +from . import MV2 as MV # noqa diff --git a/Lib/axis.py b/Lib/axis.py index 4c1f9997..a8275acd 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -20,7 +20,7 @@ from . import forecast import warnings standard_library.install_aliases() -from collections import UserList # noqa +from collections import UserList # noqa _debug = 0 std_axis_attributes = ['name', 'units', 'length', 'values', 'bounds'] @@ -203,12 +203,15 @@ def mapLinearIntersection(xind, yind, iind, j Returns ------- - True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: + True if the coordinate interval (a,b) intersects the node nodeSubI or cell + bounds [boundLeft,boundRight], where the interval (a,b) is defined by: * aMinusEps,aPlusEps = a +/- epsilon * bPlusEps,bMinusEps = b +/- epsilon - and the intersection option iind = 'n','b','e','s' specifies whether the intersection is with respect to the node value nodeSubI ('n' or 'e') or the cell bounds [boundLeft,boundRight]. + and the intersection option iind = 'n','b','e','s' specifies whether + the intersection is with respect to the node value nodeSubI ('n' or 'e') + or the cell bounds [boundLeft,boundRight]. See Also -------- @@ -258,10 +261,11 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', 'b' - the interval intersects the cell bounds 's' - the cell bounds are a subset of the interval 'e' - same as 'n', plus an extra node on either side. - - Returns + + Returns ------- - The corresponding index interval (i,j), where i ar[index], index==len(ar) @@ -664,18 +668,18 @@ def isOverlapVector(vec1, vec2, atol=1.e-8): """ Parameters ---------- - vec1: + vec1: Input arrays to compare vec2: Input arrays to compare atol: float, optional Absolute tolerance, The absolute differenc is equal to **atol** Default is 1e-8 - Returns + Returns ------- (isoverlap, index) : where isoverlap is true if a leading portion of vec1 is a subset of vec2; - * index is the index such that vec1[0] <= vec2[index] + * index is the index such that vec1[0] <= vec2[index] * If indexl == len(vec2), then vec1[0] > vec2[len(vec2) - 1] """ index = lookupArray(vec2, vec1[0]) @@ -708,16 +712,16 @@ def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): See Also -------- all, any - + Examples -------- >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) >>> a - masked_array(data = [10000000000.0 1e-07 --], + masked_array(data = [10000000000.0 1e-07 --], mask = [False False True], fill_value = 1e+20) >>> b = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) - >>> ma.allclose(a, b) + >>> ma.allclose(a, b) False """ return ((ax1 is ax2) or numpy.ma.allclose( @@ -1262,8 +1266,8 @@ def mapInterval(self, interval, indicator='ccn', cycle=None): and the coordinate interval is [-5,5), the return index interval is [178,183). This is equivalent to the two intervals [178,180) and [0,3). -.. note:: - if the interval is interior to the axis, but does not span any axis element, +.. note:: + if the interval is interior to the axis, but does not span any axis element, a singleton (i,i+1) indicating an adjacent index is returned. """ i, j, k = self.mapIntervalExt(interval, indicator, cycle) @@ -2425,9 +2429,9 @@ def isVirtual(self): # Functions for selecting axes -######## Functions for selecting axes +# Functions for selecting axes def axisMatchAxis(axes, specifications=None, omit=None, order=None): - """Match a list of axes following a specification or list of + """Match a list of axes following a specification or list of specificatons, and a specification or list of specifications of those axes to omit. @@ -2436,50 +2440,60 @@ def axisMatchAxis(axes, specifications=None, omit=None, order=None): specifications: * is None, include all axes less the omitted ones. - * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. omit: * is None, do not omit any axis. - * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - order: - * A string containing the symbols `t,x,y,z` or `-`. If a `-` is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is + given, any elements of the result not chosen otherwise are filled + in from left to right with remaining candidates. Return ------ - A list of axes that match the specification omitting any axes that matches an omit specification. + A list of axes that match the specification omitting any axes that matches + an omit specification. - Axes are returned in the order they occur in the axes argument unless order is given. + Axes are returned in the order they occur in the axes argument unless order is given. """ return [axes[i] for i in axisMatchIndex(axes, specifications, omit, order)] + def axisMatchIndex(axes, specifications=None, omit=None, order=None): - """Match a list of axes following a specification or list of + """Match a list of axes following a specification or list of specificatons, and a specification or list of specifications - of those axes to omit. + of those axes to omit. Parameters ---------- specifications: * is None, include all axes less the omitted ones. - * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. omit: * is None, do not omit any axis. - * Individual specifications must be integer indices into axes or matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - order: - * A string containing the symbols `t,x,y,z` or `-`. If a `-` is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is + given, any elements of the result not chosen otherwise are filled + in from left to right with remaining candidates. Return ------ A list of axis' indices which match the specification omitting any axes that matches an omit specification. - Axes are returned in the order they occur in the axes argument unless order is given. + Axes are returned in the order they occur in the axes argument unless order is given. """ if specifications is None: @@ -2607,7 +2621,8 @@ def axisMatches(axis, specification): ---- Specification must be one of: - #. a string representing an axis id or one of the keywords time, fctau0, latitude or lat, longitude or lon, or lev or level. + #. a string representing an axis id or one of the keywords time, + fctau0, latitude or lat, longitude or lon, or lev or level. #. Axis may be surrounded with parentheses or spaces. @@ -2619,7 +2634,7 @@ def axisMatches(axis, specification): * if the value returned is true, the axis matches. #. an axis object; will match if it is the same object as axis. - """ + """ if isinstance(specification, str): s = specification.lower() s = s.strip() @@ -2671,7 +2686,7 @@ def concatenate(axes, id=None, attributes=None): Returns ------- Transient axis.""" - + data = numpy.ma.concatenate([ax[:] for ax in axes]) boundsArray = [ax.getBounds() for ax in axes] if any(elem is None for elem in boundsArray): @@ -2685,7 +2700,7 @@ def take(ax, indices): """Take elements form an array along an axis Parameters ---------- - ax: + ax: The source array. indices: The indices of the values to extract. diff --git a/Lib/bindex.py b/Lib/bindex.py index 290af337..df14ead0 100644 --- a/Lib/bindex.py +++ b/Lib/bindex.py @@ -17,7 +17,7 @@ def bindexHorizontalGrid(latlin, lonlin): latlon: lonlin is the raveled longitude values. - Returns + Returns ------- resulting index. """ diff --git a/Lib/cdmsobj.py b/Lib/cdmsobj.py index 4df4cf44..524e49be 100644 --- a/Lib/cdmsobj.py +++ b/Lib/cdmsobj.py @@ -556,20 +556,23 @@ def __init__(self, node=None): self.attributes[attname] = attval def searchone(self, pattern, attname): - """Search if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or + """Search if the attribute with name attname is a string attribute which + contains the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute. Parameters ---------- - pattern: + pattern: (str) pattern - attname: + attname: (str/None) attribute name - + Returns ------- - result: (int/True/False) - * 1 or True if the attribute with name attname is a string attribute which contains the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute, + result: (int/True/False) + * 1 or True if the attribute with name attname is a string + attribute which contains the compiled regular expression pattern, + or if attname is None and pattern matches at least one string attribute, * 0 or False if the attribute is not found or is not a string """ if attname is None: @@ -591,8 +594,9 @@ def searchone(self, pattern, attname): # attribute. Return false if the attribute is not found or is not a string def matchone(self, pattern, attname): """ - Search if the attribute with name attname is a string attribute which matches the compiled regular expression pattern, or - if attname is None and pattern matches at least one string attribute. + Search if the attribute with name attname is a string attribute which matches + the compiled regular expression pattern, or + if attname is None and pattern matches at least one string attribute. Parameters ---------- @@ -601,8 +605,10 @@ def matchone(self, pattern, attname): Returns ------- - result: (int/True/False) - * True if the attribute with name attname is a string attribute which matches the compiled regular expression pattern, or if attname is None and pattern matches at least one string attribute. + result: (int/True/False) + * True if the attribute with name attname is a string attribute which + matches the compiled regular expression pattern, or if attname is None + and pattern matches at least one string attribute. * False if the attribute is not found or is not a string. """ if attname is None: @@ -623,21 +629,22 @@ def matchone(self, pattern, attname): # internal node tag. def searchPattern(self, pattern, attribute, tag): """ - Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. + Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. + If tag is not None, it must match the internal node tag. Parameters ---------- - pattern: (str) + pattern: (str) - attribute: (str/None) + attribute: (str/None) attribute name - tag: (str/None) + tag: (str/None) node tag Returns ------- - result: (list) + result: (list) """ if tag is None or string.lower(tag) == self._node_.tag: @@ -653,19 +660,20 @@ def searchPattern(self, pattern, attribute, tag): # internal node tag. def matchPattern(self, pattern, attribute, tag): """ - Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. + Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. + If tag is not None, it must match the internal node tag. Parameters ---------- - pattern: (str) + pattern: (str) pattern - attribute: (str/None) + attribute: (str/None) attribute name - tag: (str/None) + tag: (str/None) node tag Results ------- - result: (list) + result: (list) """ if tag is None or string.lower(tag) == self._node_.tag: @@ -681,17 +689,19 @@ def matchPattern(self, pattern, attribute, tag): # If the predicate returns false, return an empty list def searchPredicate(self, predicate, tag): """ - Apply a truth-valued predicate. + Apply a truth-valued predicate. Parameters ---------- - predicate: (function) - tag: (str/None) + predicate: (function) + tag: (str/None) node tag Returns ------- - result: (list) - * Return a list containing a single instance: [self] if the predicate is true and either tag is None or matches the object node tag. If the predicate returns false, return an empty list + result: (list) + * Return a list containing a single instance: [self] if the + predicate is true and either tag is None or matches the + object node tag. If the predicate returns false, return an empty list """ if tag is None or string.lower(tag) == self._node_.tag: try: @@ -712,18 +722,18 @@ def dump(self, path=None, format=1): Parameters ---------- - path: (None) + path: (None) result file name, None for standard output. - format: (int) + format: (int) 1 if the file is formatted with newlines for readability. Returns ------- - None: (None) + None: (None) nothing returned """ if self._node_ is None: - raise CDMSError("No tree node found") # noqa + raise CDMSError("No tree node found") # noqa self._node_.dump(path, format) def _getinternals(self): diff --git a/Lib/convention.py b/Lib/convention.py index 7653d0a0..dab50e1e 100644 --- a/Lib/convention.py +++ b/Lib/convention.py @@ -205,8 +205,8 @@ def axisIsLatitude(self, axis): if (hasattr(axis, 'axis') and axis.axis == 'Y'): return True elif (hasattr(axis, 'units') and axis.units.lower() in [ - 'degrees_north', 'degree_north', 'degree_n', 'degrees_n', 'degreen', 'degreesn'] and - not (axis.isLongitude() or axis.isLevel() or axis.isTime())): + 'degrees_north', 'degree_north', 'degree_n', 'degrees_n', 'degreen', 'degreesn'] and + not (axis.isLongitude() or axis.isLevel() or axis.isTime())): return True elif (hasattr(axis, 'standard_name') and axis.standard_name.lower() == 'latitude'): return True @@ -217,8 +217,8 @@ def axisIsLongitude(self, axis): if (hasattr(axis, 'axis') and axis.axis == 'X'): return True elif (hasattr(axis, 'units') and axis.units.lower() in [ - 'degrees_east', 'degree_east', 'degree_e', 'degrees_e', 'degreee', 'degreese'] and - not (axis.isLatitude() or axis.isLevel() or axis.isTime())): + 'degrees_east', 'degree_east', 'degree_e', 'degrees_e', 'degreee', 'degreese'] and + not (axis.isLatitude() or axis.isLevel() or axis.isTime())): return True elif (hasattr(axis, 'standard_name') and axis.standard_name.lower() == 'longitude'): return True diff --git a/Lib/dataset.py b/Lib/dataset.py index d738a985..353d3ed7 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -151,7 +151,7 @@ def setNetcdfUseNCSwitchModeFlag(value): ---------- value: 0/1, False/True. - + Returns ------- No return value. @@ -231,7 +231,7 @@ def setNetcdf4Flag(value): ------- No return value. """ - if value not in [True,False,0,1]: + if value not in [True, False, 0, 1]: raise CDMSError("Error NetCDF4 flag must be 1/0 or true/False") if value in [0, False]: Cdunif.CdunifSetNCFLAGS("netcdf4", 0) @@ -239,7 +239,7 @@ def setNetcdf4Flag(value): Cdunif.CdunifSetNCFLAGS("netcdf4", 1) -def setNetcdfClassicFlag(value): +def setNetcdfClassicFlag(value): """Enable netCDF3 (classic) mode in libnetcdf. Parameters @@ -251,7 +251,7 @@ def setNetcdfClassicFlag(value): ------- No return value. """ - if value not in [True,False,0,1]: + if value not in [True, False, 0, 1]: raise CDMSError("Error NetCDF Classic flag must be 1/0 or true/False") if value in [0, False]: Cdunif.CdunifSetNCFLAGS("classic", 0) @@ -259,7 +259,7 @@ def setNetcdfClassicFlag(value): Cdunif.CdunifSetNCFLAGS("classic", 1) -def setNetcdfShuffleFlag(value): +def setNetcdfShuffleFlag(value): """Enable/Disable NetCDF shuffle. Parameters @@ -270,7 +270,7 @@ def setNetcdfShuffleFlag(value): ------- No return value. """ - if value not in [True,False,0,1]: + if value not in [True, False, 0, 1]: raise CDMSError("Error NetCDF Shuffle flag must be 1/0 or true/False") if value in [0, False]: Cdunif.CdunifSetNCFLAGS("shuffle", 0) @@ -289,7 +289,7 @@ def setNetcdfDeflateFlag(value): ------- No return value. """ - if value not in [True,False,0,1]: + if value not in [True, False, 0, 1]: raise CDMSError("Error NetCDF deflate flag must be 1/0 or true/False") if value in [0, False]: Cdunif.CdunifSetNCFLAGS("deflate", 0) @@ -340,14 +340,14 @@ def getNetcdfUseParallelFlag(): def getNetcdf4Flag(): - """Returns + """Returns ------- NetCDF4 flag value.""" return Cdunif.CdunifGetNCFLAGS("netcdf4") def getNetcdfClassicFlag(): - """Returns + """Returns ------- NetCDF classic flag value.""" return Cdunif.CdunifGetNCFLAGS("classic") @@ -368,7 +368,7 @@ def getNetcdfDeflateFlag(): def getNetcdfDeflateLevelFlag(): - """Returns + """Returns ------- NetCDF deflate level flag value.""" return Cdunif.CdunifGetNCFLAGS("deflate_level") @@ -418,21 +418,23 @@ def loadURI(uri): # Create a dataset # 'path' is the XML file name, or netCDF filename for simple file create # 'template' is a string template for the datafile(s), for dataset creation -def createDataset(path,template=None): + + +def createDataset(path, template=None): """Create a dataset. Parameters ---------- path: is the XML file name, or netCDF filename for simple file creation. - template: + template: is a string template for the datafile(s), for dataset creation. Returns ------- writing file handle. """ - return openDataset(path,'w',template) + return openDataset(path, 'w', template) # Open an existing dataset @@ -446,19 +448,19 @@ def openDataset(uri, mode='r', template=None, """ Parameters ---------- - uri: (str) + uri: (str) Filename to open - mode: (str) + mode: (str) Either `r`,`w`,`a` mode to open the file in read/write/append - template: + template: A string template for the datafile(s), for dataset creation - dods: (int) + dods: (int) Default set to 1 dpath: (str) Destination path. Returns ------- - file handle. + file handle. """ uri = uri.strip() (scheme, netloc, path, parameters, query, fragment) = urlparse(uri) @@ -662,21 +664,21 @@ def parseVarMap(text): def parseFileMap(text): - """Parse a CDMS filemap. + """Parse a CDMS filemap. Parameters ---------- - filemap: + filemap: list [ varmap, varmap, ...] - varmap: + varmap: list [ namelist, slicelist ] - namelist: + namelist: list [name, name, ...] - slicelist: + slicelist: list [indexlist, indexlist, ,,,] - indexlist: + indexlist: list [i,j,k,l,path] - + Returns ------- Parsing results. @@ -1463,7 +1465,7 @@ def sync(self): """ Syncs the file on disk. """ - if self._status_=="closed": + if self._status_ == "closed": raise CDMSError(FileWasClosed + self.id) self._file_.sync() @@ -1503,7 +1505,7 @@ def createAxis(self, name, ar, unlimited=0): is the string name of the Axis ar: numpy.ndarray/None is the 1-D data array, or None for an unlimited axis - unlimited: (int/True/False) + unlimited: (int/True/False) True/0 designate that the axis as unlimited. Returns @@ -1549,17 +1551,17 @@ def createVirtualAxis(self, name, axislen): Parameters ---------- - name: + name: is the string name of the axis. - axislen: + axislen: is the integer length of the axis. Returns ------- - axis: + axis: file axis whose id is name (cdms2.axis.FileVirtualAxis) - Note + Note ---- For netCDF output, this just creates a dimension without the associated coordinate array. On reads the axis will look like @@ -1582,15 +1584,15 @@ def copyAxis(self, axis, newname=None, unlimited=0, Parameters ---------- - axis: - axis to copy (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) - newname: (None/str) + axis: + axis to copy (cdms2.axis.FileAxis/cdms2.axis.FileVirtualAxis) + newname: (None/str) new name for axis (default None) - unlimited: (int/True/False) + unlimited: (int/True/False) unlimited dimension (default 0) - index: (int/None) + index: (int/None) (default None) - extbounds: (numpy.ndarray) + extbounds: (numpy.ndarray) new bounds to use bounds (default None) Returns @@ -1660,17 +1662,17 @@ def createRectGrid(self, id, lat, lon, order, type="generic", mask=None): Parameters ---------- - id: (str) + id: (str) grid name (default 0) - lat: (numpy.ndarray) - latitude array (default 1) - lon: (numpy.ndarray) + lat: (numpy.ndarray) + latitude array (default 1) + lon: (numpy.ndarray) longitude array (default 2) - order: (str) + order: (str) order (default 3) - type: (str) + type: (str) grid type (defalut `generic`) - mask: (None/numpy.ndarray) + mask: (None/numpy.ndarray) mask (default None) Returns @@ -1691,14 +1693,14 @@ def copyGrid(self, grid, newname=None): Parameters ---------- - newname: (str/None) + newname: (str/None) new name for grid (default None) - grid: - file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + grid: + file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) Returns ------- - file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) """ if newname is None: @@ -1756,8 +1758,8 @@ def createVariable(self, name, datatype, axesOrGrids, fill_value=None): The string name of the Variable datatype: A CDMS datatype or numpy typecode - axesOrGrids: - is a list of axes, grids. + axesOrGrids: + is a list of axes, grids. fill_value: fill_value (cast into data type). @@ -1809,17 +1811,18 @@ def createVariable(self, name, datatype, axesOrGrids, fill_value=None): # is None, search the dataset and all objects contained in it. def searchPattern(self, pattern, attribute, tag): """ - Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. + Search for a pattern in a string-valued attribute. If attribute is None, search all string attributes. + If tag is not None, it must match the internal node tag. Parameters ---------- - pattern: + pattern: expression pattern - attribute: + attribute: attribute name - tag: + tag: node tag - + Returns ------- list of match pattern @@ -1850,16 +1853,18 @@ def searchPattern(self, pattern, attribute, tag): # is None, search the dataset and all objects contained in it. def matchPattern(self, pattern, attribute, tag): """ - Match for a pattern in a string-valued attribute. If attribute is None, search all string attributes. If tag is not None, it must match the internal node tag. + Match for a pattern in a string-valued attribute. If attribute is None, + search all string attributes. If tag is not None, it must match the internal node tag. Parameters ---------- - pattern: + pattern: String expression. - attribute: + attribute: Attribute Name. If `None` search all attributre. - tag: - node tag, if `cdmsFile` only match the current dataset otherwise match all object matching the tag. + tag: + node tag, if `cdmsFile` only match the current dataset otherwise match + all object matching the tag. Returns ------- @@ -1894,19 +1899,19 @@ def matchPattern(self, pattern, attribute, tag): # the dataset itself. def searchPredicate(self, predicate, tag): """ - Apply a truth-valued predicate. + Apply a truth-valued predicate. Parameters ---------- - predicate: + predicate: function use as predicate - tag: + tag: node tag. Returns ------- - List containing a single instance - [self] if the predicate is true and either tag is None or matches the object node tag. + List containing a single instance + [self] if the predicate is true and either tag is None or matches the object node tag. Empty list If the predicate returns false. """ @@ -1948,24 +1953,26 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds Parameters ---------- var: - variable to copy (cdms2.tvariable.TransientVariable or cdms2.fvariable.FileVariable) - attributes: + variable to copy (cdms2.tvariable.TransientVariable or cdms2.fvariable.FileVariable) + attributes: A dictionary of attributes. Default is var.attributes. - axes: + axes: The list of axis objects. Default is var.getAxisList() - extbounds: + extbounds: Bounds of the (portion of) the extended dimension being written. - id or newname: + id or newname: String identifier of the new variable. - extend: - * 1 define the first dimension as the unlimited dimension. - * 0 do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. + extend: + * 1 define the first dimension as the unlimited dimension. + * 0 do not define an unlimited dimension. The default is the define + the first dimension as unlimited only if it is a time dimension. fill_value: The missing value flag. index: - The extended dimension index for writting. The default index is determined by lookup relative to the existing extended dimension. + The extended dimension index for writting. The default index is determined + by lookup relative to the existing extended dimension. grid: - Tthe variable grid. `none` the value of var.getGrid() will used. + The variable grid. `none` the value of var.getGrid() will used. Returns ------- @@ -2086,11 +2093,11 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds def write(self, var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None, dtype=None, pack=False): - """Write var to the file. + """Write var to the file. Note ---- - If the variable is not yet defined in the file, a definition is created. + If the variable is not yet defined in the file, a definition is created. By default, the time dimension of the variable is defined as the `extended dimension` of the file. The function returns the corresponding file variable. @@ -2098,23 +2105,25 @@ def write(self, var, attributes=None, axes=None, extbounds=None, id=None, ---------- var: variable to copy. - attributes: + attributes: The attribute dictionary for the variable. The default is var.attributes. - axes: + axes: The list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). - extbounds: + extbounds: The extended dimension bounds. Defaults to var.getAxis(0).getBounds(). - id: + id: The variable name in the file. Default is var.id. - extend: - * 1 causes the first dimension to be `extensible` iteratively writeable. The default is None, in which case the first dimension is extensible if it is time. + extend: + * 1 causes the first dimension to be `extensible` iteratively writeable. The default is None, + in which case the first dimension is extensible if it is time. * 0 to turn off this behaviour. fill_value: is the missing value flag. - index: - The extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. - dtype: + index: + The extended dimension index to write to. The default index is determined b + lookup relative to the existing extended dimension. + dtype: The numpy dtype. - typecode: + typecode: Deprecated, for backward compatibility only Returns ------- @@ -2259,18 +2268,18 @@ def write(self, var, attributes=None, axes=None, extbounds=None, id=None, def write_it_yourself(self, obj): """Tell obj to write itself to self (already open for writing), using its - writeg method (AbstractCurveGrid has such a method, for example). + writeg method (AbstractCurveGrid has such a method, for example). Note ---- - If `writeg` is not available, writeToFile will be used. + If `writeg` is not available, writeToFile will be used. If `writeToFile` is also not available, then `self.write(obj)` will be called to try to write obj as a variable. Parameters ---------- obj: - object containing `writeg`, `writeToFile` or `write` method. + object containing `writeg`, `writeToFile` or `write` method. Returns ------- Nothig is returned. """ @@ -2286,29 +2295,30 @@ def write_it_yourself(self, obj): def getVariable(self, id): """ Get the variable object with the given id. Returns None if not found. - + Parameters ---------- - id: str + id: str id of the variable to get Returns ------- - variable (cdms2.fvariable.FileVariable/None) + variable (cdms2.fvariable.FileVariable/None) file variable """ return self.variables.get(id) def getVariables(self, spatial=0): - """Get a list of variable objects. + """Get a list of variable objects. Parameters ---------- - spatial: - If spatial=1 or True, only return those axes defined on latitude or longitude, excluding weights and bounds + spatial: + If spatial=1 or True, only return those axes defined on latitude + or longitude, excluding weights and bounds Returns - ------- + ------- file variable. """ retval = list(self.variables.values()) @@ -2326,11 +2336,11 @@ def getAxis(self, id): Parameters ---------- - id: + id: id of the axis to get Returns -------- - file axis + file axis """ return self.axes.get(id) @@ -2340,7 +2350,7 @@ def getGrid(self, id): Parameters ---------- - id: + id: id of the grid to get Returns @@ -2351,7 +2361,7 @@ def getGrid(self, id): def getBoundsAxis(self, n, boundid=None): """Get a bounds axis of length n. Create the bounds axis if necessary. - + Parameters ---------- n: @@ -2359,7 +2369,7 @@ def getBoundsAxis(self, n, boundid=None): Returns ------- - bounds axis + bounds axis """ if boundid is None: if n == 2: diff --git a/Lib/gengrid.py b/Lib/gengrid.py index f73396b2..d932203f 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -274,7 +274,8 @@ def reconcile(self, axes): result = self.clone() for i in missing: for item in axes: - if (len(selfaxes[i]) == len(item)) and allclose(selfaxes[i], item): + if (len(selfaxes[i]) == len(item)) and \ + allclose(selfaxes[i], item): result._lataxis_.setAxis(i, item) result._lonaxis_.setAxis(i, item) break diff --git a/Lib/grid.py b/Lib/grid.py index 2cc8b68b..c7db6fa6 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -13,7 +13,7 @@ from .axis import TransientAxis, createAxis, createUniformLatitudeAxis from .axis import createUniformLongitudeAxis, getAutoBounds from .axis import createGaussianAxis, isSubsetVector -from .axis import lookupArray # noqa +from .axis import lookupArray # noqa MethodNotImplemented = "Method not yet implemented" diff --git a/Lib/gsTimeVariable.py b/Lib/gsTimeVariable.py index 8376b8ba..011b2aad 100644 --- a/Lib/gsTimeVariable.py +++ b/Lib/gsTimeVariable.py @@ -382,7 +382,7 @@ def __getitem__(self, gridIndex): return self.vars[gridIndex] # ############################################################################## -# ############# DEPRECIATED - Testing required to fully remove ################# +# ############# DEPRECIATED - Testing required to fully remove ########### # ############################################################################## diff --git a/Lib/selectors.py b/Lib/selectors.py index f9e90ed1..59de3c6b 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -202,8 +202,8 @@ def unmodified_select(self, variable, raw=0, raw != 0 or \ result is variable: # result is variable when there are no components, for example. - return result.subRegion(squeeze=squeeze, order=order, - grid=grid, raw=raw) + return result.subRegion(squeeze=squeeze, order=order, + grid=grid, raw=raw) else: return result diff --git a/Lib/tvariable.py b/Lib/tvariable.py index e92b4ffc..eb749243 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -220,7 +220,7 @@ def __init__(self, data, typecode=None, copy=1, savespace=0, if id is not None: # convert unicode to string if sys.version_info < (3, 0, 0): - if isinstance(id, unicode): # noqa + if isinstance(id, unicode): # noqa id = str(id) if not isinstance(id, str): raise CDMSError('id must be a string') @@ -509,7 +509,7 @@ def setdimattribute(self, dim, field, value): d = self.getAxis(dim) if field == "name": if sys.version_info < (3, 0, 0): - if isinstance(value, unicode): # noqa + if isinstance(value, unicode): # noqa value = str(value) if not isinstance(value, str): raise CDMSError("setdimattribute: name not a string") @@ -525,7 +525,7 @@ def setdimattribute(self, dim, field, value): elif field == "units": if sys.version_info < (3, 0, 0): - if isinstance(value, unicode): # noqa + if isinstance(value, unicode): # noqa value = str(value) if not isinstance(value, str): raise CDMSError("setdimattribute: units not a string") From d1db05f91c5e016b0305c6dc26872ef2de19e8b2 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 17 Oct 2017 18:18:52 -0700 Subject: [PATCH 018/239] chapter 4 regridding --- docs/source/manual/cdms_4.rst | 619 ++++++++++++---------------------- 1 file changed, 211 insertions(+), 408 deletions(-) diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index a5d22d7c..b07efaa1 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -22,25 +22,28 @@ variable regridded to the target grid: .. doctest:: + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" >>> import cdms2 - >>> f = cdms2.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') - >>> rlsf = f('rls') # Read the data - >>> rlsf.shape - (4, 48, 96) - >>> g = cdms2.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') - >>> rlsg = g['rls'] # Get the file variable (no data read) - >>> outgrid = rlsg.getGrid() # Get the target grid - >>> rlsnew = rlsf.regrid(outgrid) - >>> rlsnew.shape - (4, 46, 72) + >>> import cdat_info + >>> f1=cdms2.open("clt.nc") + >>> f2=cdms2.open("geos5-sample.nc") + >>> clt=f1('clt') # Read the data + >>> clt.shape + (120, 46, 72) + >>> ozone=f2['ozone'] # Get the file variable (no data read) + >>> outgrid = ozone.getGrid() # Get the target grid + >>> cltnew = clt.regrid(outgrid) + >>> cltnew.shape + (120, 181, 360) >>> outgrid.shape - (46, 72) + (181, 360) A somewhat more efficient method is to create a regridder function. This has the advantage that the mapping is created only once and can be used for multiple arrays. Also, this method can be used with data in the form -of an MA.MaskedArray or Numeric array. The steps in this process are: +of an MA.MaskedArray. The steps in this process are: #. Given an input grid and output grid, generate a regridder function. #. Call the regridder function on a Numeric array, resulting in an array @@ -50,20 +53,19 @@ of an MA.MaskedArray or Numeric array. The steps in this process are: The following example illustrates this process. The regridder function is generated at line 9, and the regridding is performed at line 10: - .. doctest:: - >>> #!/usr/bin/env python - >>> import cdms - >>> from regrid import Regridder - >>> f = cdms.open('/pcmdi/cdms/exp/cmip2/ccc/perturb.xml') - >>> rlsf = f['rls'] - >>> ingrid = rlsf.getGrid() - >>> g = cdms.open('/pcmdi/cdms/exp/cmip2/mri/perturb.xml') - >>> outgrid = g['rls'].getGrid() + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> import cdms2 + >>> from regrid2 import Regridder + >>> f = cdms2.open("clt.nc") + >>> cltf = f['clt'] + >>> ingrid = cltf.getGrid() + >>> g = cdms2.open('geos5-sample.nc') + >>> outgrid = g['ozone'].getGrid() >>> regridfunc = Regridder(ingrid, outgrid) - - >>> rlsnew = regridfunc(rlsf) + >>> cltnew = regridfunc(cltf) >>> f.close() >>> g.close() @@ -71,24 +73,24 @@ is generated at line 9, and the regridding is performed at line 10: Notes ----- -**Line #2** Makes the CDMS module available. +**Line #3** Makes the CDMS module available. -**Line #3** Makes the Regridder class available from the regrid module. +**Line #4** Makes the Regridder class available from the regrid module. -**Line #4** Opens the input dataset. +**Line #5** Opens the input dataset. -**Line #5** Gets the variable object named ‘rls’. No data is read. +**Line #6** Gets the variable object named ‘clt’. No data is read. -**Line #6** Gets the input grid. +**Line #7** Gets the input grid. -**Line #7** Opens a dataset to retrieve the output grid. +**Line #8** Opens a dataset to retrieve the output grid. -**Line #8** The output grid is the grid associated with the variable named ‘rls’ in dataset g. Just the grid is retrieved, not the data. +**Line #9** The output grid is the grid associated with the variable named ‘ozone’ in dataset g. Just the grid is retrieved, not the data. -**Line #9** Generates a regridder function regridfunc. +**Line #10** Generates a regridder function regridfunc. -**Line #10** Reads all data for variable rlsf, and calls the regridder -function on that data, resulting in a transient variable rlsnew. +**Line #11** Reads all data for variable cltf, and calls the regridder +function on that data, resulting in a transient variable cltnew. 4.1.2 SCRIP horizontal regridder ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,22 +142,21 @@ In this example: :: &remap_inputs - num_maps = 1 - - grid1_file = 'remap_grid_T42.nc' - grid2_file = 'remap_grid_POP43.nc' - interp_file1 = 'rmp_T42_to_POP43_conserv.nc' - interp_file2 = 'rmp_POP43_to_T42_conserv.nc' - map1_name = 'T42 to POP43 Conservative Mapping' - map2_name = 'POP43 to T42 Conservative Mapping' - map_method = 'conservative' - normalize_opt = 'frac' - output_opt = 'scrip' - restrict_type = 'latitude' - num_srch_bins = 90 - luse_grid1_area = .false. - luse_grid2_area = .false. - / + num_maps = 1 + + grid1_file = 'remap_grid_T42.nc' + grid2_file = 'remap_grid_POP43.nc' + interp_file1 = 'rmp_T42_to_POP43_conserv.nc' + interp_file2 = 'rmp_POP43_to_T42_conserv.nc' + map1_name = 'T42 to POP43 Conservative Mapping' + map2_name = 'POP43 to T42 Conservative Mapping' + map_method = 'conservative' + normalize_opt = 'frac' + output_opt = 'scrip' + restrict_type = 'latitude' + num_srch_bins = 90 + luse_grid1_area = .false. + luse_grid2_area = .false. .. raw:: html @@ -193,41 +194,30 @@ generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ Next, run UV-CDAT and create the regridder: -.. raw:: html - -
- -:: - - # Import regrid package for regridder functions - import regrid, cdms - # Read the regridder from the remapper file - remapf = cdms.open('rmp_T42_to_POP43_conserv.nc') - regridf = regrid.readRegridder(remapf) - remapf.close() - -.. raw:: html +.. doctest:: -
+ >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # Import regrid package for regridder functions + >>> import regrid2, cdms2 + >>> # Read the regridder from the remapper file + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> remapf.close() Then read the input data and regrid: -.. raw:: html - -
- -:: - - # Get the source variable - f = cdms.open('sampleT42Grid.nc') - t42dat = f('src_array') - f.close() - # Regrid the source variable - popdat = regridf(dat) - -.. raw:: html +.. doctest:: -
+ >>> # Get the source variable + >>> f = cdms2.open('xieArkin-T42.nc') + >>> t42prc = f('prc') + >>> f.close() + >>> # Regrid the source variable + >>> popdat = regridf(t42prc) Note that ``t42dat`` can have rank greater than 2. The trailing dimensions must match the input grid shape. For example, if ``t42dat`` @@ -235,8 +225,8 @@ has shape (12, 64, 128), then the input grid must have shape (64,128). Similarly if the variable had a generic grid with shape (8092,), the last dimension of the variable would have length 8092. -.. rubric:: 4.1.3 Pressure-level regridder - :name: pressure-level-regridder +4.1.3 Pressure-level regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To regrid a variable which is a function of latitude, longitude, pressure level, and (optionally) time to a new set of pressure levels, @@ -244,25 +234,18 @@ use the ``pressureRegrid`` function defined for variables. This function takes an axis representing the target set of pressure levels, and returns a new variable ``d`` regridded to that dimension. -.. raw:: html - -
- -:: +.. doctest:: - >>> var.shape - (3, 16, 32) - >>> var.getAxisIds() - ['level', 'latitude', 'longitude'] - >>> len(levout) - 2 - >>> result = var.pressureRegrid(levout) + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") + >>> ta=f('ta') + >>> ta.shape + (11, 17, 73, 144) + >>> ta.getAxisIds() + ['time', 'level', 'latitude', 'longitude'] + >>> result = ta.pressureRegrid(cdms2.createAxis([1000.0])) >>> result.shape - (2, 16, 32) - -.. raw:: html - -
+ (11, 1, 73, 144) 4.1.4 Cross-section regridder ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -273,26 +256,22 @@ To regrid a variable which is a function of latitude, height, and arguments the new latitudes and heights, and returns the variable regridded to those axes. -.. raw:: html - -
- -:: +.. doctest:: - >>> varin.shape - (11, 46) - >>> varin.getAxisIds() - [’level’, ’latitude’] - >>> levOut[:] - [ 10., 30., 50., 70., 100., 200., 300., 400., 500., - 700., 850., 1000.,] - >>> varout = varin.crossSectionRegrid(levOut, latOut) - >>> varout.shape - (12, 64) + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") + >>> ta=f('ta') + >>> levOut=cdms2.createAxis([1000.0,950.]) + >>> latOut=ta.getLatitude()[10:20] + >>> ta.shape + (11, 17, 73, 144) + >>> ta0 = ta[0,:] + >>> ta0.getAxisIds() + ['level', 'latitude', 'longitude'] + >>> taout = ta0.crossSectionRegrid(levOut, latOut) + >>> taout.shape + (2, 10, 144) -.. raw:: html - -
4.2 regrid module ^^^^^^^^^^^^^^^^^ @@ -304,79 +283,46 @@ of CDMS, it is designed to work with CDMS objects. 4.2.1 CDMS horizontal regridder ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The Python command - -.. raw:: html - -
- -:: - - from regrid import Regridder - -.. raw:: html +.. doctest:: -
+ from regrid2 import Regridder makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. Table 4.1 CDMS Regridder Constructor -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------------------ -+-----------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+=====================================================+============================================================================================================================================================================================================================================================================================================================================+ -| regridFunction = Regridder(inputGrid, outputGrid) | Create a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function. | -+-----------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: REgridder Constructure + :header: "Constructor", "Description" + :widths: 50, 90 -.. rubric:: 4.2.2 SCRIP Regridder - :name: scrip-regridder + "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + +4.2.2 SCRIP Regridder +^^^^^^^^^^^^^^^^^^^^^ SCRIP regridder functions are created with the ``regrid.readRegridder`` function: Table 4.2 SCRIP Regridder Constructor -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -+--------------------------------------+--------------------------------------+ -| Constructor | Description | -+======================================+======================================+ -| :: | Read a regridder from an open CDMS | -| | file object. | -| regridFunction = regrid.readRegr | | -| idder(fileobj, mapMethod=None, check | ``fileobj`` is a CDMS file object, | -| Grid=1) | as returned from ``cdms.open``. | -| | | -| | ``mapMethod`` is one of | -| | | -| | - ``'conservative'``: conservative | -| | remapper, suitable where | -| | area-integrated fields such as | -| | water or heat fluxes must be | -| | conserved. | -| | - ``'bilinear'``: bilinear | -| | interpolation | -| | - ``'bicubic'``: bicubic | -| | interpolation | -| | - ``'distwgt'``: distance-weighted | -| | interpolation. | -| | | -| | It is only necessary to specify the | -| | map method if it is not defined in | -| | the file. | -| | | -| | If ``checkGrid``\ is 1 (default), | -| | the grid cells are checked for | -| | convexity, and 'repaired' if | -| | necessary. Grid cells may appear to | -| | be nonconvex if they cross a | -| | ``0 / 2pi`` boundary. The repair | -| | consists of shifting the cell | -| | vertices to the same side modulo 360 | -| | degrees. | -+--------------------------------------+--------------------------------------+ +------------------------------------- + +.. csv-table:: + :header: "Constructor", "Description" + :widths: 80, 90 + + "regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)", "Read a regridder from an open CDMS file object." + "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." + "", "``mapMethod`` is one of:" + "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." + "", "- ``'bilinear'``: bilinear interpolation" + "", "- ``'bicubic'``: bicubic interpolation" + "", "- ``'distwgt'``: distance-weighted interpolation." + "", "It is only necessary to specify the map method if it is not defined in the file." + "", "" + "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." 4.3 Regridder Functions ^^^^^^^^^^^^^^^^^^^^^^^ @@ -399,8 +345,8 @@ input array and returns the regridded array. However, when the array has missing data, or the input and/or output grids are masked, the logic becomes more complicated. -.. rubric:: Step 1: - :name: step-1 +Step 1 +------ The regridder function first forms an input mask. This mask is either two-dimensional or n-dimensional, depending on the rank of the @@ -421,8 +367,8 @@ is obtained from the data array mask if present. - If the user mask is 3 or 4-dimensional with the same shape as the input array, it is used as the input mask. -.. rubric:: Step 2: - :name: step-2 +Step 2 +------ The data is then regridded. In the two-dimensional case, the input mask is ‘broadcast’ across the other dimensions of the array. In other words, @@ -433,8 +379,8 @@ output array, defining the fractional area of the output array which overlaps a non-missing input grid cell. This is useful for calculating area-weighted means of masked data. -.. rubric:: Step 3: - :name: step-3 +Step 3 +------ Finally, if the output grid has a mask, it is applied to the result array. Where the output mask is 0, data values are set to the missing @@ -445,132 +391,21 @@ grid cells which completely overlap input grid cells with missing values Table 4.3 CDMS Regridder function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+--------------------------+--------------------------+--------------------------+ -| Type | Function | Description | -+==========================+==========================+==========================+ -| Array or | ``regridFunction(array, | Interpolate a gridded | -| Transient-Variable | missing=None, order=None | data array to a new | -| | ,mask=None)`` | grid. The interpolation | -| | | preserves the | -| | | area-weighted mean on | -| | | each horizontal slice. | -| | | If array is a Variable, | -| | | a TransientVariable of | -| | | the same rank as the | -| | | input array is returned, | -| | | otherwise a masked array | -| | | is returned. | -| | | | -| | | ``array``\ is a | -| | | Variable, masked array, | -| | | or Numeric array of rank | -| | | 2, 3, or 4. | -| | | | -| | | For example, the string | -| | | “tzyx” indicates that | -| | | the dimension order of | -| | | ``array`` is (time, | -| | | level, latitude, | -| | | longitude). If | -| | | unspecified, the | -| | | function assumes that | -| | | the last two dimensions | -| | | of ``array`` match the | -| | | input grid. | -| | | | -| | | ``missing`` is a Float | -| | | specifying the missing | -| | | data value. The default | -| | | is 1.0e20. | -| | | | -| | | ``order`` is a string | -| | | indicating the order of | -| | | dimensions of the array. | -| | | It has the form returned | -| | | from | -| | | ``variable.getOrder().`` | -| | | | -| | | ``mask`` is a Numeric | -| | | array, of datatype | -| | | Integer or Float, | -| | | consisting of a | -| | | fractional number | -| | | between 0 and 1. A value | -| | | of 1 or 1.0 indicates | -| | | that the corresponding | -| | | data value is to be | -| | | ignored for purposes of | -| | | regridding. A value of 0 | -| | | or 0.0 indicates that | -| | | the corresponding data | -| | | value is valid. This is | -| | | consistent with the | -| | | convention for masks | -| | | used by the MA module. A | -| | | fractional value between | -| | | 0.0 and 1.0 indicates | -| | | the fraction of the data | -| | | value (e.g., the | -| | | corresponding cell) to | -| | | be ignored when | -| | | regridding. This is | -| | | useful if a variable is | -| | | regridded first to grid | -| | | A and then to another | -| | | grid B; the mask when | -| | | regridding from A to B | -| | | would be (1.0 - f) where | -| | | f is the maskArray | -| | | returned from the | -| | | initial grid operation | -| | | using the | -| | | ``returnTuple`` | -| | | argument. | -| | | | -| | | If ``mask`` is | -| | | two-dimensional of the | -| | | same shape as the input | -| | | grid, it overrides the | -| | | mask of the input grid. | -| | | If the mask has more | -| | | than two dimensions, it | -| | | must have the same shape | -| | | as ``array``. In this | -| | | case, the ``missing`` | -| | | data value is also | -| | | ignored. Such an | -| | | ndimensional mask is | -| | | useful if the pattern of | -| | | missing data varies with | -| | | level (e.g., ocean data) | -| | | or time. Note: If | -| | | neither ``missing`` or | -| | | ``mask`` is set, the | -| | | default mask is obtained | -| | | from the mask of the | -| | | array if any. | -+--------------------------+--------------------------+--------------------------+ -| Array, Array | ``regridFunction(ar, mis | If called with the | -| | sing=None, order=None, m | optional ``returnTuple`` | -| | ask=None, returnTuple=1) | argument equal to 1, the | -| | `` | function returns a tuple | -| | | (``dataArray``, | -| | | ``maskArray``). | -| | | | -| | | ``dataArray`` is the | -| | | result data array. | -| | | | -| | | ``maskArray`` is a | -| | | Float32 array of the | -| | | same shape as | -| | | ``dataArray``, such that | -| | | ``maskArray[i,j]`` is | -| | | fraction of the output | -| | | grid cell [i,j] | -| | | overlapping a | -| | | non-missing cell of the | -| | | grid. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: + :header: "Type", "Function", "Description" + :widths: 40, 40, 80 + + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." + , , "``array`` is a Variable, masked array, or Numeric array of rank 2, 3, or 4." + , , + , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." + , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." + , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" + , , "- ``mask`` is a Numeric array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MA module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." + , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." + , , "``dataArray`` is the result data array." + , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." 4.3.2 SCRIP Regridder functions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,32 +414,26 @@ A SCRIP regridder function is an instance of the ScripRegridder class. Such a function is created by calling the regrid.readRegridder method. Typical usage is straightforward: -.. raw:: html - -
+.. doctest:: -:: + >>> import cdms2 + >>> import regrid2 + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> f = cdms2.open('xieArkin-T42.nc') + >>> t42prc = f('prc') + >>> f.close() + >>> # Regrid the source variable + >>> popdat = regridf(t42prc) - >>> regridf = regrid.readRegridder(remap_file) - >>> outdat = regridf(indat) -.. raw:: html - -
The bicubic regridder takes four arguments: -.. raw:: html - -
- -:: - - >>> outdat = regridf(indat, gradlat, gradlon, gradlatlon) +.. doctest:: -.. raw:: html + >>> outdat = regridf(t42prc, gradlat, gradlon, gradlatlon) -
A regridder function also has associated methods to retrieve the following fields: @@ -652,38 +481,28 @@ Table 4.4 SCRIP Regridder functions Regrid data to a uniform output grid. -.. raw:: html - -
- -:: +.. doctest:: - 1 #!/usr/local/bin/python - 2 import cdms - 3 from regrid import Regridder - 4 f = cdms.open('rls_ccc_per.nc') - 5 rlsf = f.variables['rls'] - 6 ingrid = rlsf.getGrid() - 7 outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) - 8 regridFunc = Regridder(ingrid, outgrid) - 9 newrls = regridFunc(rlsf) - 10 f.close() + + >>> import cdms2 + >>> from regrid2 import Regridder + >>> f = cdms2.open('clt.nc') + >>> cltf = f.variables['clt'] + >>> ingrid = cltf.getGrid() + >>> outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> regridFunc = Regridder(ingrid, outgrid) + >>> newrls = regridFunc(cltf) + >>> f.close() -.. raw:: html -
+.. csv-table:: REgridder Constructure + :header: "Line", "Notes" + :widths: 8, 90 -+--------+---------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+===================================================================================================+ -| 4 | Open a netCDF file for input. | -+--------+---------------------------------------------------------------------------------------------------+ -| 7 | Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset | -+--------+---------------------------------------------------------------------------------------------------+ -| 8 | Create the regridder function | -+--------+---------------------------------------------------------------------------------------------------+ -| 9 | Read all data and regrid. The missing data value is obtained from variable rlsf | -+--------+---------------------------------------------------------------------------------------------------+ + "3", "Open a netCDF file for input." + "6", "Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset." + "7", "Create the regridder function." + "8", "Read all data and regrid. The missing data value is obtained from variable rlsf" Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to @@ -693,46 +512,39 @@ the number of cells in the input grid. Get a mask from a separate file, and set as the input grid mask. -.. raw:: html - -
- -:: - - 1 import cdms - 2 from regrid import Regridder - 3 # - 4 f = cdms.open('so_ccc_per.nc') - 5 sof = f.variables['so'] - 6 ingrid = sof.getGrid() - 7 g = cdms.open('rls_mri_per.nc') - 8 rlsg = g.variables['rls'] - 9 outgrid = rlsg.getGrid() - 10 regridFunc = Regridder(ingrid,outgrid) - 11 h = cdms.open('sft_ccc.nc') - 12 sfmaskvar = h.variables['sfmask'] - 13 sfmask = sfmaskvar[:] - 14 outArray = regridFunc(sof.subSlice(time=0),mask=sfmask) - 15 f.close() - 16 g.close() - 17 h.close() +.. doctest:: -.. raw:: html + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/clt.nc + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc + >>> import cdms2 + >>> from regrid2 import Regridder + >>> # + >>> f = cdms2.open('clt.nc') + >>> cltf = f.variables['clt'] + >>> ingrid = cltf.getGrid() + >>> g = cdms2.open('geos5-sample.nc') + >>> ozoneg = g.variables['ozone'] + >>> outgrid = ozoneg.getGrid() + >>> regridFunc = Regridder(ingrid,outgrid) + >>> uwmaskvar = g.variables['uwnd'] + >>> uwmask = uwmaskvar[:]<0 + >>> outArray = regridFunc(ozoneg.subSlice(time=0),mask=uwmask) + >>> f.close() + >>> g.close() -
+--------+-------------------------------------------------------------------------------------------------------------------+ | Line | Notes | +========+===================================================================================================================+ -| 6 | Get the input grid. | +| 7 | Get the input grid. | +--------+-------------------------------------------------------------------------------------------------------------------+ -| 9 | Get the output grid | +| 10 | Get the output grid | +--------+-------------------------------------------------------------------------------------------------------------------+ -| 10 | Create the regridder function. | +| 11 | Create the regridder function. | +--------+-------------------------------------------------------------------------------------------------------------------+ -| 13 | Get the mask. | +| 14 | Get the mask. | +--------+-------------------------------------------------------------------------------------------------------------------+ -| 14 | Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0 | +| 15 | Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0 | +--------+-------------------------------------------------------------------------------------------------------------------+ **Note:** Although it cannot be determined from the code, both mask and @@ -764,31 +576,22 @@ Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() Regrid an array with missing data, and calculate the area-weighted mean of the result. -.. raw:: html +.. doctest:: -
+ >>> from cdms.MV import * + >>> outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> outlatw, outlonw = outgrid.getWeights() + >>> outweights = outerproduct(outlatw, outlonw) + >>> grid = var.getGrid() + >>> sample = var[0,0] + >>> latw, lonw = grid.getWeights() + >>> weights = outerproduct(latw, lonw) + >>> inmask = where(greater(absolute(sample),1.e15),0,1) + >>> mean = add.reduce(ravel(inmask*weights*sample))/add.reduce(ravel(inmask*weights)) + >>> regridFunc = Regridder(grid, outgrid) + >>> outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) + >>> outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) -:: - - 1 from cdms.MV import * - ... - 2 outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) - 3 outlatw, outlonw = outgrid.getWeights() - 4 outweights = outerproduct(outlatw, outlonw) - 5 grid = var.getGrid() - 6 sample = var[0,0] - 7 latw, lonw = grid.getWeights() - 8 weights = outerproduct(latw, lonw) - 9 inmask = where(greater(absolute(sample),1.e15),0,1) - 10 mean = add.reduce(ravel(inmask*weights*sample))/ - add.reduce(ravel(inmask*weights)) - 11 regridFunc = Regridder(grid, outgrid) - 12 outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) - 13 outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) - -.. raw:: html - -
+--------+----------------------------------------------------------------------------------------------------------+ | Line | Notes | @@ -816,8 +619,8 @@ of the result. | 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | +--------+----------------------------------------------------------------------------------------------------------+ -.. rubric:: 4.4.2 SCRIP regridder - :name: scrip-regridder-1 +4.4.2 SCRIP regridder +^^^^^^^^^^^^^^^^^^^^^ **Example:** From 10b90c0b1fd454549a4f8c9a0b962bdefbff3388 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 18 Oct 2017 12:03:42 -0700 Subject: [PATCH 019/239] cdms_4 doctest --- docs/source/index.rst | 7 +- docs/source/manual/cdms_1.rst | 832 ------- docs/source/manual/cdms_2.rst | 3929 --------------------------------- docs/source/manual/cdms_3.rst | 218 -- docs/source/manual/cdms_4.rst | 53 +- 5 files changed, 38 insertions(+), 5001 deletions(-) delete mode 100644 docs/source/manual/cdms_1.rst delete mode 100644 docs/source/manual/cdms_2.rst delete mode 100644 docs/source/manual/cdms_3.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 8ab57f9f..a3877a9e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,10 +9,11 @@ Welcome to cdms2's documentation! Contents: .. toctree:: - manual/cdms_1 - manual/cdms_2 - manual/cdms_3 manual/cdms_4 + +# manual/cdms_2 +# manual/cdms_3 +# manual/cdms_4 # AbstractAxis # AbstractVariable # avariable diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst deleted file mode 100644 index 895a4722..00000000 --- a/docs/source/manual/cdms_1.rst +++ /dev/null @@ -1,832 +0,0 @@ -CHAPTER 1 ---------- - -CHAPTER 1 Introduction -~~~~~~~~~~~~~~~~~~~~~~ - -1.1 Overview -^^^^^^^^^^^^ - -The Climate Data Management System is an object-oriented data management -system, specialized for organizing multidimensional, gridded data used -in climate analysis and simulation. - -CDMS is implemented as part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT), which uses the Python language. The examples in -this chapter assume some familiarity with the language and the Python -Numeric module (http://www.numpy.org). A number of excellent tutorials -on Python are available in books or on the Internet. For example, see -the `Python Foundation's homepage `__. - -1.2 Variables -^^^^^^^^^^^^^ - -The basic unit of computation in CDMS is the variable. A variable is -essentially a multidimensional data array, augmented with a domain, a -set of attributes, and optionally a spatial and/or temporal coordinate -system (see `Coordinate Axes <#1.4>`__). As a data array, a variable can -be sliced to obtain a portion of the data, and can be used in arithmetic -computations. For example, if ``u`` and ``v`` are variables representing -the eastward and northward components of wind speed, respectively, and -both variables are functions of time, latitude, and longitude, then the -velocity for time 0 (first index) can be calculated as - -.. doctest:: - - >>> from cdms2 import MV - >>> vel = MV.sqrt(u[0]**2 + v[0]**2) - -This illustrates several points: - -- Square brackets represent the slice operator. Indexing starts at 0, - so ``u[0]`` selects from variable ``u`` for the first timepoint. The - result of this slice operation is another variable. The slice - operator can be multidimensional, and follows the syntax of Numeric - Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data - for the first ten timepoints, at all latitudes, for the second - longitude. -- Variables can be used in computation. ``**`` is the Python - exponentiation operator. -- Arithmetic functions are defined in the ``cdms.MV`` module. -- Operations on variables carry along the corresponding metadata where - applicable. In the above example, ``vel`` has the same latitude and - longitude coordinates as ``u`` and ``v``, and the time coordinate is - the first time of ``u`` and ``v``. - -1.3 File I/O -^^^^^^^^^^^^ - -A variable can be obtained from a file or collection of files, or can be -generated as the result of a computation. Files can be in any of the -self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS -control file), or PCMDI DRS. (HDF and DRS support is optional, and is -configured at the time UV-CDAT is installed.) For instance, to read data -from file sample.nc into variable u: - -.. testsetup:: * - - import MV2 - import cdms2 - import cdat_info - f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') - f2 = cdms2.open(cdat_info.get_sampledata_path()+'/geos5-sample.nc') - u = f('u') - v = f('v') - smallvar=MV2.reshape(MV2.arange(20),(4,5),id='small variable').astype(MV2.float32) - largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) - -.. doctest:: - - >>> f = cdms2.open('clt.nc') - >>> u = f('u') - -Data can be read by index or by world coordinate values. The following -reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k -such that i <= k < j): - -.. doctest:: - - >>> n = 0 - >>> u0 = f('u',time=slice(n,n+1)) - -To read ``u`` at time 1.: - -.. doctest:: - - >>> u1 = f('u',time=1.) - -A variable can be written to a file with the write function: - -.. doctest:: - - >>> g = cdms2.open('sample2.nc','w') - >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >> g.close() - -1.4 Coordinate Axes -^^^^^^^^^^^^^^^^^^^ - -A coordinate axis is a variable that represents coordinate information. -Typically an axis is associated with one or more variables in a file or -dataset, to represent the indexing and/or spatiotemporal coordinate -system(s) of the variable(s). - -Often in climate applications an axis is a one-dimensional variable -whose values are floating-point and strictly monotonic. In some cases an -axis can be multidimensional (see `Grids <#1.9>`__). If an axis is -associated with one of the canonical types latitude, longitude, level, -or time, then the axis is called tep emporal . - -The shape and physical ordering of a variable is represented by the -variables domain , an ordered tuple of one-dimensional axes. In the -previous example, the domain of the variable u is the tuple (time, -latitude, longitude). This indicates the order of the dimensions, with -the slowest- varying dimension listed first (time). The domain may be -accessed with the ``getAxisList()`` method: - -.. doctest:: - - >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - [ id: time1 - Designated a time axis. - units: months since 1978-12 - Length: 1 - First: 1.0 - Last: 1.0 - Other axis attributes: - calendar: gregorian - axis: T - Python id: ... - , id: plev - Designated a level axis. - units: hPa - Length: 2 - First: 200.0 - Last: 850.0 - Other axis attributes: - axis: Z - realtopology: linear - Python id: ... - , id: latitude1 - Designated a latitude axis. - units: degrees_north - Length: 80 - First: -88.2884 - Last: 88.2884 - Other axis attributes: - axis: Y - realtopology: linear - Python id: ... - , id: longitude1 - Designated a longitude axis. - units: degrees_east - Length: 97 - First: -180.0 - Last: 180.0 - Other axis attributes: - axis: X - topology: circular - modulo: 360.0 - realtopology: linear - Python id: ... - ] - - -In the above example, the domain elements are axes that are also -spatiotemporal. In general it is not always the case that an element of -a domain is spatiotemporal: - -- An axis in the domain of a variable need not be spatiotemporal. For - example, it may represent a range of indices, an index coordinate - system. -- The latitude and/or longitude coordinate axes associated with a - variable need not be elements of the domain. In particular this will - be true if the variable is defined on a non-rectangular grid (see `Grids <#1.9>`__). - -As previously noted, a spatial and/or temporal coordinate system may be -associated with a variable. The methods getLatitude, getLongitude, -getLevel, and getTime return the associated coordinate axes. For -example: - -.. doctest:: - - >>> t = u.getTime() - >>> print t[:] - [ 1.] - >>> print t.units - months since 1978-12 - -1.5 Attributes -^^^^^^^^^^^^^^ - -As mentioned above, variables can have associated attributes , -name-value pairs. In fact, nearly all CDMS objects can have associated -attributes, which are accessed using the Python dot notation: - -.. doctest:: - - >>> u.units='m/s' - >>> print u.units - m/s - -Attribute values can be strings, scalars, or 1-D Numeric arrays. - -When a variable is written to a file, not all the attributes are -written. Some attributes, called internal attributes, are used for -bookkeeping, and are not intended to be part of the external file -representation of the variable. In contrast, external attributes are -written to an output file along with the variable. By default, when an -attribute is set, it is treated as external. Every variable has a field -attributes, a Python dictionary that defines the external attributes: - -.. doctest:: - - >>> print u.attributes.keys() - ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] - -The Python dir command lists the internal attribute names: - -.. doctest:: - - >>> dir(u) - ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] - -In general internal attributes should not be modified directly. One -exception is the id attribute, the name of the variable. It is used in -plotting and I/O, and can be set directly. - -1.6 Masked values -^^^^^^^^^^^^^^^^^ - -Optionally, variables have a mask that represents where data are -missing. If present, the mask is an array of ones and zeros having the -shape of the data array. A mask value of one indicates that the -corresponding data array element is missing or invalid. - -Arithmetic operations in CDMS take missing data into account. The same -is true of the functions defined in the cdms.MV module. For example: - -.. doctest:: - - >>> a = MV2.array([1,2,3]) # Create array a, with no mask - >>> b = MV2.array([4,5,6]) # Same for b - >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - variable_... - masked_array(data = [5 7 9], - mask = False, - fill_value = 999999) - - - >>> a[1]=MV2.masked # Mask the second value of a a.mask() - >>> a.mask - array([False, True, False], dtype=bool) - >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - variable_... - masked_array(data = [5 -- 9], - mask = [False True False], - fill_value = 999999) - - - -When data is read from a file, the result variable is masked if the file -variable has a missing_value attribute. The mask is set to one for -those elements equal to the missing value, zero elsewhere. If no such -attribute is present in the file, the result variable is not masked. - -When a variable with masked values is written to a file, data values -with a corresponding mask value of one are set to the value of the -variables ``missing_value`` attribute. The data and ``missing_value`` -attribute are then written to the file. - -Masking is covered in `Section 2.9 `__. See also the -documentation of the Python Numeric and MA modules, on which ``cdms.MV`` -is based, at - -`http://www.numpy.org/ `__. - -1.7 File Variables -^^^^^^^^^^^^^^^^^^ - -A variable can be obtained either from a file, a collection of files, or -as the result of computation. Correspondingly there are three types of -variables in CDMS: - -- *file variable* is a variable associated with a single data file. - Setting or referencing a file variable generates I/O operations. -- A *dataset variable* is a variable associated with a collection of - files. Reference to a dataset variable reads data, possibly from - multiple files. Dataset variables are read-only. -- *transient variable* is an in-memory object not associated with a - file or dataset. Transient variables result from a computation or I/O - operation. - -Typical use of a file variables is to inquire information about the -variable in a file without actually reading the data for the variables. -A file variable is obtained by applying the slice operator [] to a file, -passing the name of the variable, or by calling the getVariable -function. Note that obtaining a file variable does not actually read the -data array: - -.. doctest:: - - >>> u = f.getVariable('u') # or u=f['u'] - >>> u.shape - (1, 2, 80, 97) - -File variables are also useful for fine-grained I/O. They behave like -transient variables, but operations on them also affect the associated -file. Specifically: - -- slicing a file variable reads data, -- setting a slice writes data, -- referencing an attribute reads the attribute, -- setting an attribute writes the attribute, -- and calling a file variable like a function reads data associated - with the variable: - -.. doctest:: - - >>> import os - >>> os.system("cp clt.nc /tmp") - 0 - >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write - >>> uvar = f['u'] # Note square brackets - >>> uvar.shape - (1, 2, 80, 97) - >>> u0 = uvar[0] # Reads data from sample.nc - >>> u0.shape - (2, 80, 97) - >>> uvar[1]=u0 # Writes data to sample.nc - >>> uvar.units # Reads the attribute 'm/s' - 'm/s' - >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data - >>> f.close() # Save changes to clt.nc (I/O may be buffered) - - -For transient variables, the data is printed only if the size of the array is less -than the print limit . This value can be set with the function -MV.set_print_limit to force the data to be printed: - -.. doctest:: - - >>> MV2.get_print_limit() # Current limit 1000 - 1000 - >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - small variable - masked_array(data = - [[ 0. 1. 2. 3. 4.] - [ 5. 6. 7. 8. 9.] - [ 10. 11. 12. 13. 14.] - [ 15. 16. 17. 18. 19.]], - mask = - False, - fill_value = 999999.0) - >>> MV2.set_print_limit(100) - >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - large variable - masked_array(data = - [[ 0. 1. 2. ..., 17. 18. 19.] - [ 20. 21. 22. ..., 37. 38. 39.] - [ 40. 41. 42. ..., 57. 58. 59.] - ..., - [ 340. 341. 342. ..., 357. 358. 359.] - [ 360. 361. 362. ..., 377. 378. 379.] - [ 380. 381. 382. ..., 397. 398. 399.]], - mask = False, - fill_value = 999999.0) - -The datatype of the variable is determined with the typecode function: - -.. doctest:: - - >>> u.typecode() - 'f' - -1.8 Dataset Variables -^^^^^^^^^^^^^^^^^^^^^ - -The third type of variable, a *dataset variable*, is associated with a -*dataset*, a collection of files that is treated as a single file. A -dataset is created with the ``cdscan`` utility. This generates an XML -metafile that describes how the files are organized and what metadata -are contained in the files. In a climate simulation application, a -dataset typically represents the data generated by one run of a general -circulation or coupled ocean-atmosphere model. - -For example, suppose data for variables u and v are stored in six files: - -1. u_2000.nc, -2. u_2001.nc, -3. u_2002.nc, -4. v_2000.nc, -5. v_2001.nc, -6. v_2002.nc. - -A metafile can be generated with the command: - -**$ cdscan -x cdsample.xml [uv]*.nc** - -The metafile **cdsample.xml** is then used like an ordinary data file: - -.. doctest:: - - >>> import os - >>> os.system("cdscan -x cdsample.xml [uv]*.nc") - 0 - >>> f = cdms2.open('cdsample.xml') - >>> u = f('u') - >>> u.shape - (3, 16, 32) - -1.9 Grids -^^^^^^^^^ - -A latitude-longitude grid represents the coordinate information -associated with a variable. A grid encapsulates: - -- latitude, longitude coordinates -- grid cell boundaries -- area weights - -CDMS defines a rich set of grid types to represent the variety of -coordinate systems used in climate model applications. Grids can be -categorized as rectangular or nonrectangular. - -A rectangular grid has latitude and longitude axes that are -one-dimensional, with strictly monotonic values. The grid is essentially -the Cartesian product of the axes. If either criterion is not met, the -grid is nonrectangular . - -CDMS supports two types of nonrectangular grid: - -- A curvilinear grid consists of a latitude and longitude axis, each of - which is a two-dimensional coordinate axis. Curvilinear grids are - often used in ocean model applications. -- A generic grid consists of a latitude and longitude axis, each of - which is an auxiliary one-dimensional coordinate axis. An auxiliary - axis has values that are not necessarily monotonic. As the name - suggests, generic grids can represent virtually any type of grid. - However, it is more difficult to determine adjacency relationships - between grid points. - -1.9.1 Example: a curvilinear grid -''''''''''''''''''''''''''''''''' - -In this example, variable sample is defined on a 128x192 curvilinear -grid. Note that: - -- The domain of variable sample is ( y , x ) where y and x are index - coordinate axes. -- The curvilinear grid associated with sample consists of axes ( lat , - lon ), each a two-dimensional coordinate axis. -- lat and lon each have domain ( y , x ) - -.. doctest:: - - >>> f = cdms2.open('sampleCurveGrid4.nc') - - - >>> # lat and lon are coordinate axes, but are grouped with data variables - >>> f.variables.keys() - ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] - - >>> # y and x are index coordinate axes - >>> f.axes.keys() - ['nvert', 'x', 'y'] - - >>> # Read data for variable sample - >>> sample = f('sample') - - >>> # The associated grid g is curvilinear - >>> g = sample.getGrid() - - >>> # The domain of the variable consfigists of index axes - >>> sample.getAxisIds() - ['y', 'x'] - - >>> # Get the coordinate axes associated with the grid - >>> lat = g.getLatitude() # or sample.getLatitude() - >>> lon = g.getLongitude() # or sample.getLongitude() - - >>> # lat and lon have the same domain, a subset of the domain of 'sample' - >>> lat.getAxisIds() - ['y', 'x'] - - >>> # lat and lon are variables ... - >>> lat.shape - (32, 48) - - >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - lat - masked_array(data = - [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 - -76.08465554] - [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 - -73.92641847] - [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 - -71.44420823] - ..., - [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 - 42.32854943] - [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 - 42.70106429] - [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 - 43.0307341 ]], - mask = - False, - fill_value = 1e+20) - - >>> lat_in_radians = lat*MV2.pi/180.0 - -.. figure:: images/curvilinear_grid.jpg - :alt: curvilinear grid - - Figure1: Curvilinear Grid - -1.9.2 Example: a generic grid -''''''''''''''''''''''''''''' - -In this example variable zs is defined on a generic grid. Figure 2 -illustrates the grid, in this case a geodesic grid. - -.. doctest:: - - >>> f.variables.keys() - ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] - >>> f.axes.keys() - ['nvert', 'x', 'y'] - >>> zs = f('sample') - >>> g = zs.getGrid() - >>> g - - >>> lat = g.getLatitude() - >>> lon = g.getLongitude() - >>> lat.shape - (32, 48) - >>> lon.shape # variable zs is defined in terms of a single index coordinate - (32, 48) - >>> # axis, 'cell' - >>> zs.shape - (32, 48) - >>> zs.getAxisIds() - ['y', 'x'] - - >>> # lat and lon are also defined in terms of the cell axis - >>> lat.getAxisIds() - ['y', 'x'] - - >>> # lat and lon are one-dimensional, 'auxiliary' coordinate - >>> # axes: values are not monotonic - >>> lat.__class__ - - - -.. figure:: images/generic_grid.jpg - :alt: generic grid - - Figure 2: Generic Grid - -Generic grids can be used to represent any of the grid types. The method -toGenericGrid can be applied to any grid to convert it to a generic -representation. Similarly, a rectangular grid can be represented as -curvilinear. The method toCurveGrid is used to convert a non-generic -grid to curvilinear representation: - -.. doctest:: * - - >>> f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') - >>> clt = f('clt') - >>> rectgrid = clt.getGrid() - >>> rectgrid.shape - (46, 72) - >>> curvegrid = rectgrid.toCurveGrid() - >>> curvegrid - - >>> genericgrid = curvegrid.toGenericGrid() - >>> genericgrid - - -1.10 Regridding -^^^^^^^^^^^^^^^ - -Regridding is the process of mapping variables from one grid to another. -CDMS supports two forms of regridding. Which one you use depends on the -class of grids being transformed: - -- To interpolate from one rectangular grid to another, use the built-in - CDMS regridder. CDMS also has built-in regridders to interpolate from - one set of pressure levels to another, or from one vertical - cross-section to another. -- To interpolate from any lat-lon grid, rectangular or non-rectangular, - use the SCRIP regridder. - -1.10.1 CDMS Regridder -''''''''''''''''''''' - -The built-in CDMS regridder is used to transform data from one -rectangular grid to another. For example, to regrid variable ``u`` (from -a rectangular grid) to a 96x192 rectangular Gaussian grid: - -.. doctest:: - - >>> f = cdms2.open('clt.nc') - >>> u = f('u') - >>> u.shape - (1, 2, 80, 97) - >>> t63_grid = cdms2.createGaussianGrid(96) - >>> u63 = u.regrid(t63_grid) - >>> u63.shape - (1, 2, 96, 192) - -To regrid a variable ``uold`` to the same grid as variable ``vnew``: - -.. doctest:: - - >>> f = cdms2.open('clt.nc') - >>> uold = f('u') - >>> unew = f2('uwnd') - >>> uold.shape - (1, 2, 80, 97) - >>> unew.shape - (1, 14, 181, 360) - >>> t63_grid = unew.getGrid() # Obtain the grid for vnew - >>> u63 = u.regrid(t63_grid) - >>> u63.shape - (1, 2, 181, 360) - -1.10.2 SCRIP Regridder -'''''''''''''''''''''' - -To interpolate between any lat-lon grid types, the SCRIP regridder may -be used. The SCRIP package was developed at [Los Alamos National -Laboratory](http://oceans11.lanl.gov/drupal/Models/OtherSoftware). -SCRIP is written in Fortran 90, and must be built and installed -separately from the UV-CDAT/CDMS installation. - -The steps to regrid a variable are: - -(external to CDMS) - -1. Obtain or generate the grids, in SCRIP netCDF format. -2. Run SCRIP to generate a *remapping* file. - -(in CDMS) - -1. Read the regridder from the SCRIP remapping file. -2. Call the regridder with the source data, returning data on the target - grid. - -Steps 1 and 2 need only be done once. The regridder can be used as often -as necessary. - -#For example, suppose the source data on a T42 grid is to be mapped to a -#POP curvilinear grid. Assume that SCRIP generated a remapping file named -#rmp_T42_to_POP43_conserv.nc: -# -#.. doctest:: -# -# >>> # Import regrid package for regridder functions -# >>> import regrid2, cdms2 -# -# >>> # Get the source variable -# >>> f = cdms2.open('sampleT42Grid.nc') -# >>> dat = f('src_array') -# >>> f.close() -# -# >>> # Read the regridder from the remapper file -# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') -# >>> regridf = regrid2.readRegridder(remapf) -# >>> remapf.close() -# -# >>> # Regrid the source variable -# >>> popdat = regridf(dat) - -Regridding is discussed in `Chapter 4 `__. - -1.11 Time types -^^^^^^^^^^^^^^^ - -CDMS provides extensive support for time values in the cdtime module. -cdtime also defines a set of calendars , specifying the number of days -in a given month. - -Two time types are available: relative time and component time . -Relative time is time relative to a fixed base time. It consists of: - -- a ``units`` string, of the form ``"units since basetime"`` , and -- a floating-point ``value`` - -For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and -units=" days since 1996-1-1". To create a relative time type: - -.. doctest:: - - >>> import cdtime - >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") - >>> rt - 28.000000 days since 1996-1-1 - >>> rt.value - 28.0 - >>> rt.units - 'days since 1996-1-1' - -A component time consists of the integer fields year, month, day, hour, -minute , and the floating-point field second . For example: - - -.. doctest:: - - >>> ct = cdtime.comptime(1996,2,28,12,10,30) - >>> ct - 1996-2-28 12:10:30.0 - >>> ct.year - 1996 - >>> ct.month - 2 - -The conversion functions tocomp and torel convert between the two -representations. For instance, suppose that the time axis of a variable -is represented in units " days since 1979" . To find the coordinate -value corresponding to January 1, 1990: - -.. doctest:: - - >>> ct = cdtime.comptime(1990,1) - >>> rt = ct.torel("days since 1979") - >>> rt.value - 4018.0 - -Time values can be used to specify intervals of time to read. The syntax -time=(c1,c2) specifies that data should be read for times t such that -c1<=t<=c2: - -.. doctest:: - - >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") - >>> c1 = cdtime.comptime(1980,1) - >>> c2 = cdtime.comptime(1980,2) - >>> tas = fh['tas'] - >>> tas.shape - (484, 45, 72) - >>> x = tas.subRegion(time=(c1,c2)) - >>> x.shape - (125, 45, 72) - -or string representations can be used: - - -.. doctest:: - - >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") - >>> tas = fh['tas'] - >>> x = tas.subRegion(time=('1980-1','1980-2')) - -Time types are described in Chapter 3. - -1.12 Plotting data -^^^^^^^^^^^^^^^^^^ - -Data read via the CDMS Python interface can be plotted using the vcs -module. This module, part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT) is documented in the VCS reference manual. The -vcs module provides access to the functionality of the VCS visualization -program. - -To generate a plot: - -- Initialize a canvas with the ``vcs init`` routine. -- Plot the data using the canvas ``plot`` routine. - -For example: - -.. doctest:: - - >>> import cdms2, vcs, cdat_info - >>> fh=cdms2.open(cdat_info.get_sampledata_path() + "/tas_cru_1979.nc") - >>> fh['time'][:] # Print the time coordinates - array([ 1476., 1477., 1478., 1479., 1480., 1481., 1482., 1483., - 1484., 1485., 1486., 1487.]) - - >>> tas = fh('tas', time=1479) - >>> tas.shape - (1, 36, 72) - >>> w = vcs.init() # Initialize a canvas - >>> w.plot(tas) # Generate a plot - `__ -for details. - -1.13 Databases -^^^^^^^^^^^^^^ - -Datasets can be aggregated together into hierarchical collections, -called databases . In typical usage, a program: - -- connects to a database -- searches for data opens a dataset -- accesses data - -Databases add the ability to search for data and metadata in a -distributed computing environment. At present CDMS supports one -particular type of database, based on the Lightweight Directory Access -Protocol (LDAP). - -Here is an example of accessing data via a database: - -#.. doctest:: -# -# >>> db = cdms.connect() # Connect to the default database. -# >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. -# >>> f.variables.keys() # List the variables in the dataset. -# ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] - -Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst deleted file mode 100644 index bfacaeb4..00000000 --- a/docs/source/manual/cdms_2.rst +++ /dev/null @@ -1,3929 +0,0 @@ -CHAPTER 2 CDMS Python Application Programming Interface -------------------------------------------------------- - -2.1 Overview -^^^^^^^^^^^^ - -This chapter describes the CDMS Python application programming interface -(API). Python is a popular public-domain, object-oriented language. Its -features include support for object-oriented development, a rich set of -programming constructs, and an extensible architecture. CDMS itself is -implemented in a mixture of C and Python. In this chapter the assumption -is made that the reader is familiar with the basic features of the -Python language. - -Python supports the notion of a module, which groups together associated -classes and methods. The import command makes the module accessible to -an application. This chapter documents the cdms, cdtime, and regrid -modules. - -The chapter sections correspond to the CDMS classes. Each section -contains tables base. If no parent, the datapath is absolute.describing -the class internal (non-persistent) attributes, constructors (functions -for creating an object), and class methods (functions). A method can -return an instance of a CDMS class, or one of the Python types: - - -Table 2.1 Python types used in CDMS - -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Description | -+==============+=======================================================================================================================================================================================================+ -| Array | Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Comptime | Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Dictionary | An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Float | Floating-point value. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Integer | Integer value. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| List | An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| None | No value returned. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Reltime | Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -2.2 A first example -^^^^^^^^^^^^^^^^^^^ - -The following Python script reads January and July monthly temperature -data from an input dataset, averages over time, and writes the results -to an output file. The input temperature data is ordered (time, -latitude, longitude). - -.. doctest:: - - >>> import cdms2, cdat_info - >>> from cdms2 import MV - >>> jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc') - >>> tasvar = jones['tas'] - >>> jans = tasvar[0::12] - >>> julys = tasvar[6::12] - >>> janavg = MV.average(jans) - >>> janavg.id = "tas_jan" - >>> janavg.long_name = "mean January surface temperature" - >>> julyavg = MV.average(julys) - >>> julyavg.id = "tas_jul" - >>> julyavg.long_name = "mean July surface temperature" - >>> out = cdms2.open('janjuly.nc','w') - >>> out.write(janavg) - >> out.write(julyavg) - >> out.comment = "Average January/July from Jones dataset" - >>> jones.close() - >>> out.close() - - -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| 2,3 | Makes the CDMS and MV modules available. MV defines arithmetic functions. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 4 | Opens a netCDF file read-only. The result jones is a dataset object. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 5 | Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 6 | Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 7 | Reads all July data into a masked array julys. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 8 | Calculate the average January value for each grid zone. Any missing data is handled automatically. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 9,10 | Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 14 | Create a new netCDF output file named ‘janjuly.nc’ to hold the results. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 15 | Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 17 | Set the global attribute ‘comment’. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 18 | Close the output file. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -2.3 cdms module - -The cdms module is the Python interface to CDMS. The objects and methods -in this chapter are made accessible with the command: - -.. raw:: html - -
- -:: - - import cdms2 - -.. raw:: html - -
- -The functions described in this section are not associated with a class. -Rather, they are called as module functions, e.g., - -.. raw:: html - -
- -:: - - file = cdms2.open('sample.nc') - -.. raw:: html - -
- - -Table 2.2 cdms module functions - -+-------------+-------------------------------------------------------------------------+ -| Type | Definition | -+=============+=========================================================================+ -| ``Variable``| ``asVariable(s)``: Transform ``s`` | -| | into a transient variable. ``s`` is | -| | a masked array, Numeric array, or | -| | Variable. If ``s`` is already a | -| | transient variable, ``s`` is | -| | returned. See also: ``isVariable``. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createAxis(data, bounds=None)``: | -| | Create a one-dimensional coordinate | -| | Axis, which is not associated with a | -| | file or dataset. This is useful for | -| | creating a grid which is not | -| | contained in a file or dataset. | -| | ``data`` is a one-dimensional, | -| | monotonic Numeric array. ``bounds`` | -| | is an array of shape | -| | ``(len(data),2)``, such that for all | -| | ``i``, ``data[i]`` is in the range | -| | ``[bounds[i,0],bounds[i,1] ]``. If | -| | ``bounds`` is not specified, the | -| | default boundaries are generated at | -| | the midpoints between the | -| | consecutive data values, provided | -| | that the autobounds mode is 'on' | -| | (the default). See | -| | ``setAutoBounds``. Also see: | -| | ``CdmsFile.createAxis`` | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createEqualAreaAxis(nlat)``: | -| | Create an equal-area latitude axis. | -| | The latitude values range from north | -| | to south, and for all axis values | -| | ``x[i]``, ``sin(x[i])sin(x[i+1])`` | -| | is constant. ``nlat`` is the axis | -| | length. The axis is not associated | -| | with a file or dataset. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createGaussianAxis(nlat)``: Create | -| | a Gaussian latitude axis. Axis | -| | values range from north to south. | -| | ``nlat`` is the axis length. The | -| | axis is not associated with a file | -| | or dataset. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGaussianGrid(nlats, xorigin= | -| | 0.0, order="yx")``: | -| | Create a Gaussian grid, with shape | -| | ``(nlats, 2*nlats)``. ``nlats`` is | -| | the number of latitudes. ``xorigin`` | -| | is the origin of the longitude axis. | -| | ``order`` is either "yx" (lat-lon, | -| | default) or "xy" (lon-lat) | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, | -| | order="yx", mask=None)``: | -| | Create a generic grid, that is, a | -| | grid which is not typed as Gaussian, | -| | uniform, or equal-area. The grid is | -| | not associated with a file or | -| | dataset. ``latArray`` is a NumPy | -| | array of latitude values. | -| | ``lonArray`` is a NumPy array of | -| | longitude values. ``latBounds`` is a | -| | NumPy array having shape | -| | ``(len(latArray),2)``, of latitude | -| | boundaries. ``lonBounds`` is a NumPy | -| | array having shape | -| | ``(len(lonArray),2)``, of longitude | -| | boundaries. ``order`` is a | -| | ``string`` specifying the order of | -| | the axes, either "yx" for (latitude, | -| | longitude), or "xy" for the reverse. | -| | ``mask`` (optional) is an | -| | ``integer``-valued NumPy mask array, | -| | having the same shape and ordering | -| | as the grid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGlobalMeanGrid(grid)``: | -| | Generate a grid for calculating the | -| | global mean via a regridding | -| | operation. The return grid is a | -| | single zone covering the range of | -| | the input grid. ``grid`` is a | -| | RectGrid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createRectGrid(lat, lon, order, ty | -| | pe="generic", mask=None)``: | -| | Create a rectilinear grid, not | -| | associated with a file or dataset. | -| | This might be used as the target | -| | grid for a regridding operation. | -| | ``lat`` is a latitude axis, created | -| | by ``cdms.createAxis``. ``lon`` is a | -| | longitude axis, created by | -| | ``cdms.createAxis``. ``order`` is a | -| | string with value "yx" (the first | -| | grid dimension is latitude) or "xy" | -| | (the first grid dimension is | -| | longitude). ``type`` is one of | -| | 'gaussian','uniform','equalarea',or | -| | 'generic'. If specified, ``mask`` is | -| | a two-dimensional, logical Numeric | -| | array (all values are zero or one) | -| | with the same shape as the grid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createUniformGrid(startLat, nlat, | -| | deltaLat, start-Lon, nlon, deltaLon, | -| | order="yx", mask=None)``: | -| | Create a uniform rectilinear grid. | -| | The grid is not associated with a | -| | file or dataset. The grid boundaries | -| | are at the midpoints of the axis | -| | values. ``startLat`` is the starting | -| | latitude value. ``nlat`` is the | -| | number of latitudes. If ``nlat`` is | -| | 1, the grid latitude boundaries will | -| | be ``startLat`` +/- ``deltaLat/2``. | -| | ``deltaLat`` is the increment | -| | between latitudes. ``startLon`` is | -| | the starting longitude value. | -| | ``nlon`` is the number of | -| | longitudes. If ``nlon`` is 1, the | -| | grid longitude boundaries will be | -| | ``startLon`` +/- ``deltaLon/2``. | -| | ``deltaLon`` is the increment | -| | between longitudes. ``order`` is a | -| | string with value "yx" (the first | -| | grid dimension is latitude) or "xy" | -| | (the first grid dimension is | -| | longitude). If specified, ``mask`` | -| | is a two-dimensional, logical | -| | Numeric array (all values are zero | -| | or one) with the same shape as the | -| | grid. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createUniformLatitudeAxis(startLat | -| | , nlat, deltaLat)``: | -| | Create a uniform latitude axis. The | -| | axis boundaries are at the midpoints | -| | of the axis values. The axis is | -| | designated as a circular latitude | -| | axis. ``startLat`` is the starting | -| | latitude value. ``nlat`` is the | -| | number of latitudes. ``deltaLat`` is | -| | the increment between latitudes. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createZonalGrid(grid)``: Create a | -| | zonal grid. The output grid has the | -| | same latitude as the input grid, and | -| | a single longitude. This may be used | -| | to calculate zonal averages via a | -| | regridding operation. ``grid`` is a | -| | RectGrid. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createUniformLongitudeAxis(startLo | -| | n, nlon, delta-Lon)``: | -| | Create a uniform longitude axis. The | -| | axis boundaries are at the midpoints | -| | of the axis values. The axis is | -| | designated as a circular longitude | -| | axis. ``startLon`` is the starting | -| | longitude value. ``nlon`` is the | -| | number of longitudes. ``deltaLon`` | -| | is the increment between longitudes. | -+-------------+-------------------------------------------------------------------------+ -| ``Variable``| ``createVariable(array, typecode=Non | -| | e, copy=0, savespace=0, mask=None, f | -| | ill_value=None, grid=None, axes=None | -| | , attributes=None, id=None)``: | -| | This function is documented in Table | -| | 2.34 on page 90. | -+-------------+-------------------------------------------------------------------------+ -| ``Integer`` | ``getAutoBounds()``: Get the current | -| | autobounds mode. Returns 0, 1, or 2. | -| | See ``setAutoBounds``. | -+-------------+-------------------------------------------------------------------------+ -| ``Integer`` | ``isVariable(s)``: Return ``1`` if | -| | ``s`` is a variable, ``0`` | -| | otherwise. See also: ``asVariable``. | -+-------------+-------------------------------------------------------------------------+ -| ``Dataset`` | ``open(url,mode='r')``: Open or | -| | create a ``Dataset`` or | -| | ``CdmsFile``. ``url`` is a Uniform | -| | Resource Locator, referring to a | -| | cdunif or XML file. If the URL has | -| | the extension '.xml' or '.cdml', a | -| | ``Dataset`` is returned, otherwise a | -| | ``CdmsFile`` is returned. If the URL | -| | protocol is 'http', the file must be | -| | a '.xml' or '.cdml' file, and the | -| | mode must be 'r'. If the protocol is | -| | 'file' or is omitted, a local file | -| | or dataset is opened. ``mode`` is | -| | the open mode. See Table 2.24 on | -| | page 70. | -| | **Example**: Open an existing | -| | dataset: | -| | ``f = cdms.open("sampleset.xml")`` | -| | | -| | **Example**: Create a netCDF file: | -| | ``f = cdms.open("newfile.nc",'w')`` | -+-------------+-------------------------------------------------------------------------+ -| ``List`` | ``order2index (axes, orderstring)``: | -| | Find the index permutation of axes | -| | to match order. Return a list of | -| | indices. ``axes`` is a list of axis | -| | objects. ``orderstring`` is defined | -| | as in ``orderparse``. | -+-------------+-------------------------------------------------------------------------+ -| ``List`` | ``orderparse(orderstring)``: Parse | -| | an order string. Returns a list of | -| | axes specifiers. ``orderstring`` | -| | consists of: | -| | | -| | - Letters t, x, y, z meaning time, | -| | longitude, latitude, level | -| | - Numbers 0-9 representing position | -| | in axes | -| | - Dash (-) meaning insert the next | -| | available axis here. | -| | - The ellipsis ... meaning fill | -| | these positions with any | -| | remaining axes. | -| | - (name) meaning an axis whose id | -| | is name | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``setAutoBounds(mode)``: Set | -| | autobounds mode. In some | -| | circumstances CDMS can generate | -| | boundaries for 1-D axes and | -| | rectilinear grids, when the bounds | -| | are not explicitly defined. The | -| | autobounds mode determines how this | -| | is done: If ``mode`` is ``'grid'`` | -| | or ``2`` (the default), the | -| | ``getBounds`` method will | -| | automatically generate boundary | -| | information for an axis or grid if | -| | the axis is designated as a latitude | -| | or longitude axis, and the | -| | boundaries are not explicitly | -| | defined. If ``mode`` is ``'on'`` or | -| | ``1``, the ``getBounds`` method will | -| | automatically generate boundary | -| | information for an axis or grid, if | -| | the boundaries are not explicitly | -| | defined. If ``mode`` is ``'off'`` or | -| | ``0``, and no boundary data is | -| | explicitly defined, the bounds will | -| | NOT be generated; the ``getBounds`` | -| | method will return ``None`` for the | -| | boundaries. Note: In versions of | -| | CDMS prior to V4.0, the default | -| | ``mode`` was ``'on'``. | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``setClassifyGrids(mode)``: Set the | -| | grid classification mode. This | -| | affects how grid type is determined, | -| | for the purpose of generating grid | -| | boundaries. If ``mode`` is ``'on'`` | -| | (the default), grid type is | -| | determined by a grid classification | -| | method, regardless of the value of | -| | ``grid.get-Type()``. If ``mode`` is | -| | ``'off'``, the value of | -| | ``grid.getType()`` determines the | -| | grid type | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``writeScripGrid(path, grid, gridTit | -| | le=None)``: | -| | Write a grid to a SCRIP grid file. | -| | ``path`` is a string, the path of | -| | the SCRIP file to be created. | -| | ``grid`` is a CDMS grid object. It | -| | may be rectangular. ``gridTitle`` is | -| | a string ID for the grid. | -+-------------+-------------------------------------------------------------------------+ - - -Table 2.3 Class Tags - -+--------------+---------------------+ -| Tag | Class | -+==============+=====================+ -| ‘axis’ | Axis | -+--------------+---------------------+ -| ‘database’ | Database | -+--------------+---------------------+ -| ‘dataset’ | Dataset, CdmsFile | -+--------------+---------------------+ -| ‘grid’ | RectGrid | -+--------------+---------------------+ -| ‘variable’ | Variable | -+--------------+---------------------+ -| ‘xlink’ | Xlink | -+--------------+---------------------+ - - -2.4 CdmsObj -^^^^^^^^^^^ - -A CdmsObj is the base class for all CDMS database objects. At the -application level, CdmsObj objects are never created and used directly. -Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the -basis of user application programming. - -All objects derived from CdmsObj have a special attribute .attributes. -This is a Python dictionary, which contains all the external -(persistent) attributes associated with the object. This is in contrast -to the internal, non-persistent attributes of an object, which are -built-in and predefined. When a CDMS object is written to a file, the -external attributes are written, but not the internal attributes. - -**Example**: get a list of all external attributes of obj. - -.. raw:: html - -
- -:: - - extatts = obj.attributes.keys() - -.. raw:: html - -
- - -Table 2.4 Attributes common to all CDMS objects - -+--------------+--------------+--------------------------------------------------+ -| Type | Name | Definition | -+==============+==============+==================================================+ -| Dictionary | attributes | External attribute dictionary for this object. | -+--------------+--------------+--------------------------------------------------+ - - -Table 2.5 Getting and setting attributes - -+--------------------------------------+--------------------------------------+ -| Type | Definition | -+======================================+======================================+ -| various | ``value = obj.attname`` | -| | Get an internal or external | -| | attribute value. If the attribute is | -| | external, it is read from the | -| | database. If the attribute is not | -| | already in the database, it is | -| | created as an external attribute. | -| | Internal attributes cannot be | -| | created, only referenced. | -+--------------------------------------+--------------------------------------+ -| various | ``obj.attname = value`` | -| | Set an internal or external | -| | attribute value. If the attribute is | -| | external, it is written to the | -| | database. | -+--------------------------------------+--------------------------------------+ - - -2.5 CoordinateAxis -^^^^^^^^^^^^^^^^^^ - -A CoordinateAxis is a variable that represents coordinate information. -It may be contained in a file or dataset, or may be transient -(memoryresident). Setting a slice of a file CoordinateAxis writes to the -file, and referencing a file CoordinateAxis slice reads data from the -file. Axis objects are also used to define the domain of a Variable. - -CDMS defines several different types of CoordinateAxis objects. Table -2.9 on page 45 documents methods that are common to all CoordinateAxis -types. Table 2.10 on page 48 specifies methods that are unique to 1D -Axis objects. - - -Table 2.6 CoordinateAxis types - -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Definition | -+======================+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``CoordinateAxis`` | A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis`` | A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis2D`` | A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``AuxAxis1D`` | A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.7 CoordinateAxis Internal Attributes - -+------------------+------------------+--------------------------------------------+ -| Type | Name | Definition | -+==================+==================+============================================+ -| ``Dictionary`` | ``attributes`` | External attribute dictionary. | -+------------------+------------------+--------------------------------------------+ -| ``String`` | ``id`` | CoordinateAxis identifer. | -+------------------+------------------+--------------------------------------------+ -| ``Dataset`` | ``parent`` | The dataset which contains the variable. | -+------------------+------------------+--------------------------------------------+ -| ``Tuple`` | ``shape`` | The length of each axis. | -+------------------+------------------+--------------------------------------------+ - - -Table 2.8 Axis Constructors - -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+=================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================+ -| ``cdms.createAxis(data, bounds=None)`` | Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Dataset.createAxis(name,ar)`` | Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented. ) | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``CdmsFile.createAxis(name,ar,unlimited=0)`` | Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|   | A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|   | B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited`` | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createEqualAreaAxis(nlat)`` | See Table 2.2 on page 33. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createGaussianAxis(nlat)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.9 CoordinateAxis Methods - -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============+====================================================================+================================================================================================================================================================================================================================================================================+ -| ``Array`` | ``array = axis[i:j]`` | Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``axis[i:j] = array`` | Write a slice of data to the external file. Dataset axes are read-only. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``assignValue(array)`` | Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis`` | ``clone(copyData=1)`` | Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLatitude(persistent=0)`` | Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLevel(persistent=0)`` | Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLongitude(persistent=0, modulo=360.0)`` | Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateTime(persistent=0, calendar = cdtime.MixedCalendar)`` | Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Array`` | ``getBounds()`` | Get the associated boundary array. The shape of the return array depends on the type of axis: | -|   |   | * ``Axis``: ``(n,2)`` | -|   |   | * ``Axis2D``: ``(i,j,4)`` | -|   |   | * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. | -|   |   | If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``getCalendar()`` | Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: | -|   |   | * ``cdtime.GregorianCalendar``: the standard Gregorian calendar | -|   |   | * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar | -|   |   | * ``cdtime.JulianCalendar``: years divisible by 4 are leap years | -|   |   | * ``cdtime.NoLeapCalendar``: a year is 365 days | -|   |   | * ``cdtime.Calendar360``: a year is 360 days | -|   |   | * ``None``: no calendar can be identified | -|   |   | Note: If the axis is not a time axis, the global, file-related calendar is returned. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Array`` | ``getValue()`` | Get the entire axis vector. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLatitude()`` | Returns true iff the axis is a latitude axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLevel()`` | Returns true iff the axis is a level axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLongitude()`` | Returns true iff the axis is a longitude axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isTime()`` | Returns true iff the axis is a time axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``len(axis)`` | The length of the axis if one-dimensional. If multidimensional, the length of the first dimension. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``size()`` | The number of elements in the axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``String`` | ``typecode()`` | The ``Numeric`` datatype identifier. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.10 Axis Methods, additional to CoordinateAxis - -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============================+===============================================+==========================================================================================================================================================================================================================================================================================================================+ -| ``List`` of component times | ``asComponentTime(calendar=None)`` | ``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``List`` of relative times | ``asRelativeTime()`` | ``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateCircular(modulo, persistent=0)`` | Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isCircular()`` | Returns ``True`` if the axis has circular topology. An axis is defined as circular if: | -|   |   | * ``axis.topology == 'circular'``, or | -|   |   | * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0 | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLinear()`` | Returns ``True`` if the axis has a linear representation. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Tuple`` | ``mapInterval(interval)`` | Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``(i,j,k)`` | ``mapIntervalExt(interval)`` | Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: | -|   |   | * ``(x,y)`` | -|   |   | * ``(x,y,indicator)`` | -|   |   | * ``(x,y,indicator,cycle)`` | -|   |   | * ``None or ':'`` | -|   |   | * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: | -|   |   | * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis| -|   |   | * ``'n'`` - select node values which are contained in the interval | -|   |   | * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval | -|   |   | * ``'e'`` - same as n, but include an extra node on either side | -|   |   | * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval | -|   |   | * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. | -|   |   | * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. | -|   |   | * An interval of ``None`` or ``':'`` returns the full index interval of the axis. | -|   |   | * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. | -|   |   | * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` | -|   |   | * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. | -|   |   | * otherwise the interval wraps around the axis endpoint. | -|   |   | * see also: ``mapinterval``, ``variable.subregion()`` | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``transientaxis`` | ``subaxis(i,j,k=1)`` | create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -table 2.11 axis slice operators - -+---------------+-----------------------------------------------------------------------------+ -| slice | definition | -+===============+=============================================================================+ -| ``[i]`` | the ``ith`` element, starting with index ``0`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:]`` | the ``ith`` element through and including the end | -+---------------+-----------------------------------------------------------------------------+ -| ``[:j]`` | the beginning element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[:]`` | the entire array | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | -+---------------+-----------------------------------------------------------------------------+ - -**example:** - -a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length -``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index -interval(s), with wraparound. the result index interval ``-2 <= n < 3`` -wraps around, since ``-2 < 0``, and has a stride of ``1``. this is -equivalent to the two contiguous index intervals ``2 <= n < 0`` and -``0 <= n < 3`` - -.. raw:: html - -
- -:: - - >>> axis.isCircular() - 1 - >>> axis.mapIntervalExt((-5.0,5.0,'co')) - (-2,3,1) - -.. raw:: html - -
- - -2.6 CdmsFile -^^^^^^^^^^^^ -A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` -interface. netCDF files are accessible in read-write mode. All other -formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. - -As of CDMS V3, the legacy cuDataset interface is also supported by -Cdms-Files. See “cu Module” on page 180. - - -Table 2.12 CdmsFile Internal Attributes - -+------------------+------------------+---------------------------------------+ -| Type | Name | Definition | -+==================+==================+=======================================+ -| ``Dictionary`` | ``attributes`` | Global, external file attributes | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``grids`` | Grids contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``String`` | ``id`` | File pathname. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``variables`` | Variables contained in the file. | -+------------------+------------------+---------------------------------------+ - - -Table 2.13 CdmsFile Constructors - -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+==========================================+==================================================================================================================================================================================+ -| ``fileobj = cdms.open(path, mode)`` | Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70. | -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``fileobj = cdms.createDataset(path)`` | Create the file specified by path, a string. | -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.14 CdmsFile Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| ``Transient-Variable`` | ``fileobj(varname, selec | Calling a ``CdmsFile`` | -| | tor)`` | object as a function | -| | | reads the region of data | -| | | specified by the | -| | | ``selector``. The result | -| | | is a transient variable, | -| | | unless ``raw = 1`` is | -| | | specified. See | -| | | "Selectors" on page 103. | -| | | | -| | | **Example:** The | -| | | following reads data for | -| | | variable 'prc', year | -| | | 1980: | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('test. | -| | | nc') | -| | | x = f('prc', time=(' | -| | | 1980-1','1981-1')) | -+--------------------------+--------------------------+--------------------------+ -| ``Variable``, ``Axis``, | ``fileobj['id']`` | Get the persistent | -| or ``Grid`` | | variable, axis or grid | -| | | object having the string | -| | | identifier. This does | -| | | not read the data for a | -| | | variable. | -| | | | -| | | **Example:** The | -| | | following gets the | -| | | persistent variable | -| | | ``v``, equivalent to | -| | | ``v = f.variables['prc'] | -| | | ``. | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('sampl | -| | | e.nc') | -| | | v = f['prc'] | -| | | | -| | | **Example:** The | -| | | following gets the axis | -| | | named time, equivalent | -| | | to | -| | | ``t = f.axes['time']``. | -| | | | -| | | ``t = f['time']`` | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``close()`` | Close the file. | -+--------------------------+--------------------------+--------------------------+ -| ``Axis`` | ``copyAxis(axis, newname | Copy ``axis`` values and | -| | =None)`` | attributes to a new axis | -| | | in the file. The | -| | | returned object is | -| | | persistent: it can be | -| | | used to write axis data | -| | | to or read axis data | -| | | from the file. If an | -| | | axis already exists in | -| | | the file, having the | -| | | same name and coordinate | -| | | values, it is returned. | -| | | It is an error if an | -| | | axis of the same name | -| | | exists, but with | -| | | different coordinate | -| | | values. ``axis`` is the | -| | | axis object to be | -| | | copied. ``newname``, if | -| | | specified, is the string | -| | | identifier of the new | -| | | axis object. If not | -| | | specified, the | -| | | identifier of the input | -| | | axis is used. | -+--------------------------+--------------------------+--------------------------+ -| ``Grid`` | ``copyGrid(grid, newname | Copy grid values and | -| | =None)`` | attributes to a new grid | -| | | in the file. The | -| | | returned grid is | -| | | persistent. If a grid | -| | | already exists in the | -| | | file, having the same | -| | | name and axes, it is | -| | | returned. An error is | -| | | raised if a grid of the | -| | | same name exists, having | -| | | different axes. ``grid`` | -| | | is the grid object to be | -| | | copied. ``newname``, if | -| | | specified is the string | -| | | identifier of the new | -| | | grid object. If | -| | | unspecified, the | -| | | identifier of the input | -| | | grid is used. | -+--------------------------+--------------------------+--------------------------+ -| ``Axis`` | ``createAxis(id, ar, unl | Create a new ``Axis``. | -| | imited=0)`` | This is a persistent | -| | | object which can be used | -| | | to read or write axis | -| | | data to the file. ``id`` | -| | | is an alphanumeric | -| | | string identifier, | -| | | containing no blanks. | -| | | ``ar`` is the | -| | | one-dimensional axis | -| | | array. Set ``unlimited`` | -| | | to ``cdms.Unlimited`` to | -| | | indicate that the axis | -| | | is extensible. | -+--------------------------+--------------------------+--------------------------+ -| ``RectGrid`` | ``createRectGrid(id, lat | Create a ``RectGrid`` in | -| | , lon, order, type="gene | the file. This is not a | -| | ric", mask=None)`` | persistent object: the | -| | | order, type, and mask | -| | | are not written to the | -| | | file. However, the grid | -| | | may be used for | -| | | regridding operations. | -| | | ``lat`` is a latitude | -| | | axis in the file. | -| | | ``lon`` is a longitude | -| | | axis in the file. | -| | | ``order`` is a string | -| | | with value ``"yx"`` (the | -| | | first grid dimension is | -| | | latitude) or ``"xy"`` | -| | | (the first grid | -| | | dimension is longitude). | -| | | ``type`` is one of | -| | | ``'gaussian'``,\ ``'unif | -| | | orm'``,\ ``'equalarea'`` | -| | | , | -| | | or ``'generic'``. If | -| | | specified, ``mask`` is a | -| | | two-dimensional, logical | -| | | Numeric array (all | -| | | values are zero or one) | -| | | with the same shape as | -| | | the grid. | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | ``createVariable(String | Create a new Variable. | -| | id, String datatype,List | This is a persistent | -| | axes, fill_value=None)`` | object which can be used | -| | | to read or write | -| | | variable data to the | -| | | file. ``id`` is a String | -| | | name which is unique | -| | | with respect to all | -| | | other objects in the | -| | | file. ``datatype`` is an | -| | | ``MA`` typecode, e.g., | -| | | ``MA.Float``, | -| | | ``MA.Int``. ``axes`` is | -| | | a list of Axis and/or | -| | | Grid objects. | -| | | ``fill_value`` is the | -| | | missing value | -| | | (optional). | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | ``createVariableCopy(var | Create a new | -| | , newname=None)`` | ``Variable``, with the | -| | | same name, axes, and | -| | | attributes as the input | -| | | variable. An error is | -| | | raised if a variable of | -| | | the same name exists in | -| | | the file. ``var`` is the | -| | | ``Variable`` to be | -| | | copied. ``newname``, if | -| | | specified is the name of | -| | | the new variable. If | -| | | unspecified, the | -| | | returned variable has | -| | | the same name as | -| | | ``var``. | -| | | | -| | | **Note:** Unlike | -| | | copyAxis, the actual | -| | | data is not copied to | -| | | the new variable. | -+--------------------------+--------------------------+--------------------------+ -| ``CurveGrid`` or | ``readScripGrid(self, wh | Read a curvilinear or | -| ``Generic-Grid`` | ichGrid='destination', c | generic grid from a | -| | heck-Grid=1)`` | SCRIP netCDF file. The | -| | | file can be a SCRIP grid | -| | | file or remapping file. | -| | | If a mapping file, | -| | | ``whichGrid`` chooses | -| | | the grid to read, either | -| | | ``"source"`` or | -| | | ``"destination"``. If | -| | | ``checkGrid`` is ``1`` | -| | | (default), the grid | -| | | cells are checked for | -| | | convexity, and | -| | | 'repaired' if necessary. | -| | | Grid cells may appear to | -| | | be nonconvex if they | -| | | cross a ``0 / 2pi`` | -| | | boundary. The repair | -| | | consists of shifting the | -| | | cell vertices to the | -| | | same side modulo 360 | -| | | degrees. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``sync()`` | Writes any pending | -| | | changes to the file. | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | :: | Write a variable or | -| | | array to the file. The | -| | write(var, attribute | return value is the | -| | s=None, axes=None, extbo | associated file | -| | unds=None, id=None, exte | variable. | -| | nd=None, fill_value=None | | -| | , index=None, typecode=N | If the variable does not | -| | one) | exist in the file, it is | -| | | first defined and all | -| | | attributes written, then | -| | | the data is written. By | -| | | default, the time | -| | | dimension of the | -| | | variable is defined as | -| | | the unlimited dimension | -| | | of the file. If the data | -| | | is already defined, then | -| | | data is extended or | -| | | overwritten depending on | -| | | the value of keywords | -| | | ``extend`` and | -| | | ``index``, and the | -| | | unlimited dimension | -| | | values associated with | -| | | ``var``. | -| | | | -| | | ``var`` is a Variable, | -| | | masked array, or Numeric | -| | | array. ``attributes`` is | -| | | the attribute dictionary | -| | | for the variable. The | -| | | default is | -| | | ``var.attributes``. | -| | | ``axes`` is the list of | -| | | file axes comprising the | -| | | domain of the variable. | -| | | The default is to copy | -| | | ``var.getAxisList()``. | -| | | ``extbounds`` is the | -| | | unlimited dimension | -| | | bounds. Defaults to | -| | | ``var.getAxis(0).getBoun | -| | | ds()``. | -| | | ``id`` is the variable | -| | | name in the file. | -| | | Default is ``var.id``. | -| | | ``extend = 1`` causes | -| | | the first dimension to | -| | | be unlimited: | -| | | iteratively writeable. | -| | | The default is ``None``, | -| | | in which case the first | -| | | dimension is extensible | -| | | if it is ``time.Set`` to | -| | | ``0`` to turn off this | -| | | behaviour. | -| | | ``fill_value`` is the | -| | | missing value flag. | -| | | ``index`` is the | -| | | extended dimension index | -| | | to write to. The default | -| | | index is determined by | -| | | lookup relative to the | -| | | existing extended | -| | | dimension. | -| | | | -| | | **Note:** data can also | -| | | be written by setting a | -| | | slice of a file | -| | | variable, and attributes | -| | | can be written by | -| | | setting an attribute of | -| | | a file variable. | -+--------------------------+--------------------------+--------------------------+ - - -Table 2.15 CDMS Datatypes - -+-----------------+-----------------------------------+ -| CDMS Datatype | Definition | -+=================+===================================+ -| ``CdChar`` | character | -+-----------------+-----------------------------------+ -| ``CdDouble`` | double-precision floating-point | -+-----------------+-----------------------------------+ -| ``CdFloat`` | floating-point | -+-----------------+-----------------------------------+ -| ``CdInt`` | integer | -+-----------------+-----------------------------------+ -| ``CdLong`` | long integer | -+-----------------+-----------------------------------+ -| ``CdShort`` | short integer | -+-----------------+-----------------------------------+ - - -2.7 Database -^^^^^^^^^^^^ -A Database is a collection of datasets and other CDMS objects. It -consists of a hierarchical collection of objects, with the database -being at the root, or top of the hierarchy. A database is used to: - -- search for metadata -- access data -- provide authentication and access control for data and metadata - -The figure below illustrates several important points: - -- Each object in the database has a relative name of the form tag=id. - The id of an object is unique with respect to all objects contained - in the parent. - -- The name of the object consists of its relative name followed by the - relative name(s) of its antecedent objects, up to and including the - database name. In the figure below, one of the variables has name - ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. - -- Subordinate objects are thought of as being contained in the parent. - In this example, the database ‘CDMS’ contains two datasets, each of - which contain several variables. - -|Diagram 1| - -Figure 1 - - -2.7.1 Overview - -To access a database: - -#. Open a connection. The connect method opens a database connection. - connect takes a database URI and returns a database object: - ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` -#. Search the database, locating one or more datasets, variables, and/or - other objects. - - The database searchFilter method searches the database. A single - database connection may be used for an arbitrary number of searches. - - **Example**: Find all observed datasets - - ``result = db.searchFilter(category="observed",tag="dataset")`` - - Searches can be restricted to a subhierarchy of the database. - - **Example:** Search just the dataset ``'ncep_reanalysis_mo'``: - - ``result = db.searchFilter(relbase="dataset=ncep_reanalysis")`` - -#. Refine the search results if necessary. The result of a search can be - narrowed with the searchPredicate method. -#. Process the results. A search result consists of a sequence of - entries. Each entry has a name, the name of the CDMS object, and an - attribute dictionary, consisting of the attributes located by the - search: - - `` for entry in result: print entry.name, entry.attributes`` - -#. Access the data. The CDMS object associated with an entry is obtained - from the getObject method: - - ``obj = entry.getObject()`` - - If the id of a dataset is known, the dataset can be opened directly - with the open method: - - ``dset = db.open("ncep_reanalysis_mo")`` - -#. Close the database connection: - - ``db.close()`` - - -Table 2.16 Database Internal Attributes - -+------------------+------------------+----------------------------------------+ -| Type | Name | Summary | -+==================+==================+========================================+ -| ``Dictionary`` | ``attributes`` | Database attribute dictionary | -+------------------+------------------+----------------------------------------+ -| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``netloc`` | Hostname, for server-based databases | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``path`` | path name | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``uri`` | Uniform Resource Identifier | -+------------------+------------------+----------------------------------------+ - - -Table 2.17 Database Constructors - -+---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+=========================================================+==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``db = cdms.connect(uri=None, user="", password="")`` | Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection | -+---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.18 Database Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| None | ``close()`` | Close a database | -| | | connection. | -+--------------------------+--------------------------+--------------------------+ -| List | ``listDatasets()`` | Return a list of the | -| | | dataset IDs in this | -| | | database. A dataset ID | -| | | can be passed to the | -| | | ``open`` command. | -+--------------------------+--------------------------+--------------------------+ -| Dataset | ``open(dsetid, mode='r') | Open a dataset. | -| | `` | | -| | | ``dsetid`` is the string | -| | | dataset identifier | -| | | | -| | | ``mode`` is the open | -| | | mode, 'r' - read-only, | -| | | 'r+' - read-write, 'w' - | -| | | create. | -| | | | -| | | ``openDataset`` is a | -| | | synonym for ``open``. | -+--------------------------+--------------------------+--------------------------+ -| SearchResult | :: | Search a CDMS database. | -| | | | -| | searchFilter(filter= | ``filter`` is the string | -| | None, tag=None, relbase= | search filter. Simple | -| | None, scope=Subtree, att | filters have the form | -| | names=None, timeout=None | "tag = value". Simple | -| | ) | filters can be combined | -| | | using logical operators | -| | | '&', '\|', '!' in prefix | -| | | notation. | -| | | | -| | | **Example:** | -| | | | -| | | The filter | -| | | ``'(&(objec)(id=cli))'`` | -| | | finds all variables | -| | | named "cli". | -| | | | -| | | A formal definition of | -| | | search filters is | -| | | provided in the | -| | | following section. | -| | | | -| | | ``tag`` restricts the | -| | | search to objects with | -| | | that tag ("dataset" \| | -| | | "variable" \| "database" | -| | | \| "axis" \| "grid"). | -| | | | -| | | ``relbase`` is the | -| | | relative name of the | -| | | base object of the | -| | | search. The search is | -| | | restricted to the base | -| | | object and all objects | -| | | below it in the | -| | | hierarchy. | -| | | | -| | | **Example:** | -| | | | -| | | To search only dataset | -| | | 'ncep\_reanalysis\_mo', | -| | | specify: | -| | | | -| | | ``relbase="dataset=ncep_ | -| | | reanalysis_mo" `` | -| | | | -| | | To search only variable | -| | | 'ua' in | -| | | 'ncep\_reanalysis\_mo', | -| | | use: | -| | | | -| | | ``relbase="variable=ua,d | -| | | ataset=ncep_reanalysis_m | -| | | o"`` | -| | | | -| | | If no base is specified, | -| | | the entire database is | -| | | searched. See the | -| | | ``scope`` argument also. | -| | | | -| | | ``scope`` is the search | -| | | scope (**Subtree** \| | -| | | **Onelevel** \| | -| | | **Base**). | -| | | | -| | | - **Subtree** searches | -| | | the base object and | -| | | its descendants. | -| | | - **Onelevel** searches | -| | | the base object and | -| | | its immediate | -| | | descendants. | -| | | - **Base**\ searches | -| | | the base object | -| | | alone. | -| | | | -| | | The default is | -| | | **Subtree**. | -| | | | -| | | ``attnames``: list of | -| | | attribute names. | -| | | Restricts the attributes | -| | | returned. If ``None``, | -| | | all attributes are | -| | | returned. Attributes | -| | | 'id' and 'objectclass' | -| | | are always included in | -| | | the list. | -| | | | -| | | ``timeout``: integer | -| | | number of seconds before | -| | | timeout. The default is | -| | | no timeout. | -+--------------------------+--------------------------+--------------------------+ - - -2.7.2 Searching a database - -The ``searchFilter`` method is used to search a database. The result is -called a search result, and consists of a sequence of result entries. - -In its simplest form, ``searchFilter`` takes an argument consisting of a -string filter. The search returns a sequence of entries, corresponding -to those objects having an attribute which matches the filter. Simple -filters have the form (tag = value), where value can contain wildcards. -For example: - -.. raw:: html - -
- -:: - - (id = ncep*) - (project = AMIP2) - -.. raw:: html - -
- -+--------------------------------------------------------------------+------------------------+ -| Simple filters can be combined with the logical operators ‘&’, ‘ | ’, ‘!’. For example, | -+--------------------------------------------------------------------+------------------------+ - -.. raw:: html - -
- -:: - - (&(id = bmrc*)(project = AMIP2)) - -.. raw:: html - -
- -matches all objects with id starting with bmrc, and a project attribute -with value ‘AMIP2’. - -Formally, search filters are strings defined as follows: - -.. raw:: html - -
- -:: - - filter ::= "(" filtercomp ")" - - filtercomp ::= "&" filterlist | # and - "|" filterlist | # or - "!" filterlist | # not - simple - - filterlist ::= filter | filter filterlist - simple ::= tag op value - op ::= "=" | # equality - - "~=" | # approximate equality - "<=" | # lexicographically less than or equal to - ">=" # lexicographically greater than or equal to - - tag ::= string attribute name - value ::= string attribute value, may include '*' as a wild card - -.. raw:: html - -
- -Attribute names are defined in the chapter on “Climate Data Markup -Language (CDML)” on page 149. In addition, some special attributes are -defined for convenience: - -- ``category`` is either “experimental” or “observed” -- ``parentid`` is the ID of the parent dataset -- ``project`` is a project identifier, e.g., “AMIP2” -- ``objectclass`` is the list of tags associated with the object. - -The set of objects searched is called the search scope. The top object -in the hierarchy is the base object. By default, all objects in the -database are searched, that is, the database is the base object. If the -database is very large, this may result in an unnecessarily slow or -inefficient search. To remedy this the search scope can be limited in -several ways: - -- The base object can be changed. -- The scope can be limited to the base object and one level below, or - to just the base object. -- The search can be restricted to objects of a given class (dataset, - variable, etc.) -- The search can be restricted to return only a subset of the object - attributes -- The search can be restricted to the result of a previous search. -- A search result is accessed sequentially within a for loop: - -.. raw:: html - -
- -:: - - result = db.searchFilter('(&(category=obs*)(id=ncep*))') - for entry in result: - print entry.name - -.. raw:: html - -
- -Search results can be narrowed using ``searchPredicate``. In the -following example, the result of one search is itself searched for all -variables defined on a 94x192 grid: - -.. raw:: html - -
- -:: - - >>> result = db.searchFilter('parentid=ncep*',tag="variable") - >>> len(result) - 65 - >>> result2 = result.searchPredicate(lambda x: - - x.getGrid().shape==(94,192)) - >>> len(result2) - 3 - >>> for entry in result2: print entry.name - variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US - variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US - variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US - -.. raw:: html - -
- - -Table 2.19 SearchResult Methods - -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+================+============================================+==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ResultEntry | ``[i]`` | Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):`` | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Integer | ``len()`` | Number of entries in the result. | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| SearchResult | ``searchPredicate(predicate, tag=None)`` | Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag. **Note**: In the current implementation, ``searchPredicate``\ is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches. | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -A search result is a sequence of result entries. Each entry has a string -name, the name of the object in the database hierarchy, and an attribute -dictionary. An entry corresponds to an object found by the search, but -differs from the object, in that only the attributes requested are -associated with the entry. In general, there will be much more -information defined for the associated CDMS object, which is retrieved -with the ``getObject`` method. - - -Table 2.20 ResultEntry Attributes - -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ -| Type | Name | Description | -+==============+==================+=======================================================================================================================+ -| String | ``name`` | The name of this entry in the database. | -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ -| Dictionary | ``attributes`` | The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key | -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ - - -Table 2.21 ResultEntry Methods - -+---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============+===================+======================================================================================================================================================================================================================================================================================+ -| ``CdmsObj`` | ``getObject()`` | Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. | -+---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -2.7.3 Accessing data - -To access data via CDMS: - -#. Locate the dataset ID. This may involve searching the metadata. -#. Open the dataset, using the open method. -#. Reference the portion of the variable to be read. - -In the next example, a portion of variable ‘ua’ is read from dataset -‘ncep\_reanalysis\_mo’: - -.. raw:: html - -
- -:: - - dset = db.open('ncep_reanalysis_mo') - ua = dset.variables['ua'] - data = ua[0,0] - -.. raw:: html - -
- - -2.7.4 Examples of database searches - -In the following examples, db is the database opened with - -.. raw:: html - -
- -:: - - db = cdms.connect() - -.. raw:: html - -
- -This defaults to the database defined in environment variable -``CDMSROOT``. - -**Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: - -.. raw:: html - -
- -:: - - for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", - tag = "variable"): - print entry.name - -.. raw:: html - -
- -**Example:** Find all axes with bounds defined: - -.. raw:: html - -
- -:: - - for entry in db.searchFilter(filter="bounds=*",tag="axis"): - print entry.name - -.. raw:: html - -
- -**Example:** Locate all GDT datasets: - -.. raw:: html - -
- -:: - - for entry in - db.searchFilter(filter="Conventions=GDT*",tag="dataset"): - print entry.name - -.. raw:: html - -
- -**Example:** Find all variables with missing time values, in observed -datasets: - -.. raw:: html - -
- -:: - - def missingTime(obj): - time = obj.getTime() - return time.length != time.partition_length - - result = db.searchFilter(filter="category=observed") - for entry in result.searchPredicate(missingTime): - print entry.name - -.. raw:: html - -
- -**Example:** Find all CMIP2 datasets having a variable with id “hfss”: - -.. raw:: html - -
- -:: - - for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): - print entry.getObject().parent.id - -.. raw:: html - -
- -**Example:** Find all observed variables on 73x144 grids: - -.. raw:: html - -
- -:: - - result = db.searchFilter(category='obs*') - for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): - print entry.name - -.. raw:: html - -
- -**Example:** Find all observed variables with more than 1000 timepoints: - -.. raw:: html - -
- -:: - - result = db.searchFilter(category='obs*') - for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): - print entry.name, len(entry.getObject().getTime()) - -.. raw:: html - -
- -**Example:** Find the total number of each type of object in the -database - -.. raw:: html - -
- -:: - - print len(db.searchFilter(tag="database")),"database" - print len(db.searchFilter(tag="dataset")),"datasets" - print len(db.searchFilter(tag="variable")),"variables" - print len(db.searchFilter(tag="axis")),"axes" - -.. raw:: html - -
- - -2.8 Dataset -^^^^^^^^^^^ -A Dataset is a virtual file. It consists of a metafile, in CDML/XML -representation, and one or more data files. - -As of CDMS V3, the legacy cuDataset interface is supported by Datasets. -See “cu Module” on page 180. - - -Table 2.22 Dataset Internal Attributes - -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Type | Name | Description | -+==============+==================+==========================================================================================================+ -| Dictionary | ``attributes`` | Dataset external attributes. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``axes`` | Axes contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``datapath`` | Path of data files, relative to the parent database. If no parent, the datapath is absolute. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``grids`` | Grids contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``mode`` | Open mode. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Database | ``parent`` | Database which contains this dataset. If the dataset is not part of a database, the value is ``None``. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``uri`` | Uniform Resource Identifier of this dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``variables`` | Variables contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``xlinks`` | External links contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ - - -Table 2.23 Dataset Constructors - -+-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+===========================================================+===================================================================================================================================================================================================================+ -| ``datasetobj = cdms.open(String uri, String mode='r')`` | Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open`` | -+-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.24 Open Modes - -+--------+-----------------------------------------------------------------------+ -| Mode | Definition | -+========+=======================================================================+ -| ‘r’ | read-only | -+--------+-----------------------------------------------------------------------+ -| ‘r+’ | read-write | -+--------+-----------------------------------------------------------------------+ -| ‘a’ | read-write. Open the file if it exists, otherwise create a new file | -+--------+-----------------------------------------------------------------------+ -| ‘w’ | Create a new file, read-write | -+--------+-----------------------------------------------------------------------+ - - -Table 2.25 Dataset Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| Transient-Variable | ``datasetobj(varname, se | Calling a Dataset object | -| | lector)`` | as a function reads the | -| | | region of data defined | -| | | by the selector. The | -| | | result is a transient | -| | | variable, unless | -| | | ``raw = 1`` is | -| | | specified. See | -| | | "Selectors" on page 103. | -| | | **Example:** The | -| | | following reads data for | -| | | variable 'prc', year | -| | | 1980: | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('test. | -| | | xml') | -| | | x = f('prc', time=(' | -| | | 1980-1','1981-1')) | -+--------------------------+--------------------------+--------------------------+ -| Variable, Axis, or Grid | ``datasetobj['id']`` | The square bracket | -| | | operator applied to a | -| | | dataset gets the | -| | | persistent variable, | -| | | axis or grid object | -| | | having the string | -| | | identifier. This does | -| | | not read the data for a | -| | | variable. Returns | -| | | ``None`` if not found. | -| | | | -| | | **Example:** | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('sampl | -| | | e.xml') | -| | | v = f['prc'] | -| | | | -| | | gets the persistent | -| | | variable v, equivalent | -| | | to | -| | | ``v = f.variab | -| | | les['prc']``. | -| | | | -| | | **Example:** | -| | | | -| | | | ``t = f['time']`` | -| | | | gets the axis named | -| | | 'time', equivalent to | -| | | ``t = f.axes['time']`` | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``close()`` | Close the dataset. | -+--------------------------+--------------------------+--------------------------+ -| ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | -| | , lon, order, type="gene | dataset. This is not a | -| | ric", mask=Non | persistent object: the | -| | e)`` | order, type, and mask | -| | | are not written to the | -| | | dataset. However, the | -| | | grid may be used for | -| | | regridding operations. | -| | | | -| | | ``lat`` is a latitude | -| | | axis in the dataset. | -| | | | -| | | ``lon`` is a longitude | -| | | axis in the dataset. | -| | | | -| | | ``order`` is a string | -| | | with value "yx" (the | -| | | first grid dimension is | -| | | latitude) or "xy" (the | -| | | first grid dimension is | -| | | longitude). | -| | | | -| | | ``type`` is one of | -| | | 'gaussian','uniform','eq | -| | | ualarea',or | -| | | 'generic' | -| | | | -| | | If specified, ``mask`` | -| | | is a two-dimensional, | -| | | logical Numeric array | -| | | (all values are zero or | -| | | one) with the same shape | -| | | as the grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(id)`` | Get an axis object from | -| | | the file or dataset. | -| | | | -| | | ``id`` is the string | -| | | axis identifier. | -+--------------------------+--------------------------+--------------------------+ -| Grid | ``getGrid(id)`` | Get a grid object from a | -| | | file or dataset. | -| | | | -| | | ``id`` is the string | -| | | grid identifier. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getPaths()`` | Get a sorted list of | -| | | pathnames of datafiles | -| | | which comprise the | -| | | dataset. This does not | -| | | include the XML metafile | -| | | path, which is stored in | -| | | the .uri attribute. | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``getVariable(id)`` | Get a variable object | -| | | from a file or dataset. | -| | | | -| | | ``id`` is the string | -| | | variable identifier. | -+--------------------------+--------------------------+--------------------------+ -| CurveGrid or GenericGrid | ``readScripGrid(self, wh | Read a curvilinear or | -| | ichGrid='destination', c | generic grid from a | -| | heck-or Generic-Grid=1)` | SCRIP dataset. The | -| | ` | dataset can be a SCRIP | -| | | grid file or remapping | -| | | file. | -| | | | -| | | If a mapping file, | -| | | ``whichGrid`` chooses | -| | | the grid to read, either | -| | | ``"source"`` or | -| | | ``"destination"``. | -| | | | -| | | If ``checkGrid`` is 1 | -| | | (default), the grid | -| | | cells are checked for | -| | | convexity, and | -| | | 'repaired' if necessary. | -| | | Grid cells may appear to | -| | | be nonconvex if they | -| | | cross a ``0 / 2pi`` | -| | | boundary. The repair | -| | | consists of shifting the | -| | | cell vertices to the | -| | | same side modulo 360 | -| | | degrees. | -+--------------------------+--------------------------+--------------------------+ -| None | ``sync()`` | Write any pending | -| | | changes to the dataset. | -+--------------------------+--------------------------+--------------------------+ - - -2.9 MV module -^^^^^^^^^^^^^ - -The fundamental CDMS data object is the variable. A variable is -comprised of: - -- a masked data array, as defined in the NumPy MA module. -- a domain: an ordered list of axes and/or grids. -- an attribute dictionary. - -The MV module is a work-alike replacement for the MA module, that -carries along the domain and attribute information where appropriate. MV -provides the same set of functions as MA. However, MV functions generate -transient variables as results. Often this simplifies scripts that -perform computation. MA is part of the Python Numeric package, -documented at http://www.numpy.org. - -MV can be imported with the command: - -.. raw:: html - -
- -:: - - import MV - -.. raw:: html - -
- -The command - -.. raw:: html - -
- -:: - - from MV import * - -.. raw:: html - -
- -allows use of MV commands without any prefix. - -Table 2.26 on page 75 lists the constructors in MV. All functions return -a transient variable. In most cases the keywords axes, attributes, and -id are available. axes is a list of axis objects which specifies the -domain of the variable. attributes is a dictionary. id is a special -attribute string that serves as the identifier of the variable, and -should not contain blanks or non-printing characters. It is used when -the variable is plotted or written to a file. Since the id is just an -attribute, it can also be set like any attribute: - -.. raw:: html - -
- -:: - - var.id = 'temperature' - -.. raw:: html - -
- -For completeness MV provides access to all the MA functions. The -functions not listed in the following tables are identical to the -corresponding MA function: ``allclose``, ``allequal``, -``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, -``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, -``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, -``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, -``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, -``putmask``, ``rank``, ``ravel``, ``set_fill_value``, -``set_print_limit``, ``shape``, ``size``. See the documentation at -http://numpy.sourceforge.net for a description of these functions. - - -Table 2.26 Variable Constructors in module MV - -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MA.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MA.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | return an array of all ones of the given length or shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``reshape(a, newshape, axes=none, attributes=none, id=none)`` | copy of a with a new shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``resize(a, new_shape, axes=none, attributes=none, id=none)`` | return a new array with the specified shape. the original arrays total size can be any size. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | an array of all zeros of the given length or shape | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -The following table describes the MV non-constructor functions. with the -exception of argsort, all functions return a transient variable. - - -Table 2.27 MV functions - -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Function | Description | -+=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+ -| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numeric array of indices for sorting along a given axis. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``asarray(data, typecode=None)`` | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``average(a, axis=0, weights=None)`` | Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``choose(condition, t)`` | Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``concatenate(arrays, axis=0, axisid=None, axisattributes=None)`` | Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``count(a, axis=None)`` | Count of the non-masked elements in ``a``, or along a certain axis. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``isMaskedVariable(x)`` | Return true if ``x`` is an instance of a variable. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_equal(x, value)`` | ``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_greater(x, value)`` | ``x`` masked where ``x > value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_greater_equal(x, value)`` | ``x`` masked where ``x >= value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_less(x, value)`` | ``x`` masked where ``x < value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_less_equal(x, value)`` | ``x`` masked where ``x ≤ value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_not_equal(x, value)`` | ``x`` masked where ``x != value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_outside(x, v1, v2)`` | ``x`` with mask of all values of ``x`` that are outside ``[v1,v2]`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_where(condition, x, copy=1)`` | Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``maximum(a, b=None)`` | Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``minimum(a, b=None)`` | Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``outerproduct(a, b)`` | Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``power(a, b)`` | ``a**b`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``product(a, axis=0, fill_value=1)`` | Product of elements along axis using ``fill_value`` for missing elements. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``repeat(ar, repeats, axis=0)`` | Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``set_default_fill_value(value_type, value)`` | Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sort(ar, axis=-1)`` | Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sum(a, axis=0, fill_value=0)`` | Sum of elements along a certain axis using ``fill_value`` for missing. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numeric manual. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``transpose(ar, axes=None)`` | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``where(condition, x, y)`` | ``x`` where ``condition`` is true, ``y`` otherwise | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -2.10 HorizontalGrid -^^^^^^^^^^^^^^^^^^^ - -A HorizontalGrid represents a latitude-longitude coordinate system. In -addition, it optionally describes how lat-lon space is partitioned into -cells. Specifically, a HorizontalGrid: - -- consists of a latitude and longitude coordinate axis. -- may have associated boundary arrays describing the grid cell - boundaries, -- may optionally have an associated logical mask. - -CDMS supports several types of HorizontalGrids: - - -Table 2.28 - -+-------------------+----------------------------------------------------------------------------------+ -| Grid Type | Definition | -+===================+==================================================================================+ -| ``RectGrid`` | Associated latitude an longitude are 1-D axes, with strictly monotonic values. | -+-------------------+----------------------------------------------------------------------------------+ -| ``CurveGrid`` | Latitude and longitude are 2-D coordinate axes (Axis2D). | -+-------------------+----------------------------------------------------------------------------------+ -| ``GenericGrid`` | Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D) | -+-------------------+----------------------------------------------------------------------------------+ - - -Table 2.29 HorizontalGrid Internal Attribute - -+-----------------------+------------------+------------------------------------------------+ -| Type | Name | Definition | -+=======================+==================+================================================+ -| Dictionary | ``attributes`` | External attribute dictionary. | -+-----------------------+------------------+------------------------------------------------+ -| String | ``id`` | The grid identifier. | -+-----------------------+------------------+------------------------------------------------+ -| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | -+-----------------------+------------------+------------------------------------------------+ -| Tuple | ``shape`` | The shape of the grid, a 2-tuple | -+-----------------------+------------------+------------------------------------------------+ - -Table 2.31 on page 82 describes the methods that apply to all types of -HorizontalGrids. Table 2.32 on page 86 describes the additional methods -that are unique to RectGrids. - - -Table 2.30 RectGrid Constructors - -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| Constructor | Description | -+=========================================================================================================+==================================================================================+ -| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | Create a grid not associated with a file or dataset. See Table 2.2 on page 33. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``CdmsFile.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a file. See Table 2.14 on page 53. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``Dataset.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a dataset. See Table 2.25 on page 71. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGaussianGrid(nlats, xorigin=0.0, order="yx")`` | See Table 2.2 on page 33. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGlobalMeanGrid(grid)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createZonalGrid(grid)`` | See Table 2.2 on page 18 | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ - - -Table 2.31 HorizontalGrid Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Description | -+==========================+==========================+==========================+ -| Horizontal-Grid | ``clone()`` | Return a transient copy | -| | | of the grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(Integer n)`` | Get the n-th axis.n is | -| | | either 0 or 1. | -+--------------------------+--------------------------+--------------------------+ -| Tuple | ``getBounds()`` | Get the grid boundary | -| | | arrays. | -| | | | -| | | Returns a tuple | -| | | ``(latitudeArray, longit | -| | | udeArray)``, | -| | | where latitudeArray is a | -| | | Numeric array of | -| | | latitude bounds, and | -| | | similarly for | -| | | longitudeArray.The shape | -| | | of latitudeArray and | -| | | longitudeArray depend on | -| | | the type of grid: | -| | | | -| | | - for rectangular grids | -| | | with shape (nlat, | -| | | nlon), the boundary | -| | | arrays have shape | -| | | (nlat,2) and | -| | | (nlon,2). | -| | | - for curvilinear grids | -| | | with shape (nx, ny), | -| | | the boundary arrays | -| | | each have shape (nx, | -| | | ny, 4). | -| | | - for generic grids | -| | | with shape (ncell,), | -| | | the boundary arrays | -| | | each have shape | -| | | (ncell, nvert) where | -| | | nvert is the maximum | -| | | number of vertices | -| | | per cell. | -| | | | -| | | For rectilinear grids: | -| | | If no boundary arrays | -| | | are explicitly defined | -| | | (in the file or | -| | | dataset), the result | -| | | depends on the auto- | -| | | Bounds mode (see | -| | | ``cdms.setAutoBounds``) | -| | | and the grid | -| | | classification mode (see | -| | | ``cdms.setClassifyGrids` | -| | | `). | -| | | By default, autoBounds | -| | | mode is enabled, in | -| | | which case the boundary | -| | | arrays are generated | -| | | based on the type of | -| | | grid. If disabled, the | -| | | return value is | -| | | (None,None).For | -| | | rectilinear grids: The | -| | | grid classification mode | -| | | specifies how the grid | -| | | type is to be | -| | | determined. By default, | -| | | the grid type (Gaussian, | -| | | uniform, etc.) is | -| | | determined by calling | -| | | grid.classifyInFamily. | -| | | If the mode is 'off' | -| | | grid.getType is used | -| | | instead. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLatitude()`` | Get the latitude axis of | -| | | this grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLongitude()`` | Get the latitude axis of | -| | | this grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getMask()`` | Get the mask array of | -| | | this grid, if | -| | | any.Returns a 2-D | -| | | Numeric array, having | -| | | the same shape as the | -| | | grid. If the mask is not | -| | | explicitly defined, the | -| | | return value is | -| | | ``None``. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getMesh(self, transpos | Generate a mesh array | -| | e=None)`` | for the meshfill | -| | | graphics method.If | -| | | transpose is defined to | -| | | a tuple, say (1,0), | -| | | first transpose | -| | | latbounds and lonbounds | -| | | according to the tuple, | -| | | in this case (1,0,2). | -+--------------------------+--------------------------+--------------------------+ -| None | ``setBounds(latBounds, l | Set the grid | -| | onBounds, persistent=0)` | boundaries.\ ``latBounds | -| | ` | `` | -| | | is a NumPy array of | -| | | shape (n,2), such that | -| | | the boundaries of the | -| | | kth axis value are | -| | | ``[latBounds[k,0],latBou | -| | | nds[k,1] ]``. | -| | | ``lonBounds`` is defined | -| | | similarly for the | -| | | longitude array. | -| | | **Note:** By default, | -| | | the boundaries are not | -| | | written to the file or | -| | | dataset containing the | -| | | grid (if any). This | -| | | allows bounds to be set | -| | | on read-only files, for | -| | | regridding. If the | -| | | optional argument | -| | | ``persistent`` is set to | -| | | 1, the boundary array is | -| | | written to the file. | -+--------------------------+--------------------------+--------------------------+ -| None | ``setMask(mask, persiste | Set the grid mask. If | -| | nt=0)`` | ``persistent == 1``, the | -| | | mask values are written | -| | | to the associated file, | -| | | if any. Otherwise, the | -| | | mask is associated with | -| | | the grid, but no I/O is | -| | | generated. ``mask`` is a | -| | | two-dimensional, | -| | | Boolean-valued Numeric | -| | | array, having the same | -| | | shape as the grid. | -+--------------------------+--------------------------+--------------------------+ -| Horizontal-Grid | ``subGridRegion(latInter | Create a new grid | -| | val, lonInterval)`` | corresponding to the | -| | | coordinate region | -| | | defined by | -| | | ``latInterval, lonInterv | -| | | al.`` | -| | | | -| | | ``latInterval`` and | -| | | ``lonInterval`` are the | -| | | coordinate intervals for | -| | | latitude and longitude, | -| | | respectively. | -| | | | -| | | Each interval is a tuple | -| | | having one of the forms: | -| | | | -| | | - ``(x,y)`` | -| | | - ``(x,y,indicator)`` | -| | | - ``(x,y,indicator,cycl | -| | | e)`` | -| | | - ``None`` | -| | | | -| | | where ``x`` and ``y`` | -| | | are coordinates | -| | | indicating the interval | -| | | ``[x,y)``, and: | -| | | | -| | | ``indicator`` is a | -| | | two-character string, | -| | | where the first | -| | | character is 'c' if the | -| | | interval is closed on | -| | | the left, 'o' if open, | -| | | and the second character | -| | | has the same meaning for | -| | | the right-hand point. | -| | | (Default: 'co'). | -| | | | -| | | If ``cycle`` is | -| | | specified, the axis is | -| | | treated as circular with | -| | | the given cycle value. | -| | | By default, if | -| | | ``grid.isCircular()`` is | -| | | true, the axis is | -| | | treated as circular with | -| | | a default value of | -| | | 360.0. | -| | | | -| | | An interval of ``None`` | -| | | returns the full index | -| | | interval of the axis. | -| | | | -| | | If a mask is defined, | -| | | the subgrid also has a | -| | | mask corresponding to | -| | | the index ranges.Note: | -| | | The result grid is not | -| | | associated with any file | -| | | or dataset. | -+--------------------------+--------------------------+--------------------------+ -| Transient-CurveGrid | ``toCurveGrid(gridid=Non | Convert to a curvilinear | -| | e)`` | grid. If the grid is | -| | | already curvilinear, a | -| | | copy of the grid object | -| | | is returned. ``gridid`` | -| | | is the string identifier | -| | | of the resulting | -| | | curvilinear grid object. | -| | | If unspecified, the grid | -| | | ID is copied. **Note:** | -| | | This method does not | -| | | apply to generic grids. | -+--------------------------+--------------------------+--------------------------+ -| Transient-GenericGrid | ``toGenericGrid(gridid=N | Convert to a generic | -| | one)`` | grid. If the grid is | -| | | already generic, a copy | -| | | of the grid is returned. | -| | | ``gridid`` is the string | -| | | identifier of the | -| | | resulting curvilinear | -| | | grid object. If | -| | | unspecified, the grid ID | -| | | is copied. | -+--------------------------+--------------------------+--------------------------+ - - -Table 2.32 RectGrid Methods, additional to HorizontalGrid - Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Description | -+==========================+==========================+==========================+ -| String | ``getOrder()`` | Get the grid ordering, | -| | | either "yx" if latitude | -| | | is the first axis, or | -| | | "xy" if longitude is the | -| | | first axis. | -+--------------------------+--------------------------+--------------------------+ -| String | ``getType()`` | Get the grid type, | -| | | either "gaussian", | -| | | "uniform", "equalarea", | -| | | or "generic". | -+--------------------------+--------------------------+--------------------------+ -| (Array,Array) | ``getWeights()`` | Get the normalized area | -| | | weight arrays, as a | -| | | tuple | -| | | ``(latWeights, lon | -| | | Weights)``. | -| | | It is assumed that the | -| | | latitude and longitude | -| | | axes are defined in | -| | | degrees. | -| | | | -| | | The latitude weights are | -| | | defined as: | -| | | | -| | | ``latWeights[i] = 0.5 * | -| | | abs(sin(latBounds[i+1]) | -| | | - sin(latBounds[i] | -| | | ))`` | -| | | | -| | | The longitude weights | -| | | are defined as: | -| | | | -| | | ``lonWeights[i] = abs(lo | -| | | nBounds[i+1] - lonBounds | -| | | [i])/360.0`` | -| | | | -| | | For a global grid, the | -| | | weight arrays are | -| | | normalized such that the | -| | | sum of the weights is | -| | | 1.0 | -| | | | -| | | **Example:** | -| | | | -| | | Generate the 2-D weights | -| | | array, such that | -| | | ``weights[i.j]`` is the | -| | | fractional area of grid | -| | | zone ``[i,j]``. | -| | | | -| | | :: | -| | | | -| | | from cdms import MV | -| | | latwts, lonwts = gri | -| | | d.getWeights() | -| | | weights = MV.outerpr | -| | | oduct(latwts, lonwts) | -| | | | -| | | Also see the function | -| | | ``area_weights`` in | -| | | module | -| | | ``pcmdi.weighting``. | -+--------------------------+--------------------------+--------------------------+ -| None | ``setType(gridtype)`` | Set the grid type. | -| | | ``gridtype`` is one of | -| | | "gaussian", "uniform", | -| | | "equalarea", or | -| | | "generic". | -+--------------------------+--------------------------+--------------------------+ -| RectGrid | ``subGrid((latStart,latS | Create a new grid, with | -| | top),(lonStart,lonStop)) | latitude index range | -| | `` | [latStart : latStop] and | -| | | longitude index range | -| | | [lonStart : lonStop]. | -| | | Either index range can | -| | | also be specified as | -| | | None, indicating that | -| | | the entire range of the | -| | | latitude or longitude is | -| | | used. | -| | | | -| | | **Example:** | -| | | | -| | | This creates newgrid | -| | | corresponding to all | -| | | latitudes and index | -| | | range [lonStart:lonStop] | -| | | of oldgrid. | -| | | | -| | | ``newgrid = oldgrid.subG | -| | | rid(None, (lonStart, lon | -| | | Stop))`` | -| | | | -| | | If a mask is defined, | -| | | the subgrid also has a | -| | | mask corresponding to | -| | | the index ranges. | -| | | | -| | | **Note:** The result | -| | | grid is not associated | -| | | with any file or | -| | | dataset. | -+--------------------------+--------------------------+--------------------------+ -| RectGrid | ``transpose()`` | Create a new grid, with | -| | | axis order reversed. The | -| | | grid mask is also | -| | | transposed. | -| | | | -| | | **Note:** The result | -| | | grid is not associated | -| | | with any file or | -| | | dataset. | -+--------------------------+--------------------------+--------------------------+ - - -2.11 Variable -^^^^^^^^^^^^^ - -A Variable is a multidimensional data object, consisting of: - -- a multidimensional data array, possibly masked, -- a collection of attributes -- a domain, an ordered tuple of CoordinateAxis objects. - -A Variable which is contained in a Dataset or CdmsFile is called a -persistent variable. Setting a slice of a persistent Variable writes -data to the Dataset or file, and referencing a Variable slice reads data -from the Dataset. Variables may also be transient, not associated with a -Dataset or CdmsFile. - -Variables support arithmetic operations, including the basic Python -operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations -defined in the MV module. The result of an arithmetic operation is a -transient variable, that is, the axis information is transferred to the -result. - -The methods subRegion and subSlice return transient variables. In -addition, a transient variable may be created with the -cdms.createVariable method. The vcs and regrid module methods take -advantage of the attribute, domain, and mask information in a transient -variable. - - -Table 2.33 Variable Internal Attributes - -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Type | Name | Definition | -+=======================+======================+=============================================================================================================================+ -| Dictionary | ``attributes`` | External attribute dictionary. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| String | ``id`` | Variable identifier. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| String | ``name\_in\_file`` | The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the variable. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Tuple | ``shape`` | The length of each axis of the variable | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.34 Variable Constructors - -+--------------------------------------+--------------------------------------+ -| Constructor | Description | -+======================================+======================================+ -| ``Dataset.createVariable(String id, | Create a Variable in a Dataset. This | -| String datatype, List axes)`` | function is not yet implemented. | -+--------------------------------------+--------------------------------------+ -| ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | -| String datatype, List axesOr- | ``id`` is the name of the variable. | -| Grids)`` | ``datatype`` is the MA or Numeric | -| | typecode, for example, MA.Float. | -| | ``axesOrGrids`` is a list of Axis | -| | and/or Grid objects, on which the | -| | variable is defined. Specifying a | -| | rectilinear grid is equivalent to | -| | listing the grid latitude and | -| | longitude axes, in the order defined | -| | for the grid. \*\*Note:\*\* this | -| | argument can either be a list or a | -| | tuple. If the tuple form is used, | -| | and there is only one element, it | -| | must have a following comma, e.g.: | -| | ``(axisobj,)``. | -+--------------------------------------+--------------------------------------+ -| :: | Create a transient variable, not | -| | associated with a file or dataset. | -| cdms.createVariable(array, typec | ``array`` is the data values: a | -| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numeric | -| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MA | -| s=None,attributes=None, id=None) | typecode of the array. Defaults to | -| | the typecode of array. ``copy`` is | -| | an integer flag: if 1, the variable | -| | is created with a copy of the array, | -| | if 0 the variable data is shared | -| | with array. ``savespace`` is an | -| | integer flag: if set to 1, internal | -| | Numeric operations will attempt to | -| | avoid silent upcasting. ``mask`` is | -| | an array of integers with value 0 or | -| | 1, having the same shape as array. | -| | array elements with a corresponding | -| | mask value of 1 are considered | -| | invalid, and are not used for | -| | subsequent Numeric operations. The | -| | default mask is obtained from array | -| | if present, otherwise is None. | -| | ``fill_value`` is the missing value | -| | flag. The default is obtained from | -| | array if possible, otherwise is set | -| | to 1.0e20 for floating point | -| | variables, 0 for integer-valued | -| | variables. ``grid`` is a rectilinear | -| | grid object. ``axes`` is a tuple of | -| | axis objects. By default the axes | -| | are obtained from array if present. | -| | Otherwise for a dimension of length | -| | n, the default axis has values [0., | -| | 1., ..., double(n)]. ``attributes`` | -| | is a dictionary of attribute values. | -| | The dictionary keys must be strings. | -| | By default the dictionary is | -| | obtained from array if present, | -| | otherwise is empty. ``id`` is the | -| | string identifier of the variable. | -| | By default the id is obtained from | -| | array if possible, otherwise is set | -| | to 'variable\_n' for some integer n. | -+--------------------------------------+--------------------------------------+ - - - -Table 2.35 Variable Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| Variable | ``tvar = var[ i:j, m:n]` | Read a slice of data | -| | ` | from the file or | -| | | dataset, resulting in a | -| | | transient variable. | -| | | Singleton dimensions are | -| | | 'squeezed' out. Data is | -| | | returned in the physical | -| | | ordering defined in the | -| | | dataset. The forms of | -| | | the slice operator are | -| | | listed in Table 2.36 on | -| | | page 102. | -+--------------------------+--------------------------+--------------------------+ -| None | ``var[ i:j, m:n] = array | Write a slice of data to | -| | `` | the external dataset. | -| | | The forms of the slice | -| | | operator are listed in | -| | | Table 2.21 on page 32. | -| | | (Variables in CdmsFiles | -| | | only) | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``tvar = var(selector)`` | Calling a variable as a | -| | | function reads the | -| | | region of data defined | -| | | by the selector. The | -| | | result is a transient | -| | | variable, unless raw=1 | -| | | keyword is specified. | -| | | See "Selectors" on page | -| | | 103. | -+--------------------------+--------------------------+--------------------------+ -| None | ``assignValue(Array ar)` | Write the entire data | -| | ` | array. Equivalent to | -| | | ``var[:] = ar``. | -| | | (Variables in CdmsFiles | -| | | only). | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``astype(typecode)`` | Cast the variable to a | -| | | new datatype. Typecodes | -| | | are as for MV, MA, and | -| | | Numeric modules. | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``clone(copyData=1)`` | Return a copy of a | -| | | transient variable. | -| | | | -| | | If copyData is 1 (the | -| | | default) the variable | -| | | data is copied as well. | -| | | If copyData is 0, the | -| | | result transient | -| | | variable shares the | -| | | original transient | -| | | variables data array. | -+--------------------------+--------------------------+--------------------------+ -| Transient Variable | :: | Return a lat/level | -| | | vertical cross-section | -| | crossSectionRegrid(n | regridded to a new set | -| | ewLevel, newLatitude, me | of latitudes newLatitude | -| | thod="log", missing=None | and levels newLevel. The | -| | , order=None) | variable should be a | -| | | function of latitude, | -| | | level, and (optionally) | -| | | time. | -| | | | -| | | ``newLevel`` is an axis | -| | | of the result pressure | -| | | levels. | -| | | | -| | | ``newLatitude`` is an | -| | | axis of the result | -| | | latitudes. | -| | | | -| | | ``method`` is optional, | -| | | either "log" to | -| | | interpolate in the log | -| | | of pressure (default), | -| | | or "linear" for linear | -| | | interpolation. | -| | | | -| | | ``missing`` is a missing | -| | | data value. The default | -| | | is ``var.getMissing()`` | -| | | | -| | | ``order`` is an order | -| | | string such as "tzy" or | -| | | "zy". The default is | -| | | ``var.getOrder()``. | -| | | | -| | | *See also:* ``regrid``, | -| | | ``pressureRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(n)`` | Get the n-th axis. | -| | | | -| | | ``n`` is an integer. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisIds()`` | Get a list of axis | -| | | identifiers. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``getAxisIndex(axis_spec | Return the index of the | -| | )`` | axis specificed by | -| | | axis\_spec. Return -1 if | -| | | no match. | -| | | | -| | | ``axis_spec`` is a | -| | | specification as defined | -| | | for getAxisList | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisList(axes=None, | Get an ordered list of | -| | omit=None, order=None)` | axis objects in the | -| | ` | domain of the variable. | -| | | | -| | | If ``axes`` is not | -| | | ``None``, include only | -| | | certain axes. Otherwise | -| | | axes is a list of | -| | | specifications as | -| | | described below. Axes | -| | | are returned in the | -| | | order specified unless | -| | | the order keyword is | -| | | given. | -| | | | -| | | If ``omit`` is not | -| | | ``None``, omit those | -| | | specified by an integer | -| | | dimension number. | -| | | Otherwise omit is a list | -| | | of specifications as | -| | | described below. | -| | | | -| | | ``order`` is an optional | -| | | string determining the | -| | | output order. | -| | | | -| | | Specifications for the | -| | | axes or omit keywords | -| | | are a list, each element | -| | | having one of the | -| | | following forms: | -| | | | -| | | - an integer dimension | -| | | index, starting at 0. | -| | | - a string representing | -| | | an axis id or one of | -| | | the strings 'time', | -| | | 'latitude', 'lat', | -| | | 'longitude', 'lon', | -| | | 'lev' or 'level'. | -| | | - a function that takes | -| | | an axis as an | -| | | argument and returns | -| | | a value. If the value | -| | | returned is true, the | -| | | axis matches. | -| | | - an axis object; will | -| | | match if it is the | -| | | same object as axis. | -| | | | -| | | ``order`` can be a | -| | | string containing the | -| | | characters t,x,y,z, or | -| | | -. If a dash ('-') is | -| | | given, any elements of | -| | | the result not chosen | -| | | otherwise are filled in | -| | | from left to right with | -| | | remaining candidates. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisListIndex(axes= | Return a list of indices | -| | None, omit=None, order=N | of axis objects. | -| | one)`` | Arguments are as for | -| | | getAxisList. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getDomain()`` | Get the domain. Each | -| | | element of the list is | -| | | itself a tuple of the | -| | | form | -| | | ``(axis,start,length,tru | -| | | e_length)`` | -| | | where axis is an axis | -| | | object, start is the | -| | | start index of the | -| | | domain relative to the | -| | | axis object, length is | -| | | the length of the axis, | -| | | and true\_length is the | -| | | actual number of | -| | | (defined) points in the | -| | | domain. *See also:* | -| | | ``getAxisList``. | -+--------------------------+--------------------------+--------------------------+ -| Horizontal-Grid | ``getGrid()`` | Return the associated | -| | | grid, or ``None`` if the | -| | | variable is not gridded. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLatitude()`` | Get the latitude axis, | -| | | or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLevel()`` | Get the vertical level | -| | | axis, or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLongitude()`` | Get the longitude axis, | -| | | or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Various | ``getMissing()`` | Get the missing data | -| | | value, or ``None`` if | -| | | not found. | -+--------------------------+--------------------------+--------------------------+ -| String | ``getOrder()`` | Get the order string of | -| | | a spatio-temporal | -| | | variable. The order | -| | | string specifies the | -| | | physical ordering of the | -| | | data. It is a string of | -| | | characters with length | -| | | equal to the rank of the | -| | | variable, indicating the | -| | | order of the variable's | -| | | time, level, latitude, | -| | | and/or longitude axes. | -| | | Each character is one | -| | | of: | -| | | | -| | | - 't': time | -| | | - 'z': vertical level | -| | | - 'y': latitude | -| | | - 'x': longitude | -| | | - '-': the axis is not | -| | | spatio-temporal. | -| | | | -| | | **Example:** | -| | | | -| | | A variable with ordering | -| | | "tzyx" is 4-dimensional, | -| | | where the ordering of | -| | | axes is (time, level, | -| | | latitude, longitude). | -| | | | -| | | **Note:** The order | -| | | string is of the form | -| | | required for the order | -| | | argument of a regridder | -| | | function. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getPaths(*intervals)`` | Get the file paths | -| | | associated with the | -| | | index region specified | -| | | by intervals. | -| | | | -| | | ``intervals`` is a list | -| | | of scalars, 2-tuples | -| | | representing [i,j), | -| | | slices, and/or Ellipses. | -| | | If no ``argument(s)`` | -| | | are present, all file | -| | | paths associated with | -| | | the variable are | -| | | returned. | -| | | | -| | | Returns a list of tuples | -| | | of the form | -| | | (path,slicetuple), where | -| | | path is the path of a | -| | | file, and slicetuple is | -| | | itself a tuple of | -| | | slices, of the same | -| | | length as the rank of | -| | | the variable, | -| | | representing the portion | -| | | of the variable in the | -| | | file corresponding to | -| | | intervals. | -| | | | -| | | **Note:** This function | -| | | is not defined for | -| | | transient variables. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getTime()`` | Get the time axis, or | -| | | ``None`` if not found. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``len(var)`` | The length of the first | -| | | dimension of the | -| | | variable. If the | -| | | variable is | -| | | zero-dimensional | -| | | (scalar), a length of 0 | -| | | is returned. | -| | | | -| | | **Note:** ``size()`` | -| | | returns the total number | -| | | of elements. | -+--------------------------+--------------------------+--------------------------+ -| Transient Variable | ``pressureRegrid (newLev | Return the variable | -| | el, method="log", missin | regridded to a new set | -| | g=None, order=None | of pressure levels | -| | )`` | newLevel. The variable | -| | | must be a function of | -| | | latitude, longitude, | -| | | pressure level, and | -| | | (optionally) time. | -| | | | -| | | ``newLevel`` is an axis | -| | | of the result pressure | -| | | levels. | -| | | | -| | | ``method`` is optional, | -| | | either "log" to | -| | | interpolate in the log | -| | | of pressure (default), | -| | | or "linear" for linear | -| | | interpolation. | -| | | | -| | | ``missing`` is a missing | -| | | data value. The default | -| | | is ``var.getMissing()`` | -| | | | -| | | ``order`` is an order | -| | | string such as "tzyx" or | -| | | "zyx". The default is | -| | | ``var.getOrder()`` | -| | | | -| | | See also: ``regrid``, | -| | | ``crossSectionRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``rank()`` | The number of dimensions | -| | | of the variable. | -+--------------------------+--------------------------+--------------------------+ -| Transient | :: | Return the variable | -| | | regridded to the | -| | regrid (togrid, miss | horizontal grid togrid. | -| | ing=None, order=None, Va | | -| | riable mask=None) | ``missing`` is a Float | -| | | specifying the missing | -| | | data value. The default | -| | | is 1.0e20. | -| | | | -| | | ``order`` is a string | -| | | indicating the order of | -| | | dimensions of the array. | -| | | It has the form returned | -| | | from | -| | | ``variable.getOrder()``. | -| | | For example, the string | -| | | "tzyx" indicates that | -| | | the dimension order of | -| | | array is (time, level, | -| | | latitude, longitude). If | -| | | unspecified, the | -| | | function assumes that | -| | | the last two dimensions | -| | | of array match the input | -| | | grid. | -| | | | -| | | ``mask`` is a Numeric | -| | | array, of datatype | -| | | Integer or Float, | -| | | consisting of ones and | -| | | zeros. A value of 0 or | -| | | 0.0 indicates that the | -| | | corresponding data value | -| | | is to be ignored for | -| | | purposes of regridding. | -| | | If mask is | -| | | two-dimensional of the | -| | | same shape as the input | -| | | grid, it overrides the | -| | | mask of the input grid. | -| | | If the mask has more | -| | | than two dimensions, it | -| | | must have the same shape | -| | | as array. In this case, | -| | | the missing data value | -| | | is also ignored. Such an | -| | | n-dimensional mask is | -| | | useful if the pattern of | -| | | missing data varies with | -| | | level (e.g., ocean data) | -| | | or time. Note: If | -| | | neither missing or mask | -| | | is set, the default mask | -| | | is obtained from the | -| | | mask of the array if | -| | | any. | -| | | | -| | | See also: | -| | | ``crossSectionRegrid``, | -| | | ``pressureRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setAxis(n, axis)`` | Set the n-th axis | -| | | (0-origin index) of to a | -| | | copy of axis. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setAxisList(axislist)` | Set all axes of the | -| | ` | variable. axislist is a | -| | | list of axis objects. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setMissing(value)`` | Set the missing value. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``size()`` | Number of elements of | -| | | the variable. | -+--------------------------+--------------------------+--------------------------+ -| Variable | :: | Read a coordinate region | -| | | of data, returning a | -| | subRegion(*region, t | transient variable. A | -| | ime=None, level=None, la | region is a | -| | titude=None, longitude=N | hyperrectangle in | -| | one, squeeze=0, raw=0) | coordinate space. | -| | | | -| | | ``region`` is an | -| | | argument list, each item | -| | | of which specifies an | -| | | interval of a coordinate | -| | | axis. The intervals are | -| | | listed in the order of | -| | | the variable axes. If | -| | | trailing dimensions are | -| | | omitted, all values of | -| | | those dimensions are | -| | | retrieved. If an axis is | -| | | circular | -| | | (axis.isCircular() is | -| | | true) or cycle is | -| | | specified (see below), | -| | | then data will be read | -| | | with wraparound in that | -| | | dimension. Only one axis | -| | | may be read with | -| | | wraparound. A coordinate | -| | | interval has one of the | -| | | forms listed in Table | -| | | 2.37 on page 102. Also | -| | | see | -| | | ``axis.mapIntervalExt``. | -| | | | -| | | The optional keyword | -| | | arguments ``time``, | -| | | ``level``, ``latitude``, | -| | | and ``longitude`` may | -| | | also be used to specify | -| | | the dimension for which | -| | | the interval applies. | -| | | This is particularly | -| | | useful if the order of | -| | | dimensions is not known | -| | | in advance. An exception | -| | | is raised if a keyword | -| | | argument conflicts with | -| | | a positional region | -| | | argument. | -| | | | -| | | The optional keyword | -| | | argument ``squeeze`` | -| | | determines whether or | -| | | not the shape of the | -| | | returned array contains | -| | | dimensions whose length | -| | | is 1; by default this | -| | | argument is 0, and such | -| | | dimensions are not | -| | | 'squeezed out'. | -| | | | -| | | The optional keyword | -| | | argument ``raw`` | -| | | specifies whether the | -| | | return object is a | -| | | variable or a masked | -| | | array. By default, a | -| | | transient variable is | -| | | returned, having the | -| | | axes and attributes | -| | | corresponding to2,3 the | -| | | region read. If raw=1, | -| | | an MA masked array is | -| | | returned, equivalent to | -| | | the transient variable | -| | | without the axis and | -| | | attribute information. | -+--------------------------+--------------------------+--------------------------+ -| Variable | :: | Read a slice of data, | -| | | returning a transient | -| | subSlice(*specs, tim | variable. This is a | -| | e=None, level=None, lati | functional form of the | -| | tude=None, longitude=Non | slice operator [] with | -| | e, squeeze=0, raw=0) | the squeeze option | -| | | turned off. | -| | | | -| | | ``specs`` is an argument | -| | | list, each element of | -| | | which specifies a slice | -| | | of the corresponding | -| | | dimension. There can be | -| | | zero or more positional | -| | | arguments, each of the | -| | | form: | -| | | | -| | | - a single integer n, | -| | | meaning | -| | | ``slice(n, n+1)`` | -| | | - an instance of the | -| | | slice class | -| | | - a tuple, which will | -| | | be used as arguments | -| | | to create a slice | -| | | - ':', which means a | -| | | slice covering that | -| | | entire dimension | -| | | - Ellipsis (...), which | -| | | means to fill the | -| | | slice list with ':' | -| | | leaving only enough | -| | | room at the end for | -| | | the remaining | -| | | positional arguments | -| | | - a Python slice | -| | | object, of the form | -| | | ``slice(i,j,k)`` | -| | | | -| | | If there are fewer | -| | | slices than | -| | | corresponding | -| | | dimensions, all values | -| | | of the trailing | -| | | dimensions are read. | -| | | | -| | | The keyword arguments | -| | | are defined as in | -| | | subRegion. | -| | | | -| | | There must be no | -| | | conflict between the | -| | | positional arguments and | -| | | the keywords. | -| | | | -| | | In ``(a)-(c)`` and (f), | -| | | negative numbers are | -| | | treated as offsets from | -| | | the end of that | -| | | dimension, as in normal | -| | | Python indexing. | -+--------------------------+--------------------------+--------------------------+ -| String | ``typecode()`` | The Numeric datatype | -| | | identifier. | -+--------------------------+--------------------------+--------------------------+ - -**Example:** Get a region of data. - -Variable ta is a function of (time, latitude, longitude). Read data -corresponding to all times, latitudes -45.0 up to but not -including+45.0, longitudes 0.0 through and including longitude 180.0: - -.. raw:: html - -
- -:: - - data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) - -.. raw:: html - -
- -or equivalently: - -.. raw:: html - -
- -:: - - data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, - 180.0) - -.. raw:: html - -
- -Read all data for March, 1980: - -.. raw:: html - -
- -:: - - data = ta.subRegion(time=('1980-3','1980-4','co')) - -.. raw:: html - -
- - - -Table 2.36 Variable Slice Operators - -+-------------------+---------------------------------------------------------------+ -| Operator | Description | -+===================+===============================================================+ -| ``[i]`` | The ith element, zero-origin indexing. | -+-------------------+---------------------------------------------------------------+ -| ``[i:j]`` | The ith element through, but not including, element j | -+-------------------+---------------------------------------------------------------+ -| ``[i:]`` | The ith element through the end | -+-------------------+---------------------------------------------------------------+ -| ``[:j]`` | The beginning element through, but not including, element j | -+-------------------+---------------------------------------------------------------+ -| ``[:]`` | The entire array | -+-------------------+---------------------------------------------------------------+ -| ``[i:j:k]`` | Every kth element | -+-------------------+---------------------------------------------------------------+ -| ``[i:j, m:n]`` | Multidimensional slice | -+-------------------+---------------------------------------------------------------+ -| ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | -+-------------------+---------------------------------------------------------------+ -| ``[-1]`` | Negative indices ‘wrap around’. -1 is the last element | -+-------------------+---------------------------------------------------------------+ - - - -Table 2.37 Index and Coordinate Intervals - -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| Interval Definition | Example Interval Definition | Example | -+========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ -| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | -| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | -| | | ``'1980-1-3'`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | -| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | -| | | ``slice(,,-1)`` reverses the direction of the axis. | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``':'`` | all axis values of one dimension |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``Ellipsis`` | all values of all intermediate axes |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ - - - -2.11.1 Selectors - -A selector is a specification of a region of data to be selected from a -variable. For example, the statement - -.. raw:: html - -
- -:: - - x = v(time='1979-1-1', level=(1000.0,100.0)) - -.. raw:: html - -
- -means ‘select the values of variable v for time ‘1979-1-1’ and levels -1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are -generally used to represent regions of space and time. - -The form for using a selector is - -.. raw:: html - -
- -:: - - result = v(s) - -.. raw:: html - -
- -where v is a variable and s is the selector. An equivalent form is - -.. raw:: html - -
- -:: - - result = f('varid', s) - -.. raw:: html - -
- -where f is a file or dataset, and ‘varid’ is the string ID of a -variable. - -A selector consists of a list of selector components. For example, the -selector - -.. raw:: html - -
- -:: - - time='1979-1-1', level=(1000.0,100.0) - -.. raw:: html - -
- -has two components: time=’1979-1-1’, and level=(1000.0,100.0). This -illustrates that selector components can be defined with keywords, using -the form: - -.. raw:: html - -
- -:: - - keyword=value - -.. raw:: html - -
- -Note that for the keywords time, level, latitude, and longitude, the -selector can be used with any variable. If the corresponding axis is not -found, the selector component is ignored. This is very useful for -writing general purpose scripts. The required keyword overrides this -behavior. These keywords take values that are coordinate ranges or index -ranges as defined in Table 2.37 on page 102. - -The following keywords are available: Another form of selector -components is the positional form, where the component order corresponds -to the axis order of a variable. For example: - - - -Table 2.38 Selector keywords - -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| Keyword | Description | Value | -+=================+======================================================================+============================================================================+ -| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``grid`` | Regrid the result to the grid. | Grid object | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``raw`` | Return a masked array (MA.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ - -Another form of selector components is the positional form, where the -component order corresponds to the axis order of a variable. For -example: - -.. raw:: html - -
- -:: - - x9 = hus(('1979-1-1','1979-2-1'),1000.0) - -.. raw:: html - -
- -reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and -coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in Table 2.37 on page 102 are treated as positional. Such -selectors are more concise, but not as general or flexible as the other -types described in this section. - -Selectors are objects in their own right. This means that a selector can -be defined and reused, independent of a particular variable. Selectors -are constructed using the cdms.selectors.Selector class. The constructor -takes an argument list of selector components. For example: - -.. raw:: html - -
- -:: - - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x1 = v1(sel) - x2 = v2(sel) - -.. raw:: html - -
- -For convenience CDMS provides several predefined selectors, which can be -used directly or can be combined into more complex selectors. The -selectors time, level, latitude, longitude, and required are equivalent -to their keyword counterparts. For example: - -.. raw:: html - -
- -:: - - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) - -.. raw:: html - -
- -and - -.. raw:: html - -
- -:: - - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) - -.. raw:: html - -
- -are equivalent. Additionally, the predefined selectors -``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` -take arguments ``(startindex, stopindex[, stride])``: - -.. raw:: html - -
- -:: - - from cdms import timeslice, levelslice - x = v(timeslice(0,2), levelslice(16,17)) - -.. raw:: html - -
- -Finally, a collection of selectors is defined in module cdutil.region: - -.. raw:: html - -
- -:: - - from cdutil.region import * - NH=NorthernHemisphere=domain(latitude=(0.,90.) - SH=SouthernHemisphere=domain(latitude=(-90.,0.)) - Tropics=domain(latitude=(-23.4,23.4)) - NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) - SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) - -.. raw:: html - -
- -Selectors can be combined using the & operator, or by refining them in -the call: - -.. raw:: html - -
- -:: - - from cdms.selectors import Selector - from cdms import level - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x1 = hus(sel3) - x2 = hus(sel2, level=1000.0) - -.. raw:: html - -
- - - -2.11.2 Selector examples - -CDMS provides a variety of ways to select or slice data. In the -following examples, variable hus is contained in file sample.nc, and is -a function of (time, level, latitude, longitude). Time values are -monthly starting at 1979-1-1. There are 17 levels, the last level being -1000.0. The name of the vertical level axis is ‘plev’. All the examples -select the first two times and the last level. The last two examples -remove the singleton level dimension from the result array. - -.. raw:: html - -
- -:: - - import cdms - f = cdms.open('sample.nc') - hus = f.variables['hus'] - - # Keyword selection - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) - - # Interval indicator (see mapIntervalExt) - x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) - - # Axis ID (plev) as a keyword - x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) - - # Positional - x9 = hus(('1979-1-1','1979-2-1'),1000.0) - - # Predefined selectors - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) - - from cdms import timeslice, levelslice - x = hus(timeslice(0,2), levelslice(16,17)) - - # Call file as a function - x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) - - # Python slices - x = hus(time=slice(0,2), level=slice(16,17)) - - # Selector objects - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x = hus(sel) - - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x = hus(sel3) - x = hus(sel2, level=1000.0) - - # Squeeze singleton dimension (level) - x = hus[0:2,16] - x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) - - f.close() - -.. raw:: html - -
- - - -2.12 Examples -^^^^^^^^^^^^^ - - -2.12.1 Example 1 ----------------- - -In this example, two datasets are opened, containing surface air -temperature (‘tas’) and upper-air temperature (‘ta’) respectively. -Surface air temperature is a function of (time, latitude, longitude). -Upper-air temperature is a function of (time, level, latitude, -longitude). Time is assumed to have a relative representation in the -datasets (e.g., with units ‘months since basetime’). - -Data is extracted from both datasets for January of the first input year -through December of the second input year. For each time and level, -three quantities are calculated: slope, variance, and correlation. The -results are written to a netCDF file. For brevity, the functions -``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. - -.. raw:: html - -
- -:: - - 1. import cdms - import MV - - # Calculate variance, slope, and correlation of - # surface air temperature with upper air temperature - # by level, and save to a netCDF file. 'pathTa' is the location of - # the file containing 'ta', 'pathTas' is the file with contains 'tas'. - # Data is extracted from January of year1 through December of year2. - def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): - - # Open the files for ta and tas - fta = cdms.open(pathTa) - ftas = cdms.open(pathTas) - - 2. #Get upper air temperature - taObj = fta['ta'] - levs = taObj.getLevel() - - #Get the surface temperature for the closed interval [time1,time2] - tas = ftas('tas', time=(month1,month2,'cc')) - - # Allocate result arrays - newaxes = taObj.getAxisList(omit='time') - newshape = tuple([len(a) for a in newaxes]) - cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') - b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') - v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') - - # Remove seasonal cycle from surface air temperature - tas = removeSeasonalCycle(tas) - - # For each level of air temperature, remove seasonal cycle - # from upper air temperature, and calculate statistics - 5. for ilev in range(len(levs)): - - ta = taObj(time=(month1,month2,'cc'), \ - level=slice(ilev, ilev+1), squeeze=1) - ta = removeSeasonalCycle(ta) - cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) - v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) - - # Write slope, correlation, and variance variables - 6. f = cdms.open('CC_B_V_ALL.nc','w') - f.title = filtered - f.write(b) - f.write(cc) - f.write(v) - f.close() - - 7. if __name__=='__main__': - pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' - pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' - # Process Jan80 through Dec81 - ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') - -.. raw:: html - -
- -**Notes:** - -#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements - arithmetic functions. -#. ``taObj`` is a file (persistent) variable. At this point, no data has - actually been read. This happens when the file variable is sliced, or - when the subRegion function is called. levs is an axis. -#. Calling the file like a function reads data for the given variable - and time range. Note that month1 and month2 are time strings. -#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are - transient variables, not associated with a file. The assigned names - are used when the variables are written. -#. Another way to read data is to call the variable as a function. The - squeeze option removes singleton axes, in this case the level axis. -#. Write the data. Axis information is written automatically. -#. This is the main routine of the script. ``pathTa`` and ``pathTas`` - pathnames. Data is processed from January 1980 through December 1981. - - - -2.12.2 Example 2 ----------------- - -In the next example, the pointwise variance of a variable over time is -calculated, for all times in a dataset. The name of the dataset and -variable are entered, then the variance is calculated and plotted via -the vcs module. - -.. raw:: html - -
- -:: - - #!/usr/bin/env python - # - # Calculates gridpoint total variance - # from an array of interest - # - - import cdms - from MV import * - - # Wait for return in an interactive window - - def pause(): - print Hit return to continue: , - line = sys.stdin.readline() - - 1. # Calculate pointwise variance of variable over time - # Returns the variance and the number of points - # for which the data is defined, for each grid point - def calcVar(x): - # Check that the first axis is a time axis - firstaxis = x.getAxis(0) - if not firstaxis.isTime(): - raise 'First axis is not time, variable:', x.id - - n = count(x,0) - sumxx = sum(x*x) - sumx = sum(x) - variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) - - return variance, n - - if __name__=='__main__': - import vcs, sys - - print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', - path = string.strip(sys.stdin.readline()) - if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' - - 2. # Open the dataset - dataset = cdms.open(path) - - # Select a variable from the dataset - print 'Variables in file:',path - varnames = dataset.variables.keys() - varnames.sort() - for varname in varnames: - - var = dataset.variables[varname] - if hasattr(var,'long_name'): - long_name = var.long_name - elif hasattr(var,'title'): - long_name = var.title - else: - long_name = '?' - - print '%-10s: %s'%(varname,long_name) - print 'Select a variable: ', - 3. varname = string.strip(sys.stdin.readline()) - var = dataset(varname) - dataset.close() - - # Calculate variance, count, and set attributes - variance,n = calcVar(var) - variance.id = 'variance_%s'%var.id - n.id = 'count_%s'%var.id - if hasattr(var,'units'): - variance.units = '(%s)^2'%var.units - - # Plot variance - w=vcs.init() - 4. w.plot(variance) - pause() - w.clear() - w.plot(n) - pause() - w.clear() - -.. raw:: html - -
- -The result of running this script is as follows: - -.. raw:: html - -
- -:: - - % calcVar.py - Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: - - Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml - albt : Albedo TOA [%] - albtcs : Albedo TOA clear sky [%] - rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] - rlut : LW radiation TOA (OLR) [W/m^2] - rlutcs : LW radiation upward TOA clear sky [W/m^2] - rscrft : SW Cloud Radiation Forcing TOA [W/m^2] - rsdt : SW radiation downward TOA [W/m^2] - rsut : SW radiation upward TOA [W/m^2] - rsutcs : SW radiation upward TOA clear sky [W/m^2] - Select a variable: albt - - - - Hit return to continue: - - - -.. raw:: html - -
- -**Notes:** - -#. n = count(x, 0) returns the pointwise number of valid values, summing - across axis 0, the first axis. count is an MV function. -#. dataset is a Dataset or CdmsFile object, depending on whether a .xml - or .nc pathname is entered. dataset.variables is a dictionary mapping - variable name to file variable. -#. var is a transient variable. -#. Plot the variance and count variables. Spatial longitude and latitude - information are carried with the computations, so the continents are - plotted correctly. - -.. raw:: html - -
- -`Previous `__ `Table of -Contents `__ -`Next `__ - -.. raw:: html - -
- -.. raw:: html - - - -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- -Project Information - -- `Mission `__ -- `Governance `__ -- `Acknowledgements `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Contribute -^^^^^^^^^^ - -- `GitHub Project Page `__ -- `Wiki `__ -- `Report a Bug `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Press -^^^^^ - -- `Presentations `__ -- `Publications `__ -- `Reports `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Info -^^^^ - -- `Animations `__ -- `Design Documents `__ -- `Use Cases `__ - -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- --------------- - -.. raw:: html - - - -.. raw:: html - -
- -.. |image0| image:: /images/uvcdat.png - :class: logo - :target: / -.. |Diagram 1| image:: /images/diagram1.jpg - diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst deleted file mode 100644 index dae840c8..00000000 --- a/docs/source/manual/cdms_3.rst +++ /dev/null @@ -1,218 +0,0 @@ -CHAPTER 3 cdtime Module ------------------------ - -3.1 Time types -^^^^^^^^^^^^^^ - -The ``cdtime`` module implements the CDMS time types, methods, and -calendars. These are made available with the command - -.. doctest:: - - >>> import cdtime - -Two time types are available: relative time and component time. Relative -time is time relative to a fixed base time. It consists of: - -- a units string, of the form ‘units since basetime’, and -- a floating-point value - -For example, the time “28.0 days since 1996-1-1” has value=28.0, and -units=’days since 1996-1-1’ - -Component time consists of the integer fields year, month, day, hour, -minute, and the floating-point field second. A sample component time is -``1996-2-28 12:10:30.0`` - -The ``cdtime`` module contains functions for converting between these -forms, based on the common calendars used in climate simulation. Basic -arithmetic and comparison operators are also available. - -3.2 Calendars -^^^^^^^^^^^^^ - -A calendar specifies the number of days in each month, for a given year. -cdtime supports these calendars: - -- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap - years, except century years not evenly divisible by 400. This is - sometimes called the proleptic Gregorian calendar, meaning that the - algorithm for leap years applies for all years. -- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates - before 158210-15 are encoded with the Julian calendar, otherwise are - encoded with the Gregorian calendar. The day immediately following - 1582-10-4 is 1582-10-15. This is the default calendar. -- ``cdtime.JulianCalendar``: years evenly divisible by four are leap - years, -- ``cdtime.NoLeapCalendar``: all years have 365 days, -- ``cdtime.Calendar360``: all months have 30 days. - -Several ``cdtime`` functions have an optional calendar argument. The -default calendar is the ``MixedCalendar``. The default calendar may be -changed with the command: - - -``cdtime.DefaultCalendar = newCalendar`` - -3.3 Time Constructors -^^^^^^^^^^^^^^^^^^^^^ - -The following table describes the methods for creating time types. - - -.. csv-table:: Time Constructors - :header: "Type", "Constructor", "Defintion" - :widths: 10, 40, 80 - - "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." - ,, "``value`` is an integer or floating point value." - ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" - ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" - - "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." - ,,"``year`` is an integer." - ,,"``month`` is an integer in the range 1 .. 12" - ,,"``day`` is an integer in the range 1 .. 31" - ,,"``hour`` is an integer in the range 0 .. 23" - ,,"``minute`` is an integer in the range 0 .. 59" - ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" - - -3.4 Relative Time -^^^^^^^^^^^^^^^^^ - -A relative time type has two members, value and units. Both can be set. - -Table 3.2 Relative Time Members -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -+----------+---------+-------------------------------------------------------+ -| Type | Name | Summary | -+==========+=========+=======================================================+ -| Float | value | Number of units | -+----------+---------+-------------------------------------------------------+ -| String | units | Relative units, of the form “unit(s) since basetime | -+----------+---------+-------------------------------------------------------+ - -3.5 Component Time -^^^^^^^^^^^^^^^^^^ - -A component time type has six members, all of which are settable. - -.. csv-table:: Table 3.3 Component Time - :header: "Type", "Name", "Summary" - :widths: 15, 15, 50 - - "Integer", "year", "Year value" - "Integer", "month", "Month, in the range 1..12" - "Integer", "day", "Day of month, in the range 1 .. 31" - "Integer", "hour", "Hour, in the range 0 .. 23" - "Integer", "minute", "Minute, in the range 0 .. 59" - "Float", "second", "Seconds, in the range 0.0 .. 60.0" - -3.6 Time Methods -^^^^^^^^^^^^^^^^ - -The following methods apply both to relative and component times. - -.. csv-table:: Table 3.4 Time Methods - :header: "Type", "Method", "Definition" - :widths: 20, 75, 80 - - "Comptime or Reltime", "``t.add(value, intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" - ,, "``calendar`` is the calendar type." - "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." - ,, "``t2`` is the time to compare." - ,, "``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" - ,, "``calendar`` is the calendar type. " - "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." - ,, "``calendar`` is the calendar type." - "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." - - -3.7 Examples -^^^^^^^^^^^^ -.. doctest:: - - >>> from cdtime import * - >>> c = comptime(1996,2,28) - >>> r = reltime(28,"days since 1996-1-1") - >>> print r.add(1,Day) - 29.000000 days since 1996-1-1 - >>> print c.add(36,Hours) - 1996-2-29 12:0:0.0 - - -**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising. - -.. doctest:: - - >>> c = comptime(1979,8,31) - >>> c.add(1,Month) - 1979-9-1 0:0:0.0 - - -In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months: - -.. doctest:: - - >>> c = comptime(1979,8,31) - >>> c.add(2,Years) - 1981-8-1 0:0:0.0 - -Compare time values. - -.. doctest:: - - >>> from cdtime import * - >>> r = cdtime.reltime(28,"days since 1996-1-1") - >>> c = comptime(1996,2,28) - >>> print c.cmp(r) - 1 -# >>> print r.cmp(c) -# -1 -# >>> print r.cmp(r) -# 1 - -Subtract an interval of time. - -.. doctest:: - - >>> from cdtime import * - >>> r = cdtime.reltime(28,"days since 1996-1-1") - >>> c = comptime(1996,2,28) - >>> print r.sub(10,Days) - 18.000000 days since 1996-1-1 - >>> print c.sub(30,Days) - 1996-1-29 0:0:0.0 - - -For intervals of years or months, see the **note** under add() in the example above. - -Convert to component time. - -.. doctest:: - - >>> r = cdtime.reltime(28,"days since 1996-1-1") - >>> r.tocomp() - 1996-1-29 0:0:0.0 - - -Convert to relative time. - -.. doctest:: - - >>> c = comptime(1996,2,28) - >>> print c.torel("days since 1996-1-1") - 58.000000 days since 1996-1-1 - >>> r = reltime(28,"days since 1996-1-1") - >>> print r.torel("days since 1995") - 393.000000 days since 1995 - >>> print r.torel("days since 1995").value - 393.0 - diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index b07efaa1..91ed6ecf 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -14,6 +14,15 @@ CDMS provides several methods for interpolating gridded data: 4.1.1 CDMS horizontal regridr ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + The simplest method to regrid a variable from one rectangular, lat/lon grid to another is to use the regrid function defined for variables. @@ -261,10 +270,12 @@ regridded to those axes. >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") >>> ta=f('ta') - >>> levOut=cdms2.createAxis([1000.0,950.]) - >>> latOut=ta.getLatitude()[10:20] >>> ta.shape (11, 17, 73, 144) + >>> levOut=cdms2.createAxis([1000.0,950.]) + >>> levOut.designateLevel() + >>> latOut=cdms2.createAxis(ta.getLatitude()[10:20]) + >>> latOut.designateLatitude() >>> ta0 = ta[0,:] >>> ta0.getAxisIds() ['level', 'latitude', 'longitude'] @@ -432,7 +443,7 @@ The bicubic regridder takes four arguments: .. doctest:: - >>> outdat = regridf(t42prc, gradlat, gradlon, gradlatlon) + >>> # outdat = regridf(t42prc, gradlat, gradlon, gradlatlon) A regridder function also has associated methods to retrieve the @@ -489,7 +500,7 @@ Regrid data to a uniform output grid. >>> f = cdms2.open('clt.nc') >>> cltf = f.variables['clt'] >>> ingrid = cltf.getGrid() - >>> outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) >>> regridFunc = Regridder(ingrid, outgrid) >>> newrls = regridFunc(cltf) >>> f.close() @@ -521,10 +532,10 @@ Get a mask from a separate file, and set as the input grid mask. >>> # >>> f = cdms2.open('clt.nc') >>> cltf = f.variables['clt'] - >>> ingrid = cltf.getGrid() + >>> outgrid = cltf.getGrid() >>> g = cdms2.open('geos5-sample.nc') >>> ozoneg = g.variables['ozone'] - >>> outgrid = ozoneg.getGrid() + >>> ingrid = ozoneg.getGrid() >>> regridFunc = Regridder(ingrid,outgrid) >>> uwmaskvar = g.variables['uwnd'] >>> uwmask = uwmaskvar[:]<0 @@ -578,19 +589,23 @@ of the result. .. doctest:: - >>> from cdms.MV import * - >>> outgrid = cdms.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) - >>> outlatw, outlonw = outgrid.getWeights() - >>> outweights = outerproduct(outlatw, outlonw) - >>> grid = var.getGrid() - >>> sample = var[0,0] - >>> latw, lonw = grid.getWeights() - >>> weights = outerproduct(latw, lonw) - >>> inmask = where(greater(absolute(sample),1.e15),0,1) - >>> mean = add.reduce(ravel(inmask*weights*sample))/add.reduce(ravel(inmask*weights)) - >>> regridFunc = Regridder(grid, outgrid) - >>> outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) - >>> outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) + >>> import cdms2 + >>> from cdms2.MV2 import * + >>> from regrid2 import Regridder + >>> f = cdms2.open("ta_ncep_87-6-88-4.nc") + >>> var = f('ta') + >>> outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> outlatw, outlonw = outgrid.getWeights() + >>> outweights = outerproduct(outlatw, outlonw) + >>> grid = var.getGrid() + >>> sample = var[0,0] + >>> latw, lonw = grid.getWeights() + >>> weights = outerproduct(latw, lonw) + >>> inmask = where(greater(absolute(sample),1.e15),0,1) + >>> mean = add.reduce(ravel(inmask*weights*sample))/add.reduce(ravel(inmask*weights)) + >>> regridFunc = Regridder(grid, outgrid) + >>> outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) + >>> outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) +--------+----------------------------------------------------------------------------------------------------------+ From 889d7145ef829a8045650dd5846745ae901f4a60 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 18 Oct 2017 12:04:23 -0700 Subject: [PATCH 020/239] add other chapters --- docs/source/index.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index a3877a9e..8ab57f9f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,11 +9,10 @@ Welcome to cdms2's documentation! Contents: .. toctree:: + manual/cdms_1 + manual/cdms_2 + manual/cdms_3 manual/cdms_4 - -# manual/cdms_2 -# manual/cdms_3 -# manual/cdms_4 # AbstractAxis # AbstractVariable # avariable From e9f207ab230bec9e38d6649b6967261315d2e99e Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 18 Oct 2017 14:24:41 -0700 Subject: [PATCH 021/239] finish chapter 4 --- docs/source/index.rst | 1 + docs/source/manual/cdms_4.rst | 78 ++++++++++++++++------------------- 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 8ab57f9f..980760fe 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ Contents: manual/cdms_2 manual/cdms_3 manual/cdms_4 + # AbstractAxis # AbstractVariable # avariable diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 91ed6ecf..c2452c72 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -17,12 +17,18 @@ CDMS provides several methods for interpolating gridded data: .. testsetup:: * import requests - fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc' ] + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) The simplest method to regrid a variable from one rectangular, lat/lon grid to another is to use the regrid function defined for variables. @@ -643,46 +649,34 @@ Regrid from a curvilinear to a generic grid, using a conservative remapping. Compute the area-weighted means on input and output for comparison. -.. raw:: html - -
- -:: - - import cdms, regrid, MA - - # Open the SCRIP remapping file and data file - direc = '' - fremap = cdms.open(direc+'rmp_T42_to_C02562_conserv.nc') - fdat = cdms.open(direc+'sampleT42Grid.nc') - - # Input data array - dat = fdat('src_array') - - # Read the SCRIP regridder - regridf = regrid.readRegridder(fremap) - - # Regrid the variable - outdat = regridf(dat) - - # Get the cell area and fraction arrays. Areas are computed only - # for conservative regridding. - srcfrac = regridf.getSourceFraction() - srcarea = regridf.getSourceArea() - dstfrac = regridf.getDestinationFraction() - dstarea = regridf.getDestinationArea() - - # Calculate area-weighted means - inmean = MA.sum(srcfrac*srcarea*MA.ravel(dat)) / MA.sum(srcfrac*srcarea) - outmean = MA.sum(dstfrac*dstarea*MA.ravel(outdat)) / MA.sum(dstfrac*dstarea) - print 'Input mean:', inmean - print 'Output mean:', outmean - - fremap.close) - fdat.close() - -.. raw:: html - -
+.. doctest:: + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> import cdms2, regrid2, MV2 + >>> # Open the SCRIP remapping file and data file + >>> fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc') + >>> fdat = cdms2.open('xieArkin-T42.nc') + >>> # Input data array + >>> dat = fdat('prc')[0,:] + >>> # Read the SCRIP regridder + >>> regridf = regrid2.readRegridder(fremap) + >>> # Regrid the variable + >>> outdat = regridf(dat) + >>> # Get the cell area and fraction arrays. Areas are computed only + >>> # for conservative regridding. + >>> srcfrac = regridf.getSourceFraction() + >>> srcarea = regridf.getSourceArea() + >>> dstfrac = regridf.getDestinationFraction() + >>> dstarea = regridf.getDestinationArea() + >>> # calculate area-weighted means + >>> inmean = MV2.sum(srcfrac*srcarea*MV2.ravel(dat)) / MV2.sum(srcfrac*srcarea) + >>> outmean = MV2.sum(dstfrac*dstarea*MV2.ravel(outdat)) / MV2.sum(dstfrac*dstarea) + >>> print 'Input mean:', inmean + Input mean: 2.60376502339 + >>> print 'Output mean:', outmean + Output mean: 2.60376502339 + >>> fremap.close() + >>> fdat.close() From 09da492e1640a13919df596a3cbf4099e4bf5f3d Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Oct 2017 16:21:15 -0700 Subject: [PATCH 022/239] add chapter 5 --- docs/source/index.rst | 1 + docs/source/manual/cdms_1.rst | 846 +++++ docs/source/manual/cdms_2.rst | 3945 ++++++++++++++++++++ docs/source/manual/cdms_3.rst | 234 ++ docs/source/manual/cdms_5.rst | 206 + docs/source/manual/images/cdms_classes.jpg | Bin 0 -> 79617 bytes docs/source/manual/images/diagram1.jpg | Bin 0 -> 13530 bytes 7 files changed, 5232 insertions(+) create mode 100644 docs/source/manual/cdms_1.rst create mode 100644 docs/source/manual/cdms_2.rst create mode 100644 docs/source/manual/cdms_3.rst create mode 100644 docs/source/manual/cdms_5.rst create mode 100644 docs/source/manual/images/cdms_classes.jpg create mode 100644 docs/source/manual/images/diagram1.jpg diff --git a/docs/source/index.rst b/docs/source/index.rst index 980760fe..7af76293 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ Contents: manual/cdms_2 manual/cdms_3 manual/cdms_4 + manual/cdms_5 # AbstractAxis # AbstractVariable diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst new file mode 100644 index 00000000..73d7f24e --- /dev/null +++ b/docs/source/manual/cdms_1.rst @@ -0,0 +1,846 @@ +CHAPTER 1 +--------- + +CHAPTER 1 Introduction +~~~~~~~~~~~~~~~~~~~~~~ + +1.1 Overview +^^^^^^^^^^^^ + +The Climate Data Management System is an object-oriented data management +system, specialized for organizing multidimensional, gridded data used +in climate analysis and simulation. + +CDMS is implemented as part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT), which uses the Python language. The examples in +this chapter assume some familiarity with the language and the Python +Numeric module (http://www.numpy.org). A number of excellent tutorials +on Python are available in books or on the Internet. For example, see +the `Python Foundation's homepage `__. + +1.2 Variables +^^^^^^^^^^^^^ + +The basic unit of computation in CDMS is the variable. A variable is +essentially a multidimensional data array, augmented with a domain, a +set of attributes, and optionally a spatial and/or temporal coordinate +system (see `Coordinate Axes <#1.4>`__). As a data array, a variable can +be sliced to obtain a portion of the data, and can be used in arithmetic +computations. For example, if ``u`` and ``v`` are variables representing +the eastward and northward components of wind speed, respectively, and +both variables are functions of time, latitude, and longitude, then the +velocity for time 0 (first index) can be calculated as + +.. doctest:: + + >>> from cdms2 import MV + >>> vel = MV.sqrt(u[0]**2 + v[0]**2) + +This illustrates several points: + +- Square brackets represent the slice operator. Indexing starts at 0, + so ``u[0]`` selects from variable ``u`` for the first timepoint. The + result of this slice operation is another variable. The slice + operator can be multidimensional, and follows the syntax of Numeric + Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data + for the first ten timepoints, at all latitudes, for the second + longitude. +- Variables can be used in computation. ``**`` is the Python + exponentiation operator. +- Arithmetic functions are defined in the ``cdms.MV`` module. +- Operations on variables carry along the corresponding metadata where + applicable. In the above example, ``vel`` has the same latitude and + longitude coordinates as ``u`` and ``v``, and the time coordinate is + the first time of ``u`` and ``v``. + +1.3 File I/O +^^^^^^^^^^^^ + +A variable can be obtained from a file or collection of files, or can be +generated as the result of a computation. Files can be in any of the +self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS +control file), or PCMDI DRS. (HDF and DRS support is optional, and is +configured at the time UV-CDAT is installed.) For instance, to read data +from file sample.nc into variable u: + +.. testsetup:: * + + import MV2 + import cdms2 + import cdat_info + import requests + f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') + f2 = cdms2.open(cdat_info.get_sampledata_path()+'/geos5-sample.nc') + u = f('u') + v = f('v') + smallvar=MV2.reshape(MV2.arange(20),(4,5),id='small variable').astype(MV2.float32) + largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') + +Data can be read by index or by world coordinate values. The following +reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k +such that i <= k < j): + +.. doctest:: + + >>> n = 0 + >>> u0 = f('u',time=slice(n,n+1)) + +To read ``u`` at time 1.: + +.. doctest:: + + >>> u1 = f('u',time=1.) + +A variable can be written to a file with the write function: + +.. doctest:: + + >>> g = cdms2.open('sample2.nc','w') + >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >> g.close() + +1.4 Coordinate Axes +^^^^^^^^^^^^^^^^^^^ + +A coordinate axis is a variable that represents coordinate information. +Typically an axis is associated with one or more variables in a file or +dataset, to represent the indexing and/or spatiotemporal coordinate +system(s) of the variable(s). + +Often in climate applications an axis is a one-dimensional variable +whose values are floating-point and strictly monotonic. In some cases an +axis can be multidimensional (see `Grids <#1.9>`__). If an axis is +associated with one of the canonical types latitude, longitude, level, +or time, then the axis is called tep emporal . + +The shape and physical ordering of a variable is represented by the +variables domain , an ordered tuple of one-dimensional axes. In the +previous example, the domain of the variable u is the tuple (time, +latitude, longitude). This indicates the order of the dimensions, with +the slowest- varying dimension listed first (time). The domain may be +accessed with the ``getAxisList()`` method: + +.. doctest:: + + >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + [ id: time1 + Designated a time axis. + units: months since 1978-12 + Length: 1 + First: 1.0 + Last: 1.0 + Other axis attributes: + calendar: gregorian + axis: T + Python id: ... + , id: plev + Designated a level axis. + units: hPa + Length: 2 + First: 200.0 + Last: 850.0 + Other axis attributes: + axis: Z + realtopology: linear + Python id: ... + , id: latitude1 + Designated a latitude axis. + units: degrees_north + Length: 80 + First: -88.2884 + Last: 88.2884 + Other axis attributes: + axis: Y + realtopology: linear + Python id: ... + , id: longitude1 + Designated a longitude axis. + units: degrees_east + Length: 97 + First: -180.0 + Last: 180.0 + Other axis attributes: + axis: X + topology: circular + modulo: 360.0 + realtopology: linear + Python id: ... + ] + + +In the above example, the domain elements are axes that are also +spatiotemporal. In general it is not always the case that an element of +a domain is spatiotemporal: + +- An axis in the domain of a variable need not be spatiotemporal. For + example, it may represent a range of indices, an index coordinate + system. +- The latitude and/or longitude coordinate axes associated with a + variable need not be elements of the domain. In particular this will + be true if the variable is defined on a non-rectangular grid (see `Grids <#1.9>`__). + +As previously noted, a spatial and/or temporal coordinate system may be +associated with a variable. The methods getLatitude, getLongitude, +getLevel, and getTime return the associated coordinate axes. For +example: + +.. doctest:: + + >>> t = u.getTime() + >>> print t[:] + [ 1.] + >>> print t.units + months since 1978-12 + +1.5 Attributes +^^^^^^^^^^^^^^ + +As mentioned above, variables can have associated attributes , +name-value pairs. In fact, nearly all CDMS objects can have associated +attributes, which are accessed using the Python dot notation: + +.. doctest:: + + >>> u.units='m/s' + >>> print u.units + m/s + +Attribute values can be strings, scalars, or 1-D Numeric arrays. + +When a variable is written to a file, not all the attributes are +written. Some attributes, called internal attributes, are used for +bookkeeping, and are not intended to be part of the external file +representation of the variable. In contrast, external attributes are +written to an output file along with the variable. By default, when an +attribute is set, it is treated as external. Every variable has a field +attributes, a Python dictionary that defines the external attributes: + +.. doctest:: + + >>> print u.attributes.keys() + ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] + +The Python dir command lists the internal attribute names: + +.. doctest:: + + >>> dir(u) + ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] + +In general internal attributes should not be modified directly. One +exception is the id attribute, the name of the variable. It is used in +plotting and I/O, and can be set directly. + +1.6 Masked values +^^^^^^^^^^^^^^^^^ + +Optionally, variables have a mask that represents where data are +missing. If present, the mask is an array of ones and zeros having the +shape of the data array. A mask value of one indicates that the +corresponding data array element is missing or invalid. + +Arithmetic operations in CDMS take missing data into account. The same +is true of the functions defined in the cdms.MV module. For example: + +.. doctest:: + + >>> a = MV2.array([1,2,3]) # Create array a, with no mask + >>> b = MV2.array([4,5,6]) # Same for b + >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + variable_... + masked_array(data = [5 7 9], + mask = False, + fill_value = 999999) + + + >>> a[1]=MV2.masked # Mask the second value of a a.mask() + >>> a.mask + array([False, True, False], dtype=bool) + >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + variable_... + masked_array(data = [5 -- 9], + mask = [False True False], + fill_value = 999999) + + + +When data is read from a file, the result variable is masked if the file +variable has a missing_value attribute. The mask is set to one for +those elements equal to the missing value, zero elsewhere. If no such +attribute is present in the file, the result variable is not masked. + +When a variable with masked values is written to a file, data values +with a corresponding mask value of one are set to the value of the +variables ``missing_value`` attribute. The data and ``missing_value`` +attribute are then written to the file. + +Masking is covered in `Section 2.9 `__. See also the +documentation of the Python Numeric and MA modules, on which ``cdms.MV`` +is based, at + +`http://www.numpy.org/ `__. + +1.7 File Variables +^^^^^^^^^^^^^^^^^^ + +A variable can be obtained either from a file, a collection of files, or +as the result of computation. Correspondingly there are three types of +variables in CDMS: + +- *file variable* is a variable associated with a single data file. + Setting or referencing a file variable generates I/O operations. +- A *dataset variable* is a variable associated with a collection of + files. Reference to a dataset variable reads data, possibly from + multiple files. Dataset variables are read-only. +- *transient variable* is an in-memory object not associated with a + file or dataset. Transient variables result from a computation or I/O + operation. + +Typical use of a file variables is to inquire information about the +variable in a file without actually reading the data for the variables. +A file variable is obtained by applying the slice operator [] to a file, +passing the name of the variable, or by calling the getVariable +function. Note that obtaining a file variable does not actually read the +data array: + +.. doctest:: + + >>> u = f.getVariable('u') # or u=f['u'] + >>> u.shape + (1, 2, 80, 97) + +File variables are also useful for fine-grained I/O. They behave like +transient variables, but operations on them also affect the associated +file. Specifically: + +- slicing a file variable reads data, +- setting a slice writes data, +- referencing an attribute reads the attribute, +- setting an attribute writes the attribute, +- and calling a file variable like a function reads data associated + with the variable: + +.. doctest:: + + >>> import os + >>> os.system("cp clt.nc /tmp") + 0 + >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write + >>> uvar = f['u'] # Note square brackets + >>> uvar.shape + (1, 2, 80, 97) + >>> u0 = uvar[0] # Reads data from sample.nc + >>> u0.shape + (2, 80, 97) + >>> uvar[1]=u0 # Writes data to sample.nc + >>> uvar.units # Reads the attribute 'm/s' + 'm/s' + >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data + >>> f.close() # Save changes to clt.nc (I/O may be buffered) + + +For transient variables, the data is printed only if the size of the array is less +than the print limit . This value can be set with the function +MV.set_print_limit to force the data to be printed: + +.. doctest:: + + >>> MV2.get_print_limit() # Current limit 1000 + 1000 + >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + small variable + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.] + [ 10. 11. 12. 13. 14.] + [ 15. 16. 17. 18. 19.]], + mask = + False, + fill_value = 999999.0) + >>> MV2.set_print_limit(100) + >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + large variable + masked_array(data = + [[ 0. 1. 2. ..., 17. 18. 19.] + [ 20. 21. 22. ..., 37. 38. 39.] + [ 40. 41. 42. ..., 57. 58. 59.] + ..., + [ 340. 341. 342. ..., 357. 358. 359.] + [ 360. 361. 362. ..., 377. 378. 379.] + [ 380. 381. 382. ..., 397. 398. 399.]], + mask = False, + fill_value = 999999.0) + +The datatype of the variable is determined with the typecode function: + +.. doctest:: + + >>> u.typecode() + 'f' + +1.8 Dataset Variables +^^^^^^^^^^^^^^^^^^^^^ + +The third type of variable, a *dataset variable*, is associated with a +*dataset*, a collection of files that is treated as a single file. A +dataset is created with the ``cdscan`` utility. This generates an XML +metafile that describes how the files are organized and what metadata +are contained in the files. In a climate simulation application, a +dataset typically represents the data generated by one run of a general +circulation or coupled ocean-atmosphere model. + +For example, suppose data for variables u and v are stored in six files: + +1. u_2000.nc, +2. u_2001.nc, +3. u_2002.nc, +4. v_2000.nc, +5. v_2001.nc, +6. v_2002.nc. + +A metafile can be generated with the command: + +**$ cdscan -x cdsample.xml [uv]*.nc** + +The metafile **cdsample.xml** is then used like an ordinary data file: + +.. doctest:: + + >>> import os + >>> os.system("cdscan -x cdsample.xml [uv]*.nc") + 0 + >>> f = cdms2.open('cdsample.xml') + >>> u = f('u') + >>> u.shape + (3, 16, 32) + +1.9 Grids +^^^^^^^^^ + +A latitude-longitude grid represents the coordinate information +associated with a variable. A grid encapsulates: + +- latitude, longitude coordinates +- grid cell boundaries +- area weights + +CDMS defines a rich set of grid types to represent the variety of +coordinate systems used in climate model applications. Grids can be +categorized as rectangular or nonrectangular. + +A rectangular grid has latitude and longitude axes that are +one-dimensional, with strictly monotonic values. The grid is essentially +the Cartesian product of the axes. If either criterion is not met, the +grid is nonrectangular . + +CDMS supports two types of nonrectangular grid: + +- A curvilinear grid consists of a latitude and longitude axis, each of + which is a two-dimensional coordinate axis. Curvilinear grids are + often used in ocean model applications. +- A generic grid consists of a latitude and longitude axis, each of + which is an auxiliary one-dimensional coordinate axis. An auxiliary + axis has values that are not necessarily monotonic. As the name + suggests, generic grids can represent virtually any type of grid. + However, it is more difficult to determine adjacency relationships + between grid points. + +1.9.1 Example: a curvilinear grid +''''''''''''''''''''''''''''''''' + +In this example, variable sample is defined on a 128x192 curvilinear +grid. Note that: + +- The domain of variable sample is ( y , x ) where y and x are index + coordinate axes. +- The curvilinear grid associated with sample consists of axes ( lat , + lon ), each a two-dimensional coordinate axis. +- lat and lon each have domain ( y , x ) + +.. doctest:: + + >>> f = cdms2.open('sampleCurveGrid4.nc') + + + >>> # lat and lon are coordinate axes, but are grouped with data variables + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + + >>> # y and x are index coordinate axes + >>> f.axes.keys() + ['nvert', 'x', 'y'] + + >>> # Read data for variable sample + >>> sample = f('sample') + + >>> # The associated grid g is curvilinear + >>> g = sample.getGrid() + + >>> # The domain of the variable consfigists of index axes + >>> sample.getAxisIds() + ['y', 'x'] + + >>> # Get the coordinate axes associated with the grid + >>> lat = g.getLatitude() # or sample.getLatitude() + >>> lon = g.getLongitude() # or sample.getLongitude() + + >>> # lat and lon have the same domain, a subset of the domain of 'sample' + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are variables ... + >>> lat.shape + (32, 48) + + >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + lat + masked_array(data = + [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 + -76.08465554] + [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 + -73.92641847] + [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 + -71.44420823] + ..., + [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 + 42.32854943] + [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 + 42.70106429] + [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 + 43.0307341 ]], + mask = + False, + fill_value = 1e+20) + + >>> lat_in_radians = lat*MV2.pi/180.0 + +.. figure:: images/curvilinear_grid.jpg + :alt: curvilinear grid + + Figure1: Curvilinear Grid + +1.9.2 Example: a generic grid +''''''''''''''''''''''''''''' + +In this example variable zs is defined on a generic grid. Figure 2 +illustrates the grid, in this case a geodesic grid. + +.. doctest:: + + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + >>> f.axes.keys() + ['nvert', 'x', 'y'] + >>> zs = f('sample') + >>> g = zs.getGrid() + >>> g + + >>> lat = g.getLatitude() + >>> lon = g.getLongitude() + >>> lat.shape + (32, 48) + >>> lon.shape # variable zs is defined in terms of a single index coordinate + (32, 48) + >>> # axis, 'cell' + >>> zs.shape + (32, 48) + >>> zs.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are also defined in terms of the cell axis + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are one-dimensional, 'auxiliary' coordinate + >>> # axes: values are not monotonic + >>> lat.__class__ + + + +.. figure:: images/generic_grid.jpg + :alt: generic grid + + Figure 2: Generic Grid + +Generic grids can be used to represent any of the grid types. The method +toGenericGrid can be applied to any grid to convert it to a generic +representation. Similarly, a rectangular grid can be represented as +curvilinear. The method toCurveGrid is used to convert a non-generic +grid to curvilinear representation: + +.. doctest:: * + + >>> f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') + >>> clt = f('clt') + >>> rectgrid = clt.getGrid() + >>> rectgrid.shape + (46, 72) + >>> curvegrid = rectgrid.toCurveGrid() + >>> curvegrid + + >>> genericgrid = curvegrid.toGenericGrid() + >>> genericgrid + + +1.10 Regridding +^^^^^^^^^^^^^^^ + +Regridding is the process of mapping variables from one grid to another. +CDMS supports two forms of regridding. Which one you use depends on the +class of grids being transformed: + +- To interpolate from one rectangular grid to another, use the built-in + CDMS regridder. CDMS also has built-in regridders to interpolate from + one set of pressure levels to another, or from one vertical + cross-section to another. +- To interpolate from any lat-lon grid, rectangular or non-rectangular, + use the SCRIP regridder. + +1.10.1 CDMS Regridder +''''''''''''''''''''' + +The built-in CDMS regridder is used to transform data from one +rectangular grid to another. For example, to regrid variable ``u`` (from +a rectangular grid) to a 96x192 rectangular Gaussian grid: + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') + >>> u.shape + (1, 2, 80, 97) + >>> t63_grid = cdms2.createGaussianGrid(96) + >>> u63 = u.regrid(t63_grid) + >>> u63.shape + (1, 2, 96, 192) + +To regrid a variable ``uold`` to the same grid as variable ``vnew``: + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> uold = f('u') + >>> unew = f2('uwnd') + >>> uold.shape + (1, 2, 80, 97) + >>> unew.shape + (1, 14, 181, 360) + >>> t63_grid = unew.getGrid() # Obtain the grid for vnew + >>> u63 = u.regrid(t63_grid) + >>> u63.shape + (1, 2, 181, 360) + +1.10.2 SCRIP Regridder +'''''''''''''''''''''' + +To interpolate between any lat-lon grid types, the SCRIP regridder may +be used. The SCRIP package was developed at [Los Alamos National +Laboratory](http://oceans11.lanl.gov/drupal/Models/OtherSoftware). +SCRIP is written in Fortran 90, and must be built and installed +separately from the UV-CDAT/CDMS installation. + +The steps to regrid a variable are: + +(external to CDMS) + +1. Obtain or generate the grids, in SCRIP netCDF format. +2. Run SCRIP to generate a *remapping* file. + +(in CDMS) + +1. Read the regridder from the SCRIP remapping file. +2. Call the regridder with the source data, returning data on the target + grid. + +Steps 1 and 2 need only be done once. The regridder can be used as often +as necessary. + +#For example, suppose the source data on a T42 grid is to be mapped to a +#POP curvilinear grid. Assume that SCRIP generated a remapping file named +#rmp_T42_to_POP43_conserv.nc: +# +#.. doctest:: +# +# >>> # Import regrid package for regridder functions +# >>> import regrid2, cdms2 +# +# >>> # Get the source variable +# >>> f = cdms2.open('sampleT42Grid.nc') +# >>> dat = f('src_array') +# >>> f.close() +# +# >>> # Read the regridder from the remapper file +# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') +# >>> regridf = regrid2.readRegridder(remapf) +# >>> remapf.close() +# +# >>> # Regrid the source variable +# >>> popdat = regridf(dat) + +Regridding is discussed in `Chapter 4 `__. + +1.11 Time types +^^^^^^^^^^^^^^^ + +CDMS provides extensive support for time values in the cdtime module. +cdtime also defines a set of calendars , specifying the number of days +in a given month. + +Two time types are available: relative time and component time . +Relative time is time relative to a fixed base time. It consists of: + +- a ``units`` string, of the form ``"units since basetime"`` , and +- a floating-point ``value`` + +For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and +units=" days since 1996-1-1". To create a relative time type: + +.. doctest:: + + >>> import cdtime + >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") + >>> rt + 28.000000 days since 1996-1-1 + >>> rt.value + 28.0 + >>> rt.units + 'days since 1996-1-1' + +A component time consists of the integer fields year, month, day, hour, +minute , and the floating-point field second . For example: + + +.. doctest:: + + >>> ct = cdtime.comptime(1996,2,28,12,10,30) + >>> ct + 1996-2-28 12:10:30.0 + >>> ct.year + 1996 + >>> ct.month + 2 + +The conversion functions tocomp and torel convert between the two +representations. For instance, suppose that the time axis of a variable +is represented in units " days since 1979" . To find the coordinate +value corresponding to January 1, 1990: + +.. doctest:: + + >>> ct = cdtime.comptime(1990,1) + >>> rt = ct.torel("days since 1979") + >>> rt.value + 4018.0 + +Time values can be used to specify intervals of time to read. The syntax +time=(c1,c2) specifies that data should be read for times t such that +c1<=t<=c2: + +.. doctest:: + + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> c1 = cdtime.comptime(1980,1) + >>> c2 = cdtime.comptime(1980,2) + >>> tas = fh['tas'] + >>> tas.shape + (484, 45, 72) + >>> x = tas.subRegion(time=(c1,c2)) + >>> x.shape + (125, 45, 72) + +or string representations can be used: + + +.. doctest:: + + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> tas = fh['tas'] + >>> x = tas.subRegion(time=('1980-1','1980-2')) + +Time types are described in Chapter 3. + +1.12 Plotting data +^^^^^^^^^^^^^^^^^^ + +Data read via the CDMS Python interface can be plotted using the vcs +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the VCS reference manual. The +vcs module provides access to the functionality of the VCS visualization +program. + +To generate a plot: + +- Initialize a canvas with the ``vcs init`` routine. +- Plot the data using the canvas ``plot`` routine. + +For example: + +.. doctest:: + + >>> import cdms2, vcs, cdat_info + >>> fh=cdms2.open(cdat_info.get_sampledata_path() + "/tas_cru_1979.nc") + >>> fh['time'][:] # Print the time coordinates + array([ 1476., 1477., 1478., 1479., 1480., 1481., 1482., 1483., + 1484., 1485., 1486., 1487.]) + + >>> tas = fh('tas', time=1479) + >>> tas.shape + (1, 36, 72) + >>> w = vcs.init() # Initialize a canvas + >>> w.plot(tas) # Generate a plot + `__ +for details. + +1.13 Databases +^^^^^^^^^^^^^^ + +Datasets can be aggregated together into hierarchical collections, +called databases . In typical usage, a program: + +- connects to a database +- searches for data opens a dataset +- accesses data + +Databases add the ability to search for data and metadata in a +distributed computing environment. At present CDMS supports one +particular type of database, based on the Lightweight Directory Access +Protocol (LDAP). + +Here is an example of accessing data via a database: + +#.. doctest:: +# +# >>> db = cdms.connect() # Connect to the default database. +# >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. +# >>> f.variables.keys() # List the variables in the dataset. +# ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] + +Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst new file mode 100644 index 00000000..b6ca3763 --- /dev/null +++ b/docs/source/manual/cdms_2.rst @@ -0,0 +1,3945 @@ +CHAPTER 2 CDMS Python Application Programming Interface +------------------------------------------------------- + +2.1 Overview +^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +This chapter describes the CDMS Python application programming interface +(API). Python is a popular public-domain, object-oriented language. Its +features include support for object-oriented development, a rich set of +programming constructs, and an extensible architecture. CDMS itself is +implemented in a mixture of C and Python. In this chapter the assumption +is made that the reader is familiar with the basic features of the +Python language. + +Python supports the notion of a module, which groups together associated +classes and methods. The import command makes the module accessible to +an application. This chapter documents the cdms, cdtime, and regrid +modules. + +The chapter sections correspond to the CDMS classes. Each section +contains tables base. If no parent, the datapath is absolute.describing +the class internal (non-persistent) attributes, constructors (functions +for creating an object), and class methods (functions). A method can +return an instance of a CDMS class, or one of the Python types: + + +Table 2.1 Python types used in CDMS + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Description | ++==============+=======================================================================================================================================================================================================+ +| Array | Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Comptime | Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Dictionary | An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Float | Floating-point value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | Integer value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| List | An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| None | No value returned. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Reltime | Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +2.2 A first example +^^^^^^^^^^^^^^^^^^^ + +The following Python script reads January and July monthly temperature +data from an input dataset, averages over time, and writes the results +to an output file. The input temperature data is ordered (time, +latitude, longitude). + +.. doctest:: + + >>> import cdms2, cdat_info + >>> from cdms2 import MV + >>> jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc') + >>> tasvar = jones['tas'] + >>> jans = tasvar[0::12] + >>> julys = tasvar[6::12] + >>> janavg = MV.average(jans) + >>> janavg.id = "tas_jan" + >>> janavg.long_name = "mean January surface temperature" + >>> julyavg = MV.average(julys) + >>> julyavg.id = "tas_jul" + >>> julyavg.long_name = "mean July surface temperature" + >>> out = cdms2.open('janjuly.nc','w') + >>> out.write(janavg) + >> out.write(julyavg) + >> out.comment = "Average January/July from Jones dataset" + >>> jones.close() + >>> out.close() + + ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| 2,3 | Makes the CDMS and MV modules available. MV defines arithmetic functions. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 4 | Opens a netCDF file read-only. The result jones is a dataset object. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 5 | Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 6 | Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 7 | Reads all July data into a masked array julys. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 8 | Calculate the average January value for each grid zone. Any missing data is handled automatically. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 9,10 | Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 14 | Create a new netCDF output file named ‘janjuly.nc’ to hold the results. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 15 | Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 17 | Set the global attribute ‘comment’. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 18 | Close the output file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.3 cdms module + +The cdms module is the Python interface to CDMS. The objects and methods +in this chapter are made accessible with the command: + +.. raw:: html + +
+ +:: + + import cdms2 + +.. raw:: html + +
+ +The functions described in this section are not associated with a class. +Rather, they are called as module functions, e.g., + +.. raw:: html + +
+ +:: + + file = cdms2.open('sample.nc') + +.. raw:: html + +
+ + +Table 2.2 cdms module functions + ++-------------+-------------------------------------------------------------------------+ +| Type | Definition | ++=============+=========================================================================+ +| ``Variable``| ``asVariable(s)``: Transform ``s`` | +| | into a transient variable. ``s`` is | +| | a masked array, Numeric array, or | +| | Variable. If ``s`` is already a | +| | transient variable, ``s`` is | +| | returned. See also: ``isVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createAxis(data, bounds=None)``: | +| | Create a one-dimensional coordinate | +| | Axis, which is not associated with a | +| | file or dataset. This is useful for | +| | creating a grid which is not | +| | contained in a file or dataset. | +| | ``data`` is a one-dimensional, | +| | monotonic Numeric array. ``bounds`` | +| | is an array of shape | +| | ``(len(data),2)``, such that for all | +| | ``i``, ``data[i]`` is in the range | +| | ``[bounds[i,0],bounds[i,1] ]``. If | +| | ``bounds`` is not specified, the | +| | default boundaries are generated at | +| | the midpoints between the | +| | consecutive data values, provided | +| | that the autobounds mode is 'on' | +| | (the default). See | +| | ``setAutoBounds``. Also see: | +| | ``CdmsFile.createAxis`` | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createEqualAreaAxis(nlat)``: | +| | Create an equal-area latitude axis. | +| | The latitude values range from north | +| | to south, and for all axis values | +| | ``x[i]``, ``sin(x[i])sin(x[i+1])`` | +| | is constant. ``nlat`` is the axis | +| | length. The axis is not associated | +| | with a file or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createGaussianAxis(nlat)``: Create | +| | a Gaussian latitude axis. Axis | +| | values range from north to south. | +| | ``nlat`` is the axis length. The | +| | axis is not associated with a file | +| | or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGaussianGrid(nlats, xorigin= | +| | 0.0, order="yx")``: | +| | Create a Gaussian grid, with shape | +| | ``(nlats, 2*nlats)``. ``nlats`` is | +| | the number of latitudes. ``xorigin`` | +| | is the origin of the longitude axis. | +| | ``order`` is either "yx" (lat-lon, | +| | default) or "xy" (lon-lat) | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, | +| | order="yx", mask=None)``: | +| | Create a generic grid, that is, a | +| | grid which is not typed as Gaussian, | +| | uniform, or equal-area. The grid is | +| | not associated with a file or | +| | dataset. ``latArray`` is a NumPy | +| | array of latitude values. | +| | ``lonArray`` is a NumPy array of | +| | longitude values. ``latBounds`` is a | +| | NumPy array having shape | +| | ``(len(latArray),2)``, of latitude | +| | boundaries. ``lonBounds`` is a NumPy | +| | array having shape | +| | ``(len(lonArray),2)``, of longitude | +| | boundaries. ``order`` is a | +| | ``string`` specifying the order of | +| | the axes, either "yx" for (latitude, | +| | longitude), or "xy" for the reverse. | +| | ``mask`` (optional) is an | +| | ``integer``-valued NumPy mask array, | +| | having the same shape and ordering | +| | as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGlobalMeanGrid(grid)``: | +| | Generate a grid for calculating the | +| | global mean via a regridding | +| | operation. The return grid is a | +| | single zone covering the range of | +| | the input grid. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createRectGrid(lat, lon, order, ty | +| | pe="generic", mask=None)``: | +| | Create a rectilinear grid, not | +| | associated with a file or dataset. | +| | This might be used as the target | +| | grid for a regridding operation. | +| | ``lat`` is a latitude axis, created | +| | by ``cdms.createAxis``. ``lon`` is a | +| | longitude axis, created by | +| | ``cdms.createAxis``. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). ``type`` is one of | +| | 'gaussian','uniform','equalarea',or | +| | 'generic'. If specified, ``mask`` is | +| | a two-dimensional, logical Numeric | +| | array (all values are zero or one) | +| | with the same shape as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createUniformGrid(startLat, nlat, | +| | deltaLat, start-Lon, nlon, deltaLon, | +| | order="yx", mask=None)``: | +| | Create a uniform rectilinear grid. | +| | The grid is not associated with a | +| | file or dataset. The grid boundaries | +| | are at the midpoints of the axis | +| | values. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. If ``nlat`` is | +| | 1, the grid latitude boundaries will | +| | be ``startLat`` +/- ``deltaLat/2``. | +| | ``deltaLat`` is the increment | +| | between latitudes. ``startLon`` is | +| | the starting longitude value. | +| | ``nlon`` is the number of | +| | longitudes. If ``nlon`` is 1, the | +| | grid longitude boundaries will be | +| | ``startLon`` +/- ``deltaLon/2``. | +| | ``deltaLon`` is the increment | +| | between longitudes. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). If specified, ``mask`` | +| | is a two-dimensional, logical | +| | Numeric array (all values are zero | +| | or one) with the same shape as the | +| | grid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLatitudeAxis(startLat | +| | , nlat, deltaLat)``: | +| | Create a uniform latitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular latitude | +| | axis. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. ``deltaLat`` is | +| | the increment between latitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createZonalGrid(grid)``: Create a | +| | zonal grid. The output grid has the | +| | same latitude as the input grid, and | +| | a single longitude. This may be used | +| | to calculate zonal averages via a | +| | regridding operation. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLongitudeAxis(startLo | +| | n, nlon, delta-Lon)``: | +| | Create a uniform longitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular longitude | +| | axis. ``startLon`` is the starting | +| | longitude value. ``nlon`` is the | +| | number of longitudes. ``deltaLon`` | +| | is the increment between longitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``Variable``| ``createVariable(array, typecode=Non | +| | e, copy=0, savespace=0, mask=None, f | +| | ill_value=None, grid=None, axes=None | +| | , attributes=None, id=None)``: | +| | This function is documented in Table | +| | 2.34 on page 90. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``getAutoBounds()``: Get the current | +| | autobounds mode. Returns 0, 1, or 2. | +| | See ``setAutoBounds``. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``isVariable(s)``: Return ``1`` if | +| | ``s`` is a variable, ``0`` | +| | otherwise. See also: ``asVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Dataset`` | ``open(url,mode='r')``: Open or | +| | create a ``Dataset`` or | +| | ``CdmsFile``. ``url`` is a Uniform | +| | Resource Locator, referring to a | +| | cdunif or XML file. If the URL has | +| | the extension '.xml' or '.cdml', a | +| | ``Dataset`` is returned, otherwise a | +| | ``CdmsFile`` is returned. If the URL | +| | protocol is 'http', the file must be | +| | a '.xml' or '.cdml' file, and the | +| | mode must be 'r'. If the protocol is | +| | 'file' or is omitted, a local file | +| | or dataset is opened. ``mode`` is | +| | the open mode. See Table 2.24 on | +| | page 70. | +| | **Example**: Open an existing | +| | dataset: | +| | ``f = cdms.open("sampleset.xml")`` | +| | | +| | **Example**: Create a netCDF file: | +| | ``f = cdms.open("newfile.nc",'w')`` | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``order2index (axes, orderstring)``: | +| | Find the index permutation of axes | +| | to match order. Return a list of | +| | indices. ``axes`` is a list of axis | +| | objects. ``orderstring`` is defined | +| | as in ``orderparse``. | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``orderparse(orderstring)``: Parse | +| | an order string. Returns a list of | +| | axes specifiers. ``orderstring`` | +| | consists of: | +| | | +| | - Letters t, x, y, z meaning time, | +| | longitude, latitude, level | +| | - Numbers 0-9 representing position | +| | in axes | +| | - Dash (-) meaning insert the next | +| | available axis here. | +| | - The ellipsis ... meaning fill | +| | these positions with any | +| | remaining axes. | +| | - (name) meaning an axis whose id | +| | is name | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setAutoBounds(mode)``: Set | +| | autobounds mode. In some | +| | circumstances CDMS can generate | +| | boundaries for 1-D axes and | +| | rectilinear grids, when the bounds | +| | are not explicitly defined. The | +| | autobounds mode determines how this | +| | is done: If ``mode`` is ``'grid'`` | +| | or ``2`` (the default), the | +| | ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid if | +| | the axis is designated as a latitude | +| | or longitude axis, and the | +| | boundaries are not explicitly | +| | defined. If ``mode`` is ``'on'`` or | +| | ``1``, the ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid, if | +| | the boundaries are not explicitly | +| | defined. If ``mode`` is ``'off'`` or | +| | ``0``, and no boundary data is | +| | explicitly defined, the bounds will | +| | NOT be generated; the ``getBounds`` | +| | method will return ``None`` for the | +| | boundaries. Note: In versions of | +| | CDMS prior to V4.0, the default | +| | ``mode`` was ``'on'``. | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setClassifyGrids(mode)``: Set the | +| | grid classification mode. This | +| | affects how grid type is determined, | +| | for the purpose of generating grid | +| | boundaries. If ``mode`` is ``'on'`` | +| | (the default), grid type is | +| | determined by a grid classification | +| | method, regardless of the value of | +| | ``grid.get-Type()``. If ``mode`` is | +| | ``'off'``, the value of | +| | ``grid.getType()`` determines the | +| | grid type | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``writeScripGrid(path, grid, gridTit | +| | le=None)``: | +| | Write a grid to a SCRIP grid file. | +| | ``path`` is a string, the path of | +| | the SCRIP file to be created. | +| | ``grid`` is a CDMS grid object. It | +| | may be rectangular. ``gridTitle`` is | +| | a string ID for the grid. | ++-------------+-------------------------------------------------------------------------+ + + +Table 2.3 Class Tags + ++--------------+---------------------+ +| Tag | Class | ++==============+=====================+ +| ‘axis’ | Axis | ++--------------+---------------------+ +| ‘database’ | Database | ++--------------+---------------------+ +| ‘dataset’ | Dataset, CdmsFile | ++--------------+---------------------+ +| ‘grid’ | RectGrid | ++--------------+---------------------+ +| ‘variable’ | Variable | ++--------------+---------------------+ +| ‘xlink’ | Xlink | ++--------------+---------------------+ + + +2.4 CdmsObj +^^^^^^^^^^^ + +A CdmsObj is the base class for all CDMS database objects. At the +application level, CdmsObj objects are never created and used directly. +Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the +basis of user application programming. + +All objects derived from CdmsObj have a special attribute .attributes. +This is a Python dictionary, which contains all the external +(persistent) attributes associated with the object. This is in contrast +to the internal, non-persistent attributes of an object, which are +built-in and predefined. When a CDMS object is written to a file, the +external attributes are written, but not the internal attributes. + +**Example**: get a list of all external attributes of obj. + +.. raw:: html + +
+ +:: + + extatts = obj.attributes.keys() + +.. raw:: html + +
+ + +Table 2.4 Attributes common to all CDMS objects + ++--------------+--------------+--------------------------------------------------+ +| Type | Name | Definition | ++==============+==============+==================================================+ +| Dictionary | attributes | External attribute dictionary for this object. | ++--------------+--------------+--------------------------------------------------+ + + +Table 2.5 Getting and setting attributes + ++--------------------------------------+--------------------------------------+ +| Type | Definition | ++======================================+======================================+ +| various | ``value = obj.attname`` | +| | Get an internal or external | +| | attribute value. If the attribute is | +| | external, it is read from the | +| | database. If the attribute is not | +| | already in the database, it is | +| | created as an external attribute. | +| | Internal attributes cannot be | +| | created, only referenced. | ++--------------------------------------+--------------------------------------+ +| various | ``obj.attname = value`` | +| | Set an internal or external | +| | attribute value. If the attribute is | +| | external, it is written to the | +| | database. | ++--------------------------------------+--------------------------------------+ + + +2.5 CoordinateAxis +^^^^^^^^^^^^^^^^^^ + +A CoordinateAxis is a variable that represents coordinate information. +It may be contained in a file or dataset, or may be transient +(memoryresident). Setting a slice of a file CoordinateAxis writes to the +file, and referencing a file CoordinateAxis slice reads data from the +file. Axis objects are also used to define the domain of a Variable. + +CDMS defines several different types of CoordinateAxis objects. Table +2.9 on page 45 documents methods that are common to all CoordinateAxis +types. Table 2.10 on page 48 specifies methods that are unique to 1D +Axis objects. + + +Table 2.6 CoordinateAxis types + ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Definition | ++======================+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``CoordinateAxis`` | A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis2D`` | A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``AuxAxis1D`` | A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.7 CoordinateAxis Internal Attributes + ++------------------+------------------+--------------------------------------------+ +| Type | Name | Definition | ++==================+==================+============================================+ +| ``Dictionary`` | ``attributes`` | External attribute dictionary. | ++------------------+------------------+--------------------------------------------+ +| ``String`` | ``id`` | CoordinateAxis identifer. | ++------------------+------------------+--------------------------------------------+ +| ``Dataset`` | ``parent`` | The dataset which contains the variable. | ++------------------+------------------+--------------------------------------------+ +| ``Tuple`` | ``shape`` | The length of each axis. | ++------------------+------------------+--------------------------------------------+ + + +Table 2.8 Axis Constructors + ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================+ +| ``cdms.createAxis(data, bounds=None)`` | Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Dataset.createAxis(name,ar)`` | Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented. ) | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``CdmsFile.createAxis(name,ar,unlimited=0)`` | Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited`` | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createEqualAreaAxis(nlat)`` | See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createGaussianAxis(nlat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.9 CoordinateAxis Methods + ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+====================================================================+================================================================================================================================================================================================================================================================================+ +| ``Array`` | ``array = axis[i:j]`` | Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``axis[i:j] = array`` | Write a slice of data to the external file. Dataset axes are read-only. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``assignValue(array)`` | Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | ``clone(copyData=1)`` | Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLatitude(persistent=0)`` | Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLevel(persistent=0)`` | Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLongitude(persistent=0, modulo=360.0)`` | Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateTime(persistent=0, calendar = cdtime.MixedCalendar)`` | Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getBounds()`` | Get the associated boundary array. The shape of the return array depends on the type of axis: | +|   |   | * ``Axis``: ``(n,2)`` | +|   |   | * ``Axis2D``: ``(i,j,4)`` | +|   |   | * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. | +|   |   | If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``getCalendar()`` | Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: | +|   |   | * ``cdtime.GregorianCalendar``: the standard Gregorian calendar | +|   |   | * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar | +|   |   | * ``cdtime.JulianCalendar``: years divisible by 4 are leap years | +|   |   | * ``cdtime.NoLeapCalendar``: a year is 365 days | +|   |   | * ``cdtime.Calendar360``: a year is 360 days | +|   |   | * ``None``: no calendar can be identified | +|   |   | Note: If the axis is not a time axis, the global, file-related calendar is returned. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getValue()`` | Get the entire axis vector. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLatitude()`` | Returns true iff the axis is a latitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLevel()`` | Returns true iff the axis is a level axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLongitude()`` | Returns true iff the axis is a longitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isTime()`` | Returns true iff the axis is a time axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``len(axis)`` | The length of the axis if one-dimensional. If multidimensional, the length of the first dimension. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``size()`` | The number of elements in the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``String`` | ``typecode()`` | The ``Numeric`` datatype identifier. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.10 Axis Methods, additional to CoordinateAxis + ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============================+===============================================+==========================================================================================================================================================================================================================================================================================================================+ +| ``List`` of component times | ``asComponentTime(calendar=None)`` | ``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``List`` of relative times | ``asRelativeTime()`` | ``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateCircular(modulo, persistent=0)`` | Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isCircular()`` | Returns ``True`` if the axis has circular topology. An axis is defined as circular if: | +|   |   | * ``axis.topology == 'circular'``, or | +|   |   | * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0 | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLinear()`` | Returns ``True`` if the axis has a linear representation. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Tuple`` | ``mapInterval(interval)`` | Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``(i,j,k)`` | ``mapIntervalExt(interval)`` | Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: | +|   |   | * ``(x,y)`` | +|   |   | * ``(x,y,indicator)`` | +|   |   | * ``(x,y,indicator,cycle)`` | +|   |   | * ``None or ':'`` | +|   |   | * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: | +|   |   | * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis| +|   |   | * ``'n'`` - select node values which are contained in the interval | +|   |   | * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval | +|   |   | * ``'e'`` - same as n, but include an extra node on either side | +|   |   | * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval | +|   |   | * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. | +|   |   | * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. | +|   |   | * An interval of ``None`` or ``':'`` returns the full index interval of the axis. | +|   |   | * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. | +|   |   | * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` | +|   |   | * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. | +|   |   | * otherwise the interval wraps around the axis endpoint. | +|   |   | * see also: ``mapinterval``, ``variable.subregion()`` | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``transientaxis`` | ``subaxis(i,j,k=1)`` | create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +table 2.11 axis slice operators + ++---------------+-----------------------------------------------------------------------------+ +| slice | definition | ++===============+=============================================================================+ +| ``[i]`` | the ``ith`` element, starting with index ``0`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:]`` | the ``ith`` element through and including the end | ++---------------+-----------------------------------------------------------------------------+ +| ``[:j]`` | the beginning element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[:]`` | the entire array | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | ++---------------+-----------------------------------------------------------------------------+ + +**example:** + +a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length +``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index +interval(s), with wraparound. the result index interval ``-2 <= n < 3`` +wraps around, since ``-2 < 0``, and has a stride of ``1``. this is +equivalent to the two contiguous index intervals ``2 <= n < 0`` and +``0 <= n < 3`` + +.. raw:: html + +
+ +:: + + >>> axis.isCircular() + 1 + >>> axis.mapIntervalExt((-5.0,5.0,'co')) + (-2,3,1) + +.. raw:: html + +
+ + +2.6 CdmsFile +^^^^^^^^^^^^ +A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` +interface. netCDF files are accessible in read-write mode. All other +formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. + +As of CDMS V3, the legacy cuDataset interface is also supported by +Cdms-Files. See “cu Module” on page 180. + + +Table 2.12 CdmsFile Internal Attributes + ++------------------+------------------+---------------------------------------+ +| Type | Name | Definition | ++==================+==================+=======================================+ +| ``Dictionary`` | ``attributes`` | Global, external file attributes | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``grids`` | Grids contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``String`` | ``id`` | File pathname. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``variables`` | Variables contained in the file. | ++------------------+------------------+---------------------------------------+ + + +Table 2.13 CdmsFile Constructors + ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++==========================================+==================================================================================================================================================================================+ +| ``fileobj = cdms.open(path, mode)`` | Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``fileobj = cdms.createDataset(path)`` | Create the file specified by path, a string. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.14 CdmsFile Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| ``Transient-Variable`` | ``fileobj(varname, selec | Calling a ``CdmsFile`` | +| | tor)`` | object as a function | +| | | reads the region of data | +| | | specified by the | +| | | ``selector``. The result | +| | | is a transient variable, | +| | | unless ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | nc') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| ``Variable``, ``Axis``, | ``fileobj['id']`` | Get the persistent | +| or ``Grid`` | | variable, axis or grid | +| | | object having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. | +| | | | +| | | **Example:** The | +| | | following gets the | +| | | persistent variable | +| | | ``v``, equivalent to | +| | | ``v = f.variables['prc'] | +| | | ``. | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.nc') | +| | | v = f['prc'] | +| | | | +| | | **Example:** The | +| | | following gets the axis | +| | | named time, equivalent | +| | | to | +| | | ``t = f.axes['time']``. | +| | | | +| | | ``t = f['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``copyAxis(axis, newname | Copy ``axis`` values and | +| | =None)`` | attributes to a new axis | +| | | in the file. The | +| | | returned object is | +| | | persistent: it can be | +| | | used to write axis data | +| | | to or read axis data | +| | | from the file. If an | +| | | axis already exists in | +| | | the file, having the | +| | | same name and coordinate | +| | | values, it is returned. | +| | | It is an error if an | +| | | axis of the same name | +| | | exists, but with | +| | | different coordinate | +| | | values. ``axis`` is the | +| | | axis object to be | +| | | copied. ``newname``, if | +| | | specified, is the string | +| | | identifier of the new | +| | | axis object. If not | +| | | specified, the | +| | | identifier of the input | +| | | axis is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Grid`` | ``copyGrid(grid, newname | Copy grid values and | +| | =None)`` | attributes to a new grid | +| | | in the file. The | +| | | returned grid is | +| | | persistent. If a grid | +| | | already exists in the | +| | | file, having the same | +| | | name and axes, it is | +| | | returned. An error is | +| | | raised if a grid of the | +| | | same name exists, having | +| | | different axes. ``grid`` | +| | | is the grid object to be | +| | | copied. ``newname``, if | +| | | specified is the string | +| | | identifier of the new | +| | | grid object. If | +| | | unspecified, the | +| | | identifier of the input | +| | | grid is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``createAxis(id, ar, unl | Create a new ``Axis``. | +| | imited=0)`` | This is a persistent | +| | | object which can be used | +| | | to read or write axis | +| | | data to the file. ``id`` | +| | | is an alphanumeric | +| | | string identifier, | +| | | containing no blanks. | +| | | ``ar`` is the | +| | | one-dimensional axis | +| | | array. Set ``unlimited`` | +| | | to ``cdms.Unlimited`` to | +| | | indicate that the axis | +| | | is extensible. | ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a ``RectGrid`` in | +| | , lon, order, type="gene | the file. This is not a | +| | ric", mask=None)`` | persistent object: the | +| | | order, type, and mask | +| | | are not written to the | +| | | file. However, the grid | +| | | may be used for | +| | | regridding operations. | +| | | ``lat`` is a latitude | +| | | axis in the file. | +| | | ``lon`` is a longitude | +| | | axis in the file. | +| | | ``order`` is a string | +| | | with value ``"yx"`` (the | +| | | first grid dimension is | +| | | latitude) or ``"xy"`` | +| | | (the first grid | +| | | dimension is longitude). | +| | | ``type`` is one of | +| | | ``'gaussian'``,\ ``'unif | +| | | orm'``,\ ``'equalarea'`` | +| | | , | +| | | or ``'generic'``. If | +| | | specified, ``mask`` is a | +| | | two-dimensional, logical | +| | | Numeric array (all | +| | | values are zero or one) | +| | | with the same shape as | +| | | the grid. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariable(String | Create a new Variable. | +| | id, String datatype,List | This is a persistent | +| | axes, fill_value=None)`` | object which can be used | +| | | to read or write | +| | | variable data to the | +| | | file. ``id`` is a String | +| | | name which is unique | +| | | with respect to all | +| | | other objects in the | +| | | file. ``datatype`` is an | +| | | ``MA`` typecode, e.g., | +| | | ``MA.Float``, | +| | | ``MA.Int``. ``axes`` is | +| | | a list of Axis and/or | +| | | Grid objects. | +| | | ``fill_value`` is the | +| | | missing value | +| | | (optional). | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariableCopy(var | Create a new | +| | , newname=None)`` | ``Variable``, with the | +| | | same name, axes, and | +| | | attributes as the input | +| | | variable. An error is | +| | | raised if a variable of | +| | | the same name exists in | +| | | the file. ``var`` is the | +| | | ``Variable`` to be | +| | | copied. ``newname``, if | +| | | specified is the name of | +| | | the new variable. If | +| | | unspecified, the | +| | | returned variable has | +| | | the same name as | +| | | ``var``. | +| | | | +| | | **Note:** Unlike | +| | | copyAxis, the actual | +| | | data is not copied to | +| | | the new variable. | ++--------------------------+--------------------------+--------------------------+ +| ``CurveGrid`` or | ``readScripGrid(self, wh | Read a curvilinear or | +| ``Generic-Grid`` | ichGrid='destination', c | generic grid from a | +| | heck-Grid=1)`` | SCRIP netCDF file. The | +| | | file can be a SCRIP grid | +| | | file or remapping file. | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. If | +| | | ``checkGrid`` is ``1`` | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``sync()`` | Writes any pending | +| | | changes to the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | :: | Write a variable or | +| | | array to the file. The | +| | write(var, attribute | return value is the | +| | s=None, axes=None, extbo | associated file | +| | unds=None, id=None, exte | variable. | +| | nd=None, fill_value=None | | +| | , index=None, typecode=N | If the variable does not | +| | one) | exist in the file, it is | +| | | first defined and all | +| | | attributes written, then | +| | | the data is written. By | +| | | default, the time | +| | | dimension of the | +| | | variable is defined as | +| | | the unlimited dimension | +| | | of the file. If the data | +| | | is already defined, then | +| | | data is extended or | +| | | overwritten depending on | +| | | the value of keywords | +| | | ``extend`` and | +| | | ``index``, and the | +| | | unlimited dimension | +| | | values associated with | +| | | ``var``. | +| | | | +| | | ``var`` is a Variable, | +| | | masked array, or Numeric | +| | | array. ``attributes`` is | +| | | the attribute dictionary | +| | | for the variable. The | +| | | default is | +| | | ``var.attributes``. | +| | | ``axes`` is the list of | +| | | file axes comprising the | +| | | domain of the variable. | +| | | The default is to copy | +| | | ``var.getAxisList()``. | +| | | ``extbounds`` is the | +| | | unlimited dimension | +| | | bounds. Defaults to | +| | | ``var.getAxis(0).getBoun | +| | | ds()``. | +| | | ``id`` is the variable | +| | | name in the file. | +| | | Default is ``var.id``. | +| | | ``extend = 1`` causes | +| | | the first dimension to | +| | | be unlimited: | +| | | iteratively writeable. | +| | | The default is ``None``, | +| | | in which case the first | +| | | dimension is extensible | +| | | if it is ``time.Set`` to | +| | | ``0`` to turn off this | +| | | behaviour. | +| | | ``fill_value`` is the | +| | | missing value flag. | +| | | ``index`` is the | +| | | extended dimension index | +| | | to write to. The default | +| | | index is determined by | +| | | lookup relative to the | +| | | existing extended | +| | | dimension. | +| | | | +| | | **Note:** data can also | +| | | be written by setting a | +| | | slice of a file | +| | | variable, and attributes | +| | | can be written by | +| | | setting an attribute of | +| | | a file variable. | ++--------------------------+--------------------------+--------------------------+ + + +Table 2.15 CDMS Datatypes + ++-----------------+-----------------------------------+ +| CDMS Datatype | Definition | ++=================+===================================+ +| ``CdChar`` | character | ++-----------------+-----------------------------------+ +| ``CdDouble`` | double-precision floating-point | ++-----------------+-----------------------------------+ +| ``CdFloat`` | floating-point | ++-----------------+-----------------------------------+ +| ``CdInt`` | integer | ++-----------------+-----------------------------------+ +| ``CdLong`` | long integer | ++-----------------+-----------------------------------+ +| ``CdShort`` | short integer | ++-----------------+-----------------------------------+ + + +2.7 Database +^^^^^^^^^^^^ +A Database is a collection of datasets and other CDMS objects. It +consists of a hierarchical collection of objects, with the database +being at the root, or top of the hierarchy. A database is used to: + +- search for metadata +- access data +- provide authentication and access control for data and metadata + +The figure below illustrates several important points: + +- Each object in the database has a relative name of the form tag=id. + The id of an object is unique with respect to all objects contained + in the parent. + +- The name of the object consists of its relative name followed by the + relative name(s) of its antecedent objects, up to and including the + database name. In the figure below, one of the variables has name + ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. + +- Subordinate objects are thought of as being contained in the parent. + In this example, the database ‘CDMS’ contains two datasets, each of + which contain several variables. + +|Diagram 1| + +Figure 1 + + +2.7.1 Overview + +To access a database: + +#. Open a connection. The connect method opens a database connection. + connect takes a database URI and returns a database object: + ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` +#. Search the database, locating one or more datasets, variables, and/or + other objects. + + The database searchFilter method searches the database. A single + database connection may be used for an arbitrary number of searches. + + **Example**: Find all observed datasets + + ``result = db.searchFilter(category="observed",tag="dataset")`` + + Searches can be restricted to a subhierarchy of the database. + + **Example:** Search just the dataset ``'ncep_reanalysis_mo'``: + + ``result = db.searchFilter(relbase="dataset=ncep_reanalysis")`` + +#. Refine the search results if necessary. The result of a search can be + narrowed with the searchPredicate method. +#. Process the results. A search result consists of a sequence of + entries. Each entry has a name, the name of the CDMS object, and an + attribute dictionary, consisting of the attributes located by the + search: + + `` for entry in result: print entry.name, entry.attributes`` + +#. Access the data. The CDMS object associated with an entry is obtained + from the getObject method: + + ``obj = entry.getObject()`` + + If the id of a dataset is known, the dataset can be opened directly + with the open method: + + ``dset = db.open("ncep_reanalysis_mo")`` + +#. Close the database connection: + + ``db.close()`` + + +Table 2.16 Database Internal Attributes + ++------------------+------------------+----------------------------------------+ +| Type | Name | Summary | ++==================+==================+========================================+ +| ``Dictionary`` | ``attributes`` | Database attribute dictionary | ++------------------+------------------+----------------------------------------+ +| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``netloc`` | Hostname, for server-based databases | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``path`` | path name | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``uri`` | Uniform Resource Identifier | ++------------------+------------------+----------------------------------------+ + + +Table 2.17 Database Constructors + ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================+==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``db = cdms.connect(uri=None, user="", password="")`` | Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection | ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.18 Database Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| None | ``close()`` | Close a database | +| | | connection. | ++--------------------------+--------------------------+--------------------------+ +| List | ``listDatasets()`` | Return a list of the | +| | | dataset IDs in this | +| | | database. A dataset ID | +| | | can be passed to the | +| | | ``open`` command. | ++--------------------------+--------------------------+--------------------------+ +| Dataset | ``open(dsetid, mode='r') | Open a dataset. | +| | `` | | +| | | ``dsetid`` is the string | +| | | dataset identifier | +| | | | +| | | ``mode`` is the open | +| | | mode, 'r' - read-only, | +| | | 'r+' - read-write, 'w' - | +| | | create. | +| | | | +| | | ``openDataset`` is a | +| | | synonym for ``open``. | ++--------------------------+--------------------------+--------------------------+ +| SearchResult | :: | Search a CDMS database. | +| | | | +| | searchFilter(filter= | ``filter`` is the string | +| | None, tag=None, relbase= | search filter. Simple | +| | None, scope=Subtree, att | filters have the form | +| | names=None, timeout=None | "tag = value". Simple | +| | ) | filters can be combined | +| | | using logical operators | +| | | '&', '\|', '!' in prefix | +| | | notation. | +| | | | +| | | **Example:** | +| | | | +| | | The filter | +| | | ``'(&(objec)(id=cli))'`` | +| | | finds all variables | +| | | named "cli". | +| | | | +| | | A formal definition of | +| | | search filters is | +| | | provided in the | +| | | following section. | +| | | | +| | | ``tag`` restricts the | +| | | search to objects with | +| | | that tag ("dataset" \| | +| | | "variable" \| "database" | +| | | \| "axis" \| "grid"). | +| | | | +| | | ``relbase`` is the | +| | | relative name of the | +| | | base object of the | +| | | search. The search is | +| | | restricted to the base | +| | | object and all objects | +| | | below it in the | +| | | hierarchy. | +| | | | +| | | **Example:** | +| | | | +| | | To search only dataset | +| | | 'ncep\_reanalysis\_mo', | +| | | specify: | +| | | | +| | | ``relbase="dataset=ncep_ | +| | | reanalysis_mo" `` | +| | | | +| | | To search only variable | +| | | 'ua' in | +| | | 'ncep\_reanalysis\_mo', | +| | | use: | +| | | | +| | | ``relbase="variable=ua,d | +| | | ataset=ncep_reanalysis_m | +| | | o"`` | +| | | | +| | | If no base is specified, | +| | | the entire database is | +| | | searched. See the | +| | | ``scope`` argument also. | +| | | | +| | | ``scope`` is the search | +| | | scope (**Subtree** \| | +| | | **Onelevel** \| | +| | | **Base**). | +| | | | +| | | - **Subtree** searches | +| | | the base object and | +| | | its descendants. | +| | | - **Onelevel** searches | +| | | the base object and | +| | | its immediate | +| | | descendants. | +| | | - **Base**\ searches | +| | | the base object | +| | | alone. | +| | | | +| | | The default is | +| | | **Subtree**. | +| | | | +| | | ``attnames``: list of | +| | | attribute names. | +| | | Restricts the attributes | +| | | returned. If ``None``, | +| | | all attributes are | +| | | returned. Attributes | +| | | 'id' and 'objectclass' | +| | | are always included in | +| | | the list. | +| | | | +| | | ``timeout``: integer | +| | | number of seconds before | +| | | timeout. The default is | +| | | no timeout. | ++--------------------------+--------------------------+--------------------------+ + + +2.7.2 Searching a database + +The ``searchFilter`` method is used to search a database. The result is +called a search result, and consists of a sequence of result entries. + +In its simplest form, ``searchFilter`` takes an argument consisting of a +string filter. The search returns a sequence of entries, corresponding +to those objects having an attribute which matches the filter. Simple +filters have the form (tag = value), where value can contain wildcards. +For example: + +.. raw:: html + +
+ +:: + + (id = ncep*) + (project = AMIP2) + +.. raw:: html + +
+ ++--------------------------------------------------------------------+------------------------+ +| Simple filters can be combined with the logical operators ‘&’, ‘ | ’, ‘!’. For example, | ++--------------------------------------------------------------------+------------------------+ + +.. raw:: html + +
+ +:: + + (&(id = bmrc*)(project = AMIP2)) + +.. raw:: html + +
+ +matches all objects with id starting with bmrc, and a project attribute +with value ‘AMIP2’. + +Formally, search filters are strings defined as follows: + +.. raw:: html + +
+ +:: + + filter ::= "(" filtercomp ")" + + filtercomp ::= "&" filterlist | # and + "|" filterlist | # or + "!" filterlist | # not + simple + + filterlist ::= filter | filter filterlist + simple ::= tag op value + op ::= "=" | # equality + + "~=" | # approximate equality + "<=" | # lexicographically less than or equal to + ">=" # lexicographically greater than or equal to + + tag ::= string attribute name + value ::= string attribute value, may include '*' as a wild card + +.. raw:: html + +
+ +Attribute names are defined in the chapter on “Climate Data Markup +Language (CDML)” on page 149. In addition, some special attributes are +defined for convenience: + +- ``category`` is either “experimental” or “observed” +- ``parentid`` is the ID of the parent dataset +- ``project`` is a project identifier, e.g., “AMIP2” +- ``objectclass`` is the list of tags associated with the object. + +The set of objects searched is called the search scope. The top object +in the hierarchy is the base object. By default, all objects in the +database are searched, that is, the database is the base object. If the +database is very large, this may result in an unnecessarily slow or +inefficient search. To remedy this the search scope can be limited in +several ways: + +- The base object can be changed. +- The scope can be limited to the base object and one level below, or + to just the base object. +- The search can be restricted to objects of a given class (dataset, + variable, etc.) +- The search can be restricted to return only a subset of the object + attributes +- The search can be restricted to the result of a previous search. +- A search result is accessed sequentially within a for loop: + +.. raw:: html + +
+ +:: + + result = db.searchFilter('(&(category=obs*)(id=ncep*))') + for entry in result: + print entry.name + +.. raw:: html + +
+ +Search results can be narrowed using ``searchPredicate``. In the +following example, the result of one search is itself searched for all +variables defined on a 94x192 grid: + +.. raw:: html + +
+ +:: + + >>> result = db.searchFilter('parentid=ncep*',tag="variable") + >>> len(result) + 65 + >>> result2 = result.searchPredicate(lambda x: + + x.getGrid().shape==(94,192)) + >>> len(result2) + 3 + >>> for entry in result2: print entry.name + variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + +.. raw:: html + +
+ + +Table 2.19 SearchResult Methods + ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++================+============================================+==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ResultEntry | ``[i]`` | Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):`` | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``len()`` | Number of entries in the result. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| SearchResult | ``searchPredicate(predicate, tag=None)`` | Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag. **Note**: In the current implementation, ``searchPredicate``\ is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +A search result is a sequence of result entries. Each entry has a string +name, the name of the object in the database hierarchy, and an attribute +dictionary. An entry corresponds to an object found by the search, but +differs from the object, in that only the attributes requested are +associated with the entry. In general, there will be much more +information defined for the associated CDMS object, which is retrieved +with the ``getObject`` method. + + +Table 2.20 ResultEntry Attributes + ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+=======================================================================================================================+ +| String | ``name`` | The name of this entry in the database. | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Dictionary | ``attributes`` | The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ + + +Table 2.21 ResultEntry Methods + ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+===================+======================================================================================================================================================================================================================================================================================+ +| ``CdmsObj`` | ``getObject()`` | Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. | ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.7.3 Accessing data + +To access data via CDMS: + +#. Locate the dataset ID. This may involve searching the metadata. +#. Open the dataset, using the open method. +#. Reference the portion of the variable to be read. + +In the next example, a portion of variable ‘ua’ is read from dataset +‘ncep\_reanalysis\_mo’: + +.. raw:: html + +
+ +:: + + dset = db.open('ncep_reanalysis_mo') + ua = dset.variables['ua'] + data = ua[0,0] + +.. raw:: html + +
+ + +2.7.4 Examples of database searches + +In the following examples, db is the database opened with + +.. raw:: html + +
+ +:: + + db = cdms.connect() + +.. raw:: html + +
+ +This defaults to the database defined in environment variable +``CDMSROOT``. + +**Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", + tag = "variable"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all axes with bounds defined: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter="bounds=*",tag="axis"): + print entry.name + +.. raw:: html + +
+ +**Example:** Locate all GDT datasets: + +.. raw:: html + +
+ +:: + + for entry in + db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all variables with missing time values, in observed +datasets: + +.. raw:: html + +
+ +:: + + def missingTime(obj): + time = obj.getTime() + return time.length != time.partition_length + + result = db.searchFilter(filter="category=observed") + for entry in result.searchPredicate(missingTime): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all CMIP2 datasets having a variable with id “hfss”: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): + print entry.getObject().parent.id + +.. raw:: html + +
+ +**Example:** Find all observed variables on 73x144 grids: + +.. raw:: html + +
+ +:: + + result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all observed variables with more than 1000 timepoints: + +.. raw:: html + +
+ +:: + + result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): + print entry.name, len(entry.getObject().getTime()) + +.. raw:: html + +
+ +**Example:** Find the total number of each type of object in the +database + +.. raw:: html + +
+ +:: + + print len(db.searchFilter(tag="database")),"database" + print len(db.searchFilter(tag="dataset")),"datasets" + print len(db.searchFilter(tag="variable")),"variables" + print len(db.searchFilter(tag="axis")),"axes" + +.. raw:: html + +
+ + +2.8 Dataset +^^^^^^^^^^^ +A Dataset is a virtual file. It consists of a metafile, in CDML/XML +representation, and one or more data files. + +As of CDMS V3, the legacy cuDataset interface is supported by Datasets. +See “cu Module” on page 180. + + +Table 2.22 Dataset Internal Attributes + ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+==========================================================================================================+ +| Dictionary | ``attributes`` | Dataset external attributes. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``axes`` | Axes contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``datapath`` | Path of data files, relative to the parent database. If no parent, the datapath is absolute. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``grids`` | Grids contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``mode`` | Open mode. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Database | ``parent`` | Database which contains this dataset. If the dataset is not part of a database, the value is ``None``. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``uri`` | Uniform Resource Identifier of this dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``variables`` | Variables contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``xlinks`` | External links contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ + + +Table 2.23 Dataset Constructors + ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++===========================================================+===================================================================================================================================================================================================================+ +| ``datasetobj = cdms.open(String uri, String mode='r')`` | Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open`` | ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.24 Open Modes + ++--------+-----------------------------------------------------------------------+ +| Mode | Definition | ++========+=======================================================================+ +| ‘r’ | read-only | ++--------+-----------------------------------------------------------------------+ +| ‘r+’ | read-write | ++--------+-----------------------------------------------------------------------+ +| ‘a’ | read-write. Open the file if it exists, otherwise create a new file | ++--------+-----------------------------------------------------------------------+ +| ‘w’ | Create a new file, read-write | ++--------+-----------------------------------------------------------------------+ + + +Table 2.25 Dataset Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Transient-Variable | ``datasetobj(varname, se | Calling a Dataset object | +| | lector)`` | as a function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless | +| | | ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | xml') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| Variable, Axis, or Grid | ``datasetobj['id']`` | The square bracket | +| | | operator applied to a | +| | | dataset gets the | +| | | persistent variable, | +| | | axis or grid object | +| | | having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. Returns | +| | | ``None`` if not found. | +| | | | +| | | **Example:** | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.xml') | +| | | v = f['prc'] | +| | | | +| | | gets the persistent | +| | | variable v, equivalent | +| | | to | +| | | ``v = f.variab | +| | | les['prc']``. | +| | | | +| | | **Example:** | +| | | | +| | | | ``t = f['time']`` | +| | | | gets the axis named | +| | | 'time', equivalent to | +| | | ``t = f.axes['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the dataset. | ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | +| | , lon, order, type="gene | dataset. This is not a | +| | ric", mask=Non | persistent object: the | +| | e)`` | order, type, and mask | +| | | are not written to the | +| | | dataset. However, the | +| | | grid may be used for | +| | | regridding operations. | +| | | | +| | | ``lat`` is a latitude | +| | | axis in the dataset. | +| | | | +| | | ``lon`` is a longitude | +| | | axis in the dataset. | +| | | | +| | | ``order`` is a string | +| | | with value "yx" (the | +| | | first grid dimension is | +| | | latitude) or "xy" (the | +| | | first grid dimension is | +| | | longitude). | +| | | | +| | | ``type`` is one of | +| | | 'gaussian','uniform','eq | +| | | ualarea',or | +| | | 'generic' | +| | | | +| | | If specified, ``mask`` | +| | | is a two-dimensional, | +| | | logical Numeric array | +| | | (all values are zero or | +| | | one) with the same shape | +| | | as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(id)`` | Get an axis object from | +| | | the file or dataset. | +| | | | +| | | ``id`` is the string | +| | | axis identifier. | ++--------------------------+--------------------------+--------------------------+ +| Grid | ``getGrid(id)`` | Get a grid object from a | +| | | file or dataset. | +| | | | +| | | ``id`` is the string | +| | | grid identifier. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths()`` | Get a sorted list of | +| | | pathnames of datafiles | +| | | which comprise the | +| | | dataset. This does not | +| | | include the XML metafile | +| | | path, which is stored in | +| | | the .uri attribute. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``getVariable(id)`` | Get a variable object | +| | | from a file or dataset. | +| | | | +| | | ``id`` is the string | +| | | variable identifier. | ++--------------------------+--------------------------+--------------------------+ +| CurveGrid or GenericGrid | ``readScripGrid(self, wh | Read a curvilinear or | +| | ichGrid='destination', c | generic grid from a | +| | heck-or Generic-Grid=1)` | SCRIP dataset. The | +| | ` | dataset can be a SCRIP | +| | | grid file or remapping | +| | | file. | +| | | | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. | +| | | | +| | | If ``checkGrid`` is 1 | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| None | ``sync()`` | Write any pending | +| | | changes to the dataset. | ++--------------------------+--------------------------+--------------------------+ + + +2.9 MV module +^^^^^^^^^^^^^ + +The fundamental CDMS data object is the variable. A variable is +comprised of: + +- a masked data array, as defined in the NumPy MA module. +- a domain: an ordered list of axes and/or grids. +- an attribute dictionary. + +The MV module is a work-alike replacement for the MA module, that +carries along the domain and attribute information where appropriate. MV +provides the same set of functions as MA. However, MV functions generate +transient variables as results. Often this simplifies scripts that +perform computation. MA is part of the Python Numeric package, +documented at http://www.numpy.org. + +MV can be imported with the command: + +.. raw:: html + +
+ +:: + + import MV + +.. raw:: html + +
+ +The command + +.. raw:: html + +
+ +:: + + from MV import * + +.. raw:: html + +
+ +allows use of MV commands without any prefix. + +Table 2.26 on page 75 lists the constructors in MV. All functions return +a transient variable. In most cases the keywords axes, attributes, and +id are available. axes is a list of axis objects which specifies the +domain of the variable. attributes is a dictionary. id is a special +attribute string that serves as the identifier of the variable, and +should not contain blanks or non-printing characters. It is used when +the variable is plotted or written to a file. Since the id is just an +attribute, it can also be set like any attribute: + +.. raw:: html + +
+ +:: + + var.id = 'temperature' + +.. raw:: html + +
+ +For completeness MV provides access to all the MA functions. The +functions not listed in the following tables are identical to the +corresponding MA function: ``allclose``, ``allequal``, +``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, +``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, +``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, +``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, +``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, +``putmask``, ``rank``, ``ravel``, ``set_fill_value``, +``set_print_limit``, ``shape``, ``size``. See the documentation at +http://numpy.sourceforge.net for a description of these functions. + + +Table 2.26 Variable Constructors in module MV + ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MA.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MA.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | return an array of all ones of the given length or shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``reshape(a, newshape, axes=none, attributes=none, id=none)`` | copy of a with a new shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``resize(a, new_shape, axes=none, attributes=none, id=none)`` | return a new array with the specified shape. the original arrays total size can be any size. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | an array of all zeros of the given length or shape | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +The following table describes the MV non-constructor functions. with the +exception of argsort, all functions return a transient variable. + + +Table 2.27 MV functions + ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Function | Description | ++=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+ +| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numeric array of indices for sorting along a given axis. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asarray(data, typecode=None)`` | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``average(a, axis=0, weights=None)`` | Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``choose(condition, t)`` | Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``concatenate(arrays, axis=0, axisid=None, axisattributes=None)`` | Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``count(a, axis=None)`` | Count of the non-masked elements in ``a``, or along a certain axis. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``isMaskedVariable(x)`` | Return true if ``x`` is an instance of a variable. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_equal(x, value)`` | ``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_greater(x, value)`` | ``x`` masked where ``x > value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_greater_equal(x, value)`` | ``x`` masked where ``x >= value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_less(x, value)`` | ``x`` masked where ``x < value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_less_equal(x, value)`` | ``x`` masked where ``x ≤ value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_not_equal(x, value)`` | ``x`` masked where ``x != value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_outside(x, v1, v2)`` | ``x`` with mask of all values of ``x`` that are outside ``[v1,v2]`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_where(condition, x, copy=1)`` | Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``maximum(a, b=None)`` | Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``minimum(a, b=None)`` | Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``outerproduct(a, b)`` | Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``power(a, b)`` | ``a**b`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``product(a, axis=0, fill_value=1)`` | Product of elements along axis using ``fill_value`` for missing elements. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``repeat(ar, repeats, axis=0)`` | Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``set_default_fill_value(value_type, value)`` | Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``sort(ar, axis=-1)`` | Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``sum(a, axis=0, fill_value=0)`` | Sum of elements along a certain axis using ``fill_value`` for missing. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numeric manual. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``transpose(ar, axes=None)`` | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``where(condition, x, y)`` | ``x`` where ``condition`` is true, ``y`` otherwise | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.10 HorizontalGrid +^^^^^^^^^^^^^^^^^^^ + +A HorizontalGrid represents a latitude-longitude coordinate system. In +addition, it optionally describes how lat-lon space is partitioned into +cells. Specifically, a HorizontalGrid: + +- consists of a latitude and longitude coordinate axis. +- may have associated boundary arrays describing the grid cell + boundaries, +- may optionally have an associated logical mask. + +CDMS supports several types of HorizontalGrids: + + +Table 2.28 + ++-------------------+----------------------------------------------------------------------------------+ +| Grid Type | Definition | ++===================+==================================================================================+ +| ``RectGrid`` | Associated latitude an longitude are 1-D axes, with strictly monotonic values. | ++-------------------+----------------------------------------------------------------------------------+ +| ``CurveGrid`` | Latitude and longitude are 2-D coordinate axes (Axis2D). | ++-------------------+----------------------------------------------------------------------------------+ +| ``GenericGrid`` | Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D) | ++-------------------+----------------------------------------------------------------------------------+ + + +Table 2.29 HorizontalGrid Internal Attribute + ++-----------------------+------------------+------------------------------------------------+ +| Type | Name | Definition | ++=======================+==================+================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+------------------+------------------------------------------------+ +| String | ``id`` | The grid identifier. | ++-----------------------+------------------+------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | ++-----------------------+------------------+------------------------------------------------+ +| Tuple | ``shape`` | The shape of the grid, a 2-tuple | ++-----------------------+------------------+------------------------------------------------+ + +Table 2.31 on page 82 describes the methods that apply to all types of +HorizontalGrids. Table 2.32 on page 86 describes the additional methods +that are unique to RectGrids. + + +Table 2.30 RectGrid Constructors + ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================================================================+==================================================================================+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | Create a grid not associated with a file or dataset. See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``CdmsFile.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a file. See Table 2.14 on page 53. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``Dataset.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a dataset. See Table 2.25 on page 71. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGaussianGrid(nlats, xorigin=0.0, order="yx")`` | See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGlobalMeanGrid(grid)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createZonalGrid(grid)`` | See Table 2.2 on page 18 | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ + + +Table 2.31 HorizontalGrid Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| Horizontal-Grid | ``clone()`` | Return a transient copy | +| | | of the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(Integer n)`` | Get the n-th axis.n is | +| | | either 0 or 1. | ++--------------------------+--------------------------+--------------------------+ +| Tuple | ``getBounds()`` | Get the grid boundary | +| | | arrays. | +| | | | +| | | Returns a tuple | +| | | ``(latitudeArray, longit | +| | | udeArray)``, | +| | | where latitudeArray is a | +| | | Numeric array of | +| | | latitude bounds, and | +| | | similarly for | +| | | longitudeArray.The shape | +| | | of latitudeArray and | +| | | longitudeArray depend on | +| | | the type of grid: | +| | | | +| | | - for rectangular grids | +| | | with shape (nlat, | +| | | nlon), the boundary | +| | | arrays have shape | +| | | (nlat,2) and | +| | | (nlon,2). | +| | | - for curvilinear grids | +| | | with shape (nx, ny), | +| | | the boundary arrays | +| | | each have shape (nx, | +| | | ny, 4). | +| | | - for generic grids | +| | | with shape (ncell,), | +| | | the boundary arrays | +| | | each have shape | +| | | (ncell, nvert) where | +| | | nvert is the maximum | +| | | number of vertices | +| | | per cell. | +| | | | +| | | For rectilinear grids: | +| | | If no boundary arrays | +| | | are explicitly defined | +| | | (in the file or | +| | | dataset), the result | +| | | depends on the auto- | +| | | Bounds mode (see | +| | | ``cdms.setAutoBounds``) | +| | | and the grid | +| | | classification mode (see | +| | | ``cdms.setClassifyGrids` | +| | | `). | +| | | By default, autoBounds | +| | | mode is enabled, in | +| | | which case the boundary | +| | | arrays are generated | +| | | based on the type of | +| | | grid. If disabled, the | +| | | return value is | +| | | (None,None).For | +| | | rectilinear grids: The | +| | | grid classification mode | +| | | specifies how the grid | +| | | type is to be | +| | | determined. By default, | +| | | the grid type (Gaussian, | +| | | uniform, etc.) is | +| | | determined by calling | +| | | grid.classifyInFamily. | +| | | If the mode is 'off' | +| | | grid.getType is used | +| | | instead. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMask()`` | Get the mask array of | +| | | this grid, if | +| | | any.Returns a 2-D | +| | | Numeric array, having | +| | | the same shape as the | +| | | grid. If the mask is not | +| | | explicitly defined, the | +| | | return value is | +| | | ``None``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMesh(self, transpos | Generate a mesh array | +| | e=None)`` | for the meshfill | +| | | graphics method.If | +| | | transpose is defined to | +| | | a tuple, say (1,0), | +| | | first transpose | +| | | latbounds and lonbounds | +| | | according to the tuple, | +| | | in this case (1,0,2). | ++--------------------------+--------------------------+--------------------------+ +| None | ``setBounds(latBounds, l | Set the grid | +| | onBounds, persistent=0)` | boundaries.\ ``latBounds | +| | ` | `` | +| | | is a NumPy array of | +| | | shape (n,2), such that | +| | | the boundaries of the | +| | | kth axis value are | +| | | ``[latBounds[k,0],latBou | +| | | nds[k,1] ]``. | +| | | ``lonBounds`` is defined | +| | | similarly for the | +| | | longitude array. | +| | | **Note:** By default, | +| | | the boundaries are not | +| | | written to the file or | +| | | dataset containing the | +| | | grid (if any). This | +| | | allows bounds to be set | +| | | on read-only files, for | +| | | regridding. If the | +| | | optional argument | +| | | ``persistent`` is set to | +| | | 1, the boundary array is | +| | | written to the file. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setMask(mask, persiste | Set the grid mask. If | +| | nt=0)`` | ``persistent == 1``, the | +| | | mask values are written | +| | | to the associated file, | +| | | if any. Otherwise, the | +| | | mask is associated with | +| | | the grid, but no I/O is | +| | | generated. ``mask`` is a | +| | | two-dimensional, | +| | | Boolean-valued Numeric | +| | | array, having the same | +| | | shape as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``subGridRegion(latInter | Create a new grid | +| | val, lonInterval)`` | corresponding to the | +| | | coordinate region | +| | | defined by | +| | | ``latInterval, lonInterv | +| | | al.`` | +| | | | +| | | ``latInterval`` and | +| | | ``lonInterval`` are the | +| | | coordinate intervals for | +| | | latitude and longitude, | +| | | respectively. | +| | | | +| | | Each interval is a tuple | +| | | having one of the forms: | +| | | | +| | | - ``(x,y)`` | +| | | - ``(x,y,indicator)`` | +| | | - ``(x,y,indicator,cycl | +| | | e)`` | +| | | - ``None`` | +| | | | +| | | where ``x`` and ``y`` | +| | | are coordinates | +| | | indicating the interval | +| | | ``[x,y)``, and: | +| | | | +| | | ``indicator`` is a | +| | | two-character string, | +| | | where the first | +| | | character is 'c' if the | +| | | interval is closed on | +| | | the left, 'o' if open, | +| | | and the second character | +| | | has the same meaning for | +| | | the right-hand point. | +| | | (Default: 'co'). | +| | | | +| | | If ``cycle`` is | +| | | specified, the axis is | +| | | treated as circular with | +| | | the given cycle value. | +| | | By default, if | +| | | ``grid.isCircular()`` is | +| | | true, the axis is | +| | | treated as circular with | +| | | a default value of | +| | | 360.0. | +| | | | +| | | An interval of ``None`` | +| | | returns the full index | +| | | interval of the axis. | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges.Note: | +| | | The result grid is not | +| | | associated with any file | +| | | or dataset. | ++--------------------------+--------------------------+--------------------------+ +| Transient-CurveGrid | ``toCurveGrid(gridid=Non | Convert to a curvilinear | +| | e)`` | grid. If the grid is | +| | | already curvilinear, a | +| | | copy of the grid object | +| | | is returned. ``gridid`` | +| | | is the string identifier | +| | | of the resulting | +| | | curvilinear grid object. | +| | | If unspecified, the grid | +| | | ID is copied. **Note:** | +| | | This method does not | +| | | apply to generic grids. | ++--------------------------+--------------------------+--------------------------+ +| Transient-GenericGrid | ``toGenericGrid(gridid=N | Convert to a generic | +| | one)`` | grid. If the grid is | +| | | already generic, a copy | +| | | of the grid is returned. | +| | | ``gridid`` is the string | +| | | identifier of the | +| | | resulting curvilinear | +| | | grid object. If | +| | | unspecified, the grid ID | +| | | is copied. | ++--------------------------+--------------------------+--------------------------+ + + +Table 2.32 RectGrid Methods, additional to HorizontalGrid + Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| String | ``getOrder()`` | Get the grid ordering, | +| | | either "yx" if latitude | +| | | is the first axis, or | +| | | "xy" if longitude is the | +| | | first axis. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getType()`` | Get the grid type, | +| | | either "gaussian", | +| | | "uniform", "equalarea", | +| | | or "generic". | ++--------------------------+--------------------------+--------------------------+ +| (Array,Array) | ``getWeights()`` | Get the normalized area | +| | | weight arrays, as a | +| | | tuple | +| | | ``(latWeights, lon | +| | | Weights)``. | +| | | It is assumed that the | +| | | latitude and longitude | +| | | axes are defined in | +| | | degrees. | +| | | | +| | | The latitude weights are | +| | | defined as: | +| | | | +| | | ``latWeights[i] = 0.5 * | +| | | abs(sin(latBounds[i+1]) | +| | | - sin(latBounds[i] | +| | | ))`` | +| | | | +| | | The longitude weights | +| | | are defined as: | +| | | | +| | | ``lonWeights[i] = abs(lo | +| | | nBounds[i+1] - lonBounds | +| | | [i])/360.0`` | +| | | | +| | | For a global grid, the | +| | | weight arrays are | +| | | normalized such that the | +| | | sum of the weights is | +| | | 1.0 | +| | | | +| | | **Example:** | +| | | | +| | | Generate the 2-D weights | +| | | array, such that | +| | | ``weights[i.j]`` is the | +| | | fractional area of grid | +| | | zone ``[i,j]``. | +| | | | +| | | :: | +| | | | +| | | from cdms import MV | +| | | latwts, lonwts = gri | +| | | d.getWeights() | +| | | weights = MV.outerpr | +| | | oduct(latwts, lonwts) | +| | | | +| | | Also see the function | +| | | ``area_weights`` in | +| | | module | +| | | ``pcmdi.weighting``. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setType(gridtype)`` | Set the grid type. | +| | | ``gridtype`` is one of | +| | | "gaussian", "uniform", | +| | | "equalarea", or | +| | | "generic". | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``subGrid((latStart,latS | Create a new grid, with | +| | top),(lonStart,lonStop)) | latitude index range | +| | `` | [latStart : latStop] and | +| | | longitude index range | +| | | [lonStart : lonStop]. | +| | | Either index range can | +| | | also be specified as | +| | | None, indicating that | +| | | the entire range of the | +| | | latitude or longitude is | +| | | used. | +| | | | +| | | **Example:** | +| | | | +| | | This creates newgrid | +| | | corresponding to all | +| | | latitudes and index | +| | | range [lonStart:lonStop] | +| | | of oldgrid. | +| | | | +| | | ``newgrid = oldgrid.subG | +| | | rid(None, (lonStart, lon | +| | | Stop))`` | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``transpose()`` | Create a new grid, with | +| | | axis order reversed. The | +| | | grid mask is also | +| | | transposed. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ + + +2.11 Variable +^^^^^^^^^^^^^ + +A Variable is a multidimensional data object, consisting of: + +- a multidimensional data array, possibly masked, +- a collection of attributes +- a domain, an ordered tuple of CoordinateAxis objects. + +A Variable which is contained in a Dataset or CdmsFile is called a +persistent variable. Setting a slice of a persistent Variable writes +data to the Dataset or file, and referencing a Variable slice reads data +from the Dataset. Variables may also be transient, not associated with a +Dataset or CdmsFile. + +Variables support arithmetic operations, including the basic Python +operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations +defined in the MV module. The result of an arithmetic operation is a +transient variable, that is, the axis information is transferred to the +result. + +The methods subRegion and subSlice return transient variables. In +addition, a transient variable may be created with the +cdms.createVariable method. The vcs and regrid module methods take +advantage of the attribute, domain, and mask information in a transient +variable. + + +Table 2.33 Variable Internal Attributes + ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Definition | ++=======================+======================+=============================================================================================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``id`` | Variable identifier. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``name\_in\_file`` | The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the variable. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Tuple | ``shape`` | The length of each axis of the variable | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.34 Variable Constructors + ++--------------------------------------+--------------------------------------+ +| Constructor | Description | ++======================================+======================================+ +| ``Dataset.createVariable(String id, | Create a Variable in a Dataset. This | +| String datatype, List axes)`` | function is not yet implemented. | ++--------------------------------------+--------------------------------------+ +| ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | +| String datatype, List axesOr- | ``id`` is the name of the variable. | +| Grids)`` | ``datatype`` is the MA or Numeric | +| | typecode, for example, MA.Float. | +| | ``axesOrGrids`` is a list of Axis | +| | and/or Grid objects, on which the | +| | variable is defined. Specifying a | +| | rectilinear grid is equivalent to | +| | listing the grid latitude and | +| | longitude axes, in the order defined | +| | for the grid. \*\*Note:\*\* this | +| | argument can either be a list or a | +| | tuple. If the tuple form is used, | +| | and there is only one element, it | +| | must have a following comma, e.g.: | +| | ``(axisobj,)``. | ++--------------------------------------+--------------------------------------+ +| :: | Create a transient variable, not | +| | associated with a file or dataset. | +| cdms.createVariable(array, typec | ``array`` is the data values: a | +| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numeric | +| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MA | +| s=None,attributes=None, id=None) | typecode of the array. Defaults to | +| | the typecode of array. ``copy`` is | +| | an integer flag: if 1, the variable | +| | is created with a copy of the array, | +| | if 0 the variable data is shared | +| | with array. ``savespace`` is an | +| | integer flag: if set to 1, internal | +| | Numeric operations will attempt to | +| | avoid silent upcasting. ``mask`` is | +| | an array of integers with value 0 or | +| | 1, having the same shape as array. | +| | array elements with a corresponding | +| | mask value of 1 are considered | +| | invalid, and are not used for | +| | subsequent Numeric operations. The | +| | default mask is obtained from array | +| | if present, otherwise is None. | +| | ``fill_value`` is the missing value | +| | flag. The default is obtained from | +| | array if possible, otherwise is set | +| | to 1.0e20 for floating point | +| | variables, 0 for integer-valued | +| | variables. ``grid`` is a rectilinear | +| | grid object. ``axes`` is a tuple of | +| | axis objects. By default the axes | +| | are obtained from array if present. | +| | Otherwise for a dimension of length | +| | n, the default axis has values [0., | +| | 1., ..., double(n)]. ``attributes`` | +| | is a dictionary of attribute values. | +| | The dictionary keys must be strings. | +| | By default the dictionary is | +| | obtained from array if present, | +| | otherwise is empty. ``id`` is the | +| | string identifier of the variable. | +| | By default the id is obtained from | +| | array if possible, otherwise is set | +| | to 'variable\_n' for some integer n. | ++--------------------------------------+--------------------------------------+ + + + +Table 2.35 Variable Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Variable | ``tvar = var[ i:j, m:n]` | Read a slice of data | +| | ` | from the file or | +| | | dataset, resulting in a | +| | | transient variable. | +| | | Singleton dimensions are | +| | | 'squeezed' out. Data is | +| | | returned in the physical | +| | | ordering defined in the | +| | | dataset. The forms of | +| | | the slice operator are | +| | | listed in Table 2.36 on | +| | | page 102. | ++--------------------------+--------------------------+--------------------------+ +| None | ``var[ i:j, m:n] = array | Write a slice of data to | +| | `` | the external dataset. | +| | | The forms of the slice | +| | | operator are listed in | +| | | Table 2.21 on page 32. | +| | | (Variables in CdmsFiles | +| | | only) | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``tvar = var(selector)`` | Calling a variable as a | +| | | function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless raw=1 | +| | | keyword is specified. | +| | | See "Selectors" on page | +| | | 103. | ++--------------------------+--------------------------+--------------------------+ +| None | ``assignValue(Array ar)` | Write the entire data | +| | ` | array. Equivalent to | +| | | ``var[:] = ar``. | +| | | (Variables in CdmsFiles | +| | | only). | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``astype(typecode)`` | Cast the variable to a | +| | | new datatype. Typecodes | +| | | are as for MV, MA, and | +| | | Numeric modules. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``clone(copyData=1)`` | Return a copy of a | +| | | transient variable. | +| | | | +| | | If copyData is 1 (the | +| | | default) the variable | +| | | data is copied as well. | +| | | If copyData is 0, the | +| | | result transient | +| | | variable shares the | +| | | original transient | +| | | variables data array. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | :: | Return a lat/level | +| | | vertical cross-section | +| | crossSectionRegrid(n | regridded to a new set | +| | ewLevel, newLatitude, me | of latitudes newLatitude | +| | thod="log", missing=None | and levels newLevel. The | +| | , order=None) | variable should be a | +| | | function of latitude, | +| | | level, and (optionally) | +| | | time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``newLatitude`` is an | +| | | axis of the result | +| | | latitudes. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzy" or | +| | | "zy". The default is | +| | | ``var.getOrder()``. | +| | | | +| | | *See also:* ``regrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(n)`` | Get the n-th axis. | +| | | | +| | | ``n`` is an integer. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisIds()`` | Get a list of axis | +| | | identifiers. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``getAxisIndex(axis_spec | Return the index of the | +| | )`` | axis specificed by | +| | | axis\_spec. Return -1 if | +| | | no match. | +| | | | +| | | ``axis_spec`` is a | +| | | specification as defined | +| | | for getAxisList | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisList(axes=None, | Get an ordered list of | +| | omit=None, order=None)` | axis objects in the | +| | ` | domain of the variable. | +| | | | +| | | If ``axes`` is not | +| | | ``None``, include only | +| | | certain axes. Otherwise | +| | | axes is a list of | +| | | specifications as | +| | | described below. Axes | +| | | are returned in the | +| | | order specified unless | +| | | the order keyword is | +| | | given. | +| | | | +| | | If ``omit`` is not | +| | | ``None``, omit those | +| | | specified by an integer | +| | | dimension number. | +| | | Otherwise omit is a list | +| | | of specifications as | +| | | described below. | +| | | | +| | | ``order`` is an optional | +| | | string determining the | +| | | output order. | +| | | | +| | | Specifications for the | +| | | axes or omit keywords | +| | | are a list, each element | +| | | having one of the | +| | | following forms: | +| | | | +| | | - an integer dimension | +| | | index, starting at 0. | +| | | - a string representing | +| | | an axis id or one of | +| | | the strings 'time', | +| | | 'latitude', 'lat', | +| | | 'longitude', 'lon', | +| | | 'lev' or 'level'. | +| | | - a function that takes | +| | | an axis as an | +| | | argument and returns | +| | | a value. If the value | +| | | returned is true, the | +| | | axis matches. | +| | | - an axis object; will | +| | | match if it is the | +| | | same object as axis. | +| | | | +| | | ``order`` can be a | +| | | string containing the | +| | | characters t,x,y,z, or | +| | | -. If a dash ('-') is | +| | | given, any elements of | +| | | the result not chosen | +| | | otherwise are filled in | +| | | from left to right with | +| | | remaining candidates. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisListIndex(axes= | Return a list of indices | +| | None, omit=None, order=N | of axis objects. | +| | one)`` | Arguments are as for | +| | | getAxisList. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getDomain()`` | Get the domain. Each | +| | | element of the list is | +| | | itself a tuple of the | +| | | form | +| | | ``(axis,start,length,tru | +| | | e_length)`` | +| | | where axis is an axis | +| | | object, start is the | +| | | start index of the | +| | | domain relative to the | +| | | axis object, length is | +| | | the length of the axis, | +| | | and true\_length is the | +| | | actual number of | +| | | (defined) points in the | +| | | domain. *See also:* | +| | | ``getAxisList``. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``getGrid()`` | Return the associated | +| | | grid, or ``None`` if the | +| | | variable is not gridded. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLevel()`` | Get the vertical level | +| | | axis, or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the longitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Various | ``getMissing()`` | Get the missing data | +| | | value, or ``None`` if | +| | | not found. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getOrder()`` | Get the order string of | +| | | a spatio-temporal | +| | | variable. The order | +| | | string specifies the | +| | | physical ordering of the | +| | | data. It is a string of | +| | | characters with length | +| | | equal to the rank of the | +| | | variable, indicating the | +| | | order of the variable's | +| | | time, level, latitude, | +| | | and/or longitude axes. | +| | | Each character is one | +| | | of: | +| | | | +| | | - 't': time | +| | | - 'z': vertical level | +| | | - 'y': latitude | +| | | - 'x': longitude | +| | | - '-': the axis is not | +| | | spatio-temporal. | +| | | | +| | | **Example:** | +| | | | +| | | A variable with ordering | +| | | "tzyx" is 4-dimensional, | +| | | where the ordering of | +| | | axes is (time, level, | +| | | latitude, longitude). | +| | | | +| | | **Note:** The order | +| | | string is of the form | +| | | required for the order | +| | | argument of a regridder | +| | | function. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths(*intervals)`` | Get the file paths | +| | | associated with the | +| | | index region specified | +| | | by intervals. | +| | | | +| | | ``intervals`` is a list | +| | | of scalars, 2-tuples | +| | | representing [i,j), | +| | | slices, and/or Ellipses. | +| | | If no ``argument(s)`` | +| | | are present, all file | +| | | paths associated with | +| | | the variable are | +| | | returned. | +| | | | +| | | Returns a list of tuples | +| | | of the form | +| | | (path,slicetuple), where | +| | | path is the path of a | +| | | file, and slicetuple is | +| | | itself a tuple of | +| | | slices, of the same | +| | | length as the rank of | +| | | the variable, | +| | | representing the portion | +| | | of the variable in the | +| | | file corresponding to | +| | | intervals. | +| | | | +| | | **Note:** This function | +| | | is not defined for | +| | | transient variables. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getTime()`` | Get the time axis, or | +| | | ``None`` if not found. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``len(var)`` | The length of the first | +| | | dimension of the | +| | | variable. If the | +| | | variable is | +| | | zero-dimensional | +| | | (scalar), a length of 0 | +| | | is returned. | +| | | | +| | | **Note:** ``size()`` | +| | | returns the total number | +| | | of elements. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | ``pressureRegrid (newLev | Return the variable | +| | el, method="log", missin | regridded to a new set | +| | g=None, order=None | of pressure levels | +| | )`` | newLevel. The variable | +| | | must be a function of | +| | | latitude, longitude, | +| | | pressure level, and | +| | | (optionally) time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzyx" or | +| | | "zyx". The default is | +| | | ``var.getOrder()`` | +| | | | +| | | See also: ``regrid``, | +| | | ``crossSectionRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``rank()`` | The number of dimensions | +| | | of the variable. | ++--------------------------+--------------------------+--------------------------+ +| Transient | :: | Return the variable | +| | | regridded to the | +| | regrid (togrid, miss | horizontal grid togrid. | +| | ing=None, order=None, Va | | +| | riable mask=None) | ``missing`` is a Float | +| | | specifying the missing | +| | | data value. The default | +| | | is 1.0e20. | +| | | | +| | | ``order`` is a string | +| | | indicating the order of | +| | | dimensions of the array. | +| | | It has the form returned | +| | | from | +| | | ``variable.getOrder()``. | +| | | For example, the string | +| | | "tzyx" indicates that | +| | | the dimension order of | +| | | array is (time, level, | +| | | latitude, longitude). If | +| | | unspecified, the | +| | | function assumes that | +| | | the last two dimensions | +| | | of array match the input | +| | | grid. | +| | | | +| | | ``mask`` is a Numeric | +| | | array, of datatype | +| | | Integer or Float, | +| | | consisting of ones and | +| | | zeros. A value of 0 or | +| | | 0.0 indicates that the | +| | | corresponding data value | +| | | is to be ignored for | +| | | purposes of regridding. | +| | | If mask is | +| | | two-dimensional of the | +| | | same shape as the input | +| | | grid, it overrides the | +| | | mask of the input grid. | +| | | If the mask has more | +| | | than two dimensions, it | +| | | must have the same shape | +| | | as array. In this case, | +| | | the missing data value | +| | | is also ignored. Such an | +| | | n-dimensional mask is | +| | | useful if the pattern of | +| | | missing data varies with | +| | | level (e.g., ocean data) | +| | | or time. Note: If | +| | | neither missing or mask | +| | | is set, the default mask | +| | | is obtained from the | +| | | mask of the array if | +| | | any. | +| | | | +| | | See also: | +| | | ``crossSectionRegrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxis(n, axis)`` | Set the n-th axis | +| | | (0-origin index) of to a | +| | | copy of axis. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxisList(axislist)` | Set all axes of the | +| | ` | variable. axislist is a | +| | | list of axis objects. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setMissing(value)`` | Set the missing value. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``size()`` | Number of elements of | +| | | the variable. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a coordinate region | +| | | of data, returning a | +| | subRegion(*region, t | transient variable. A | +| | ime=None, level=None, la | region is a | +| | titude=None, longitude=N | hyperrectangle in | +| | one, squeeze=0, raw=0) | coordinate space. | +| | | | +| | | ``region`` is an | +| | | argument list, each item | +| | | of which specifies an | +| | | interval of a coordinate | +| | | axis. The intervals are | +| | | listed in the order of | +| | | the variable axes. If | +| | | trailing dimensions are | +| | | omitted, all values of | +| | | those dimensions are | +| | | retrieved. If an axis is | +| | | circular | +| | | (axis.isCircular() is | +| | | true) or cycle is | +| | | specified (see below), | +| | | then data will be read | +| | | with wraparound in that | +| | | dimension. Only one axis | +| | | may be read with | +| | | wraparound. A coordinate | +| | | interval has one of the | +| | | forms listed in Table | +| | | 2.37 on page 102. Also | +| | | see | +| | | ``axis.mapIntervalExt``. | +| | | | +| | | The optional keyword | +| | | arguments ``time``, | +| | | ``level``, ``latitude``, | +| | | and ``longitude`` may | +| | | also be used to specify | +| | | the dimension for which | +| | | the interval applies. | +| | | This is particularly | +| | | useful if the order of | +| | | dimensions is not known | +| | | in advance. An exception | +| | | is raised if a keyword | +| | | argument conflicts with | +| | | a positional region | +| | | argument. | +| | | | +| | | The optional keyword | +| | | argument ``squeeze`` | +| | | determines whether or | +| | | not the shape of the | +| | | returned array contains | +| | | dimensions whose length | +| | | is 1; by default this | +| | | argument is 0, and such | +| | | dimensions are not | +| | | 'squeezed out'. | +| | | | +| | | The optional keyword | +| | | argument ``raw`` | +| | | specifies whether the | +| | | return object is a | +| | | variable or a masked | +| | | array. By default, a | +| | | transient variable is | +| | | returned, having the | +| | | axes and attributes | +| | | corresponding to2,3 the | +| | | region read. If raw=1, | +| | | an MA masked array is | +| | | returned, equivalent to | +| | | the transient variable | +| | | without the axis and | +| | | attribute information. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a slice of data, | +| | | returning a transient | +| | subSlice(*specs, tim | variable. This is a | +| | e=None, level=None, lati | functional form of the | +| | tude=None, longitude=Non | slice operator [] with | +| | e, squeeze=0, raw=0) | the squeeze option | +| | | turned off. | +| | | | +| | | ``specs`` is an argument | +| | | list, each element of | +| | | which specifies a slice | +| | | of the corresponding | +| | | dimension. There can be | +| | | zero or more positional | +| | | arguments, each of the | +| | | form: | +| | | | +| | | - a single integer n, | +| | | meaning | +| | | ``slice(n, n+1)`` | +| | | - an instance of the | +| | | slice class | +| | | - a tuple, which will | +| | | be used as arguments | +| | | to create a slice | +| | | - ':', which means a | +| | | slice covering that | +| | | entire dimension | +| | | - Ellipsis (...), which | +| | | means to fill the | +| | | slice list with ':' | +| | | leaving only enough | +| | | room at the end for | +| | | the remaining | +| | | positional arguments | +| | | - a Python slice | +| | | object, of the form | +| | | ``slice(i,j,k)`` | +| | | | +| | | If there are fewer | +| | | slices than | +| | | corresponding | +| | | dimensions, all values | +| | | of the trailing | +| | | dimensions are read. | +| | | | +| | | The keyword arguments | +| | | are defined as in | +| | | subRegion. | +| | | | +| | | There must be no | +| | | conflict between the | +| | | positional arguments and | +| | | the keywords. | +| | | | +| | | In ``(a)-(c)`` and (f), | +| | | negative numbers are | +| | | treated as offsets from | +| | | the end of that | +| | | dimension, as in normal | +| | | Python indexing. | ++--------------------------+--------------------------+--------------------------+ +| String | ``typecode()`` | The Numeric datatype | +| | | identifier. | ++--------------------------+--------------------------+--------------------------+ + +**Example:** Get a region of data. + +Variable ta is a function of (time, latitude, longitude). Read data +corresponding to all times, latitudes -45.0 up to but not +including+45.0, longitudes 0.0 through and including longitude 180.0: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) + +.. raw:: html + +
+ +or equivalently: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, + 180.0) + +.. raw:: html + +
+ +Read all data for March, 1980: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(time=('1980-3','1980-4','co')) + +.. raw:: html + +
+ + + +Table 2.36 Variable Slice Operators + ++-------------------+---------------------------------------------------------------+ +| Operator | Description | ++===================+===============================================================+ +| ``[i]`` | The ith element, zero-origin indexing. | ++-------------------+---------------------------------------------------------------+ +| ``[i:j]`` | The ith element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[i:]`` | The ith element through the end | ++-------------------+---------------------------------------------------------------+ +| ``[:j]`` | The beginning element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[:]`` | The entire array | ++-------------------+---------------------------------------------------------------+ +| ``[i:j:k]`` | Every kth element | ++-------------------+---------------------------------------------------------------+ +| ``[i:j, m:n]`` | Multidimensional slice | ++-------------------+---------------------------------------------------------------+ +| ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | ++-------------------+---------------------------------------------------------------+ +| ``[-1]`` | Negative indices ‘wrap around’. -1 is the last element | ++-------------------+---------------------------------------------------------------+ + + + +Table 2.37 Index and Coordinate Intervals + ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| Interval Definition | Example Interval Definition | Example | ++========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ +| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | +| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | +| | | ``'1980-1-3'`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | +| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | +| | | ``slice(,,-1)`` reverses the direction of the axis. | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``':'`` | all axis values of one dimension |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``Ellipsis`` | all values of all intermediate axes |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ + + + +2.11.1 Selectors + +A selector is a specification of a region of data to be selected from a +variable. For example, the statement + +.. raw:: html + +
+ +:: + + x = v(time='1979-1-1', level=(1000.0,100.0)) + +.. raw:: html + +
+ +means ‘select the values of variable v for time ‘1979-1-1’ and levels +1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are +generally used to represent regions of space and time. + +The form for using a selector is + +.. raw:: html + +
+ +:: + + result = v(s) + +.. raw:: html + +
+ +where v is a variable and s is the selector. An equivalent form is + +.. raw:: html + +
+ +:: + + result = f('varid', s) + +.. raw:: html + +
+ +where f is a file or dataset, and ‘varid’ is the string ID of a +variable. + +A selector consists of a list of selector components. For example, the +selector + +.. raw:: html + +
+ +:: + + time='1979-1-1', level=(1000.0,100.0) + +.. raw:: html + +
+ +has two components: time=’1979-1-1’, and level=(1000.0,100.0). This +illustrates that selector components can be defined with keywords, using +the form: + +.. raw:: html + +
+ +:: + + keyword=value + +.. raw:: html + +
+ +Note that for the keywords time, level, latitude, and longitude, the +selector can be used with any variable. If the corresponding axis is not +found, the selector component is ignored. This is very useful for +writing general purpose scripts. The required keyword overrides this +behavior. These keywords take values that are coordinate ranges or index +ranges as defined in Table 2.37 on page 102. + +The following keywords are available: Another form of selector +components is the positional form, where the component order corresponds +to the axis order of a variable. For example: + + + +Table 2.38 Selector keywords + ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| Keyword | Description | Value | ++=================+======================================================================+============================================================================+ +| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``grid`` | Regrid the result to the grid. | Grid object | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``raw`` | Return a masked array (MA.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ + +Another form of selector components is the positional form, where the +component order corresponds to the axis order of a variable. For +example: + +.. raw:: html + +
+ +:: + + x9 = hus(('1979-1-1','1979-2-1'),1000.0) + +.. raw:: html + +
+ +reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and +coordinate value 1000.0 of the second axis. Non-keyword arguments of the +form(s) listed in Table 2.37 on page 102 are treated as positional. Such +selectors are more concise, but not as general or flexible as the other +types described in this section. + +Selectors are objects in their own right. This means that a selector can +be defined and reused, independent of a particular variable. Selectors +are constructed using the cdms.selectors.Selector class. The constructor +takes an argument list of selector components. For example: + +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x1 = v1(sel) + x2 = v2(sel) + +.. raw:: html + +
+ +For convenience CDMS provides several predefined selectors, which can be +used directly or can be combined into more complex selectors. The +selectors time, level, latitude, longitude, and required are equivalent +to their keyword counterparts. For example: + +.. raw:: html + +
+ +:: + + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + +.. raw:: html + +
+ +and + +.. raw:: html + +
+ +:: + + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + +.. raw:: html + +
+ +are equivalent. Additionally, the predefined selectors +``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` +take arguments ``(startindex, stopindex[, stride])``: + +.. raw:: html + +
+ +:: + + from cdms import timeslice, levelslice + x = v(timeslice(0,2), levelslice(16,17)) + +.. raw:: html + +
+ +Finally, a collection of selectors is defined in module cdutil.region: + +.. raw:: html + +
+ +:: + + from cdutil.region import * + NH=NorthernHemisphere=domain(latitude=(0.,90.) + SH=SouthernHemisphere=domain(latitude=(-90.,0.)) + Tropics=domain(latitude=(-23.4,23.4)) + NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) + SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) + +.. raw:: html + +
+ +Selectors can be combined using the & operator, or by refining them in +the call: + +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + from cdms import level + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x1 = hus(sel3) + x2 = hus(sel2, level=1000.0) + +.. raw:: html + +
+ + + +2.11.2 Selector examples + +CDMS provides a variety of ways to select or slice data. In the +following examples, variable hus is contained in file sample.nc, and is +a function of (time, level, latitude, longitude). Time values are +monthly starting at 1979-1-1. There are 17 levels, the last level being +1000.0. The name of the vertical level axis is ‘plev’. All the examples +select the first two times and the last level. The last two examples +remove the singleton level dimension from the result array. + +.. raw:: html + +
+ +:: + + import cdms + f = cdms.open('sample.nc') + hus = f.variables['hus'] + + # Keyword selection + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + + # Interval indicator (see mapIntervalExt) + x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) + + # Axis ID (plev) as a keyword + x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + + # Positional + x9 = hus(('1979-1-1','1979-2-1'),1000.0) + + # Predefined selectors + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + + from cdms import timeslice, levelslice + x = hus(timeslice(0,2), levelslice(16,17)) + + # Call file as a function + x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + + # Python slices + x = hus(time=slice(0,2), level=slice(16,17)) + + # Selector objects + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x = hus(sel) + + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x = hus(sel3) + x = hus(sel2, level=1000.0) + + # Squeeze singleton dimension (level) + x = hus[0:2,16] + x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) + + f.close() + +.. raw:: html + +
+ + + +2.12 Examples +^^^^^^^^^^^^^ + + +2.12.1 Example 1 +---------------- + +In this example, two datasets are opened, containing surface air +temperature (‘tas’) and upper-air temperature (‘ta’) respectively. +Surface air temperature is a function of (time, latitude, longitude). +Upper-air temperature is a function of (time, level, latitude, +longitude). Time is assumed to have a relative representation in the +datasets (e.g., with units ‘months since basetime’). + +Data is extracted from both datasets for January of the first input year +through December of the second input year. For each time and level, +three quantities are calculated: slope, variance, and correlation. The +results are written to a netCDF file. For brevity, the functions +``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. + +.. raw:: html + +
+ +:: + + 1. import cdms + import MV + + # Calculate variance, slope, and correlation of + # surface air temperature with upper air temperature + # by level, and save to a netCDF file. 'pathTa' is the location of + # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + # Data is extracted from January of year1 through December of year2. + def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): + + # Open the files for ta and tas + fta = cdms.open(pathTa) + ftas = cdms.open(pathTas) + + 2. #Get upper air temperature + taObj = fta['ta'] + levs = taObj.getLevel() + + #Get the surface temperature for the closed interval [time1,time2] + tas = ftas('tas', time=(month1,month2,'cc')) + + # Allocate result arrays + newaxes = taObj.getAxisList(omit='time') + newshape = tuple([len(a) for a in newaxes]) + cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + + # Remove seasonal cycle from surface air temperature + tas = removeSeasonalCycle(tas) + + # For each level of air temperature, remove seasonal cycle + # from upper air temperature, and calculate statistics + 5. for ilev in range(len(levs)): + + ta = taObj(time=(month1,month2,'cc'), \ + level=slice(ilev, ilev+1), squeeze=1) + ta = removeSeasonalCycle(ta) + cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + + # Write slope, correlation, and variance variables + 6. f = cdms.open('CC_B_V_ALL.nc','w') + f.title = filtered + f.write(b) + f.write(cc) + f.write(v) + f.close() + + 7. if __name__=='__main__': + pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' + pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' + # Process Jan80 through Dec81 + ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') + +.. raw:: html + +
+ +**Notes:** + +#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements + arithmetic functions. +#. ``taObj`` is a file (persistent) variable. At this point, no data has + actually been read. This happens when the file variable is sliced, or + when the subRegion function is called. levs is an axis. +#. Calling the file like a function reads data for the given variable + and time range. Note that month1 and month2 are time strings. +#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are + transient variables, not associated with a file. The assigned names + are used when the variables are written. +#. Another way to read data is to call the variable as a function. The + squeeze option removes singleton axes, in this case the level axis. +#. Write the data. Axis information is written automatically. +#. This is the main routine of the script. ``pathTa`` and ``pathTas`` + pathnames. Data is processed from January 1980 through December 1981. + + + +2.12.2 Example 2 +---------------- + +In the next example, the pointwise variance of a variable over time is +calculated, for all times in a dataset. The name of the dataset and +variable are entered, then the variance is calculated and plotted via +the vcs module. + +.. raw:: html + +
+ +:: + + #!/usr/bin/env python + # + # Calculates gridpoint total variance + # from an array of interest + # + + import cdms + from MV import * + + # Wait for return in an interactive window + + def pause(): + print Hit return to continue: , + line = sys.stdin.readline() + + 1. # Calculate pointwise variance of variable over time + # Returns the variance and the number of points + # for which the data is defined, for each grid point + def calcVar(x): + # Check that the first axis is a time axis + firstaxis = x.getAxis(0) + if not firstaxis.isTime(): + raise 'First axis is not time, variable:', x.id + + n = count(x,0) + sumxx = sum(x*x) + sumx = sum(x) + variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + + return variance, n + + if __name__=='__main__': + import vcs, sys + + print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + path = string.strip(sys.stdin.readline()) + if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + + 2. # Open the dataset + dataset = cdms.open(path) + + # Select a variable from the dataset + print 'Variables in file:',path + varnames = dataset.variables.keys() + varnames.sort() + for varname in varnames: + + var = dataset.variables[varname] + if hasattr(var,'long_name'): + long_name = var.long_name + elif hasattr(var,'title'): + long_name = var.title + else: + long_name = '?' + + print '%-10s: %s'%(varname,long_name) + print 'Select a variable: ', + 3. varname = string.strip(sys.stdin.readline()) + var = dataset(varname) + dataset.close() + + # Calculate variance, count, and set attributes + variance,n = calcVar(var) + variance.id = 'variance_%s'%var.id + n.id = 'count_%s'%var.id + if hasattr(var,'units'): + variance.units = '(%s)^2'%var.units + + # Plot variance + w=vcs.init() + 4. w.plot(variance) + pause() + w.clear() + w.plot(n) + pause() + w.clear() + +.. raw:: html + +
+ +The result of running this script is as follows: + +.. raw:: html + +
+ +:: + + % calcVar.py + Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: + + Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml + albt : Albedo TOA [%] + albtcs : Albedo TOA clear sky [%] + rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] + rlut : LW radiation TOA (OLR) [W/m^2] + rlutcs : LW radiation upward TOA clear sky [W/m^2] + rscrft : SW Cloud Radiation Forcing TOA [W/m^2] + rsdt : SW radiation downward TOA [W/m^2] + rsut : SW radiation upward TOA [W/m^2] + rsutcs : SW radiation upward TOA clear sky [W/m^2] + Select a variable: albt + + + + Hit return to continue: + + + +.. raw:: html + +
+ +**Notes:** + +#. n = count(x, 0) returns the pointwise number of valid values, summing + across axis 0, the first axis. count is an MV function. +#. dataset is a Dataset or CdmsFile object, depending on whether a .xml + or .nc pathname is entered. dataset.variables is a dictionary mapping + variable name to file variable. +#. var is a transient variable. +#. Plot the variance and count variables. Spatial longitude and latitude + information are carried with the computations, so the continents are + plotted correctly. + +.. raw:: html + +
+ +`Previous `__ `Table of +Contents `__ +`Next `__ + +.. raw:: html + +
+ +.. raw:: html + + + +.. raw:: html + +
+ +.. raw:: html + +
+ +.. raw:: html + +
+ +.. raw:: html + +
+ +Project Information + +- `Mission `__ +- `Governance `__ +- `Acknowledgements `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Contribute +^^^^^^^^^^ + +- `GitHub Project Page `__ +- `Wiki `__ +- `Report a Bug `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Press +^^^^^ + +- `Presentations `__ +- `Publications `__ +- `Reports `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +Info +^^^^ + +- `Animations `__ +- `Design Documents `__ +- `Use Cases `__ + +.. raw:: html + +
+ +.. raw:: html + +
+ +.. raw:: html + +
+ +-------------- + +.. raw:: html + + + +.. raw:: html + +
+ +.. |image0| image:: /images/uvcdat.png + :class: logo + :target: / +.. |Diagram 1| image:: /images/diagram1.jpg + diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst new file mode 100644 index 00000000..0c965d17 --- /dev/null +++ b/docs/source/manual/cdms_3.rst @@ -0,0 +1,234 @@ +CHAPTER 3 cdtime Module +----------------------- + +3.1 Time types +^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +The ``cdtime`` module implements the CDMS time types, methods, and +calendars. These are made available with the command + +.. doctest:: + + >>> import cdtime + +Two time types are available: relative time and component time. Relative +time is time relative to a fixed base time. It consists of: + +- a units string, of the form ‘units since basetime’, and +- a floating-point value + +For example, the time “28.0 days since 1996-1-1” has value=28.0, and +units=’days since 1996-1-1’ + +Component time consists of the integer fields year, month, day, hour, +minute, and the floating-point field second. A sample component time is +``1996-2-28 12:10:30.0`` + +The ``cdtime`` module contains functions for converting between these +forms, based on the common calendars used in climate simulation. Basic +arithmetic and comparison operators are also available. + +3.2 Calendars +^^^^^^^^^^^^^ + +A calendar specifies the number of days in each month, for a given year. +cdtime supports these calendars: + +- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap + years, except century years not evenly divisible by 400. This is + sometimes called the proleptic Gregorian calendar, meaning that the + algorithm for leap years applies for all years. +- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates + before 158210-15 are encoded with the Julian calendar, otherwise are + encoded with the Gregorian calendar. The day immediately following + 1582-10-4 is 1582-10-15. This is the default calendar. +- ``cdtime.JulianCalendar``: years evenly divisible by four are leap + years, +- ``cdtime.NoLeapCalendar``: all years have 365 days, +- ``cdtime.Calendar360``: all months have 30 days. + +Several ``cdtime`` functions have an optional calendar argument. The +default calendar is the ``MixedCalendar``. The default calendar may be +changed with the command: + + +``cdtime.DefaultCalendar = newCalendar`` + +3.3 Time Constructors +^^^^^^^^^^^^^^^^^^^^^ + +The following table describes the methods for creating time types. + + +.. csv-table:: Time Constructors + :header: "Type", "Constructor", "Defintion" + :widths: 10, 40, 80 + + "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." + ,, "``value`` is an integer or floating point value." + ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" + ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + + "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." + ,,"``year`` is an integer." + ,,"``month`` is an integer in the range 1 .. 12" + ,,"``day`` is an integer in the range 1 .. 31" + ,,"``hour`` is an integer in the range 0 .. 23" + ,,"``minute`` is an integer in the range 0 .. 59" + ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + + +3.4 Relative Time +^^^^^^^^^^^^^^^^^ + +A relative time type has two members, value and units. Both can be set. + +Table 3.2 Relative Time Members +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + ++----------+---------+-------------------------------------------------------+ +| Type | Name | Summary | ++==========+=========+=======================================================+ +| Float | value | Number of units | ++----------+---------+-------------------------------------------------------+ +| String | units | Relative units, of the form “unit(s) since basetime | ++----------+---------+-------------------------------------------------------+ + +3.5 Component Time +^^^^^^^^^^^^^^^^^^ + +A component time type has six members, all of which are settable. + +.. csv-table:: Table 3.3 Component Time + :header: "Type", "Name", "Summary" + :widths: 15, 15, 50 + + "Integer", "year", "Year value" + "Integer", "month", "Month, in the range 1..12" + "Integer", "day", "Day of month, in the range 1 .. 31" + "Integer", "hour", "Hour, in the range 0 .. 23" + "Integer", "minute", "Minute, in the range 0 .. 59" + "Float", "second", "Seconds, in the range 0.0 .. 60.0" + +3.6 Time Methods +^^^^^^^^^^^^^^^^ + +The following methods apply both to relative and component times. + +.. csv-table:: Table 3.4 Time Methods + :header: "Type", "Method", "Definition" + :widths: 20, 75, 80 + + "Comptime or Reltime", "``t.add(value, intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" + ,, "``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." + ,, "``t2`` is the time to compare." + ,, "``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" + ,, "``calendar`` is the calendar type. " + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." + ,, "``calendar`` is the calendar type." + "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." + + +3.7 Examples +^^^^^^^^^^^^ +.. doctest:: + + >>> from cdtime import * + >>> c = comptime(1996,2,28) + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.add(1,Day) + 29.000000 days since 1996-1-1 + >>> print c.add(36,Hours) + 1996-2-29 12:0:0.0 + + +**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising. + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(1,Month) + 1979-9-1 0:0:0.0 + + +In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months: + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(2,Years) + 1981-8-1 0:0:0.0 + +Compare time values. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print c.cmp(r) + 1 +# >>> print r.cmp(c) +# -1 +# >>> print r.cmp(r) +# 1 + +Subtract an interval of time. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print r.sub(10,Days) + 18.000000 days since 1996-1-1 + >>> print c.sub(30,Days) + 1996-1-29 0:0:0.0 + + +For intervals of years or months, see the **note** under add() in the example above. + +Convert to component time. + +.. doctest:: + + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> r.tocomp() + 1996-1-29 0:0:0.0 + + +Convert to relative time. + +.. doctest:: + + >>> c = comptime(1996,2,28) + >>> print c.torel("days since 1996-1-1") + 58.000000 days since 1996-1-1 + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.torel("days since 1995") + 393.000000 days since 1995 + >>> print r.torel("days since 1995").value + 393.0 + diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst new file mode 100644 index 00000000..2e269ac5 --- /dev/null +++ b/docs/source/manual/cdms_5.rst @@ -0,0 +1,206 @@ +CHAPTER 5 Plotting CDMS data in Python +-------------------------------------- + +5.1 Overview +~~~~~~~~~~~~ + +Data read via the CDMS Python interface can be plotted using the ``vcs`` +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the UV-CDAT reference manual. +The ``vcs`` module provides access to the functionality of the VCS +visualization program. + +Examples of plotting data accessed from CDMS are given below, as well as +documentation for the plot routine keywords. + +5.2 Examples +~~~~~~~~~~~~ + +In the following examples, it is assumed that variable ``psl`` is +dimensioned (time, latitude, longitude). ``psl`` is contained in the +dataset named ``'sample.xml'``. + +5.2.1 Example: plotting a gridded variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + + +.. doctest:: Example: plotting a gridded variable + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> sample = clt[0,:] + >>> w=vcs.init() + >>> w.plot(sample) + + >>> f.close() + +**Notes:** + +.. csv-table:: LineNotes + :header: "Line", "Notes" + :widths: 10, 90 + + "3","Get a horizontal slice, for the first time point." + "4","Create a VCS Canvas ``w``." + "5", "Plot the data. Because sample is a transient variable, it encapsulates all the time, latitude, longitude, and attribute information." + "7", "Close the file. This must be done after the reference to the persistent variable ``ps l``." + +Thats it! The axis coordinates, variable name, description, units, etc. +are obtained from variable sample. + +What if the units are not explicitly defined for ``clt``, or a different +description is desired? ``plot`` has a number of other keywords which +fill in the extra plot information. + +5.2.2 Example: using aplot keywords. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> sample = clt[0,:] + >>> w=vcs.init() + >>> w.plot(sample, units='percent', file_comment='', long_name="Total Cloud", comment1="Example plot", hms="00:00:00", ymd="1979/01/01") + + >>> f.close() + + +**Note:** Keyword arguments can be listed in any order. + +5.2.3 Example: plotting a time-latitude slice +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``, +this example selects and plots a time-latitude slice: + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> samp = clt[:,:,0] + >>> w = vcs.init() + >>> w.plot(samp, name='Total Cloudiness') + + +.. csv-table:: LineNotes + :header: "Line", "Notes" + :widths: 10, 90 + + "4", "``samp`` is a slice of ``clt``, at index ``0`` of the last dimension. Since ``samp`` was obtained from the slice operator, it is a transient variable, which includes the latitude and time information." + "6", "The ``name`` keyword defines the identifier, default is the name found in the file." + +5.2.4 Example: plotting subsetted data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Calling the variable ``clt`` as a function reads a subset of the +variable. The result variable ``samp`` can be plotted directly: + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> samp = clt(time = (0.0,100.0), longitude = 180.0, squeeze=1) + >>> w = vcs.init() + >>> w.plot(samp) + + >>> f.close() + + +5.3 ``plot`` method +~~~~~~~~~~~~~~~~~~~ + +The ``plot`` method is documented in the UV-CDAT Reference Manual. This +section augments the documentation with a description of the optional +keyword arguments. The general form of the plot command is: + +``canvas.plot(array [, args] [,key=value [, key=value [, ...] ] ])`` + +where: + +- canvas is a VCS Canvas object, created with the vcs.init method. + +- array is a variable, masked array, or Numeric array having between + two and five dimensions. The last dimensions of the array is termed + the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', + and 'w'. For example, if array is three-dimensional, the axes are + (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). + (Note that the t dimension need have no connection with time; any + spatial axis can be mapped to any plot dimension. For a graphics + method which is two-dimensional, such as boxfill, the y-axis is + plotted on the horizontal, and the x-axis on the vertical. + + If array is a gridded variable on a rectangular grid, the plot + function uses a box-fill graphics method. If it is non-rectangular, + the meshfill graphics method is used. + + Note that some plot keywords apply only to rectangular grids only. + +- args are optional positional arguments: + + ``args`` := template\_name, graphics\_method, graphics\_name + + ``template_name``: the name of the VCS template (e.g., 'AMIP') + + ``graphics_method``: the VCS graphics method (boxfill) + + ``graphics_name``: the name of the specific graphics method + ('default') + + See the UV-CDAT Reference Manual and VCS Reference Manual for a + detailed description of these arguments. + +- ``key=value``, ... are optional keyword/value pairs, listed in any + order. These are defined in the table below. + + +.. csv-table:: "plot keywords" + :header: "Key", "Type", "Value" + :widths: 20, 20, 80 + + "``comment1``", "string", "Comment plotted above ``file_comment``" + "``comment2``", "string", "Comment plotted above ``comment1``" + "``comment3``", "string", "Comment plotted above ``comment2``" + "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if ``xaxis`` is longitude, ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" + "``file_comment``", "string", "Comment, defaults to ``variable.parent.comment``" + "``grid``", "CDMS grid object", "Grid associated with the data. Defaults to ``variable.getGrid()``" + "``hms``", "string", "Hour, minute, second" + "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." + "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" + "``name``", "string", "Variable name, defaults to `variable.id``" + "``time``", "cdtime relative or absolute", "Time associated with the data." + ,,"Example:" + ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" + "``units``", "string", "Data units. Defaults to ``variable.units``" + "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." + "``xarray`` (``[y|z|t|w]array``)", "1-D Numeric array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to xaxis[:\] (y|z|t|waxis[:])" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" + "``xbounds`` (``ybounds``)", "2-D Numeric array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." + + "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the x-axis (y-axis). Defaults to 0, with the following exceptions:" + ,,"- If the y-axis is latitude, and has decreasing values, ``yrev`` defaults to 1" + ,,"- If the y-axis is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." + + "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." + diff --git a/docs/source/manual/images/cdms_classes.jpg b/docs/source/manual/images/cdms_classes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8084dd72a7ed675c935c7ed1b418963e9616d8c0 GIT binary patch literal 79617 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 M&%gRD!f#go9Z)Ykwg3PC literal 0 HcmV?d00001 From dcbdfdc3f494d2686e052a2abc95dd3cf7206979 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Oct 2017 17:29:45 -0700 Subject: [PATCH 023/239] add chapter 6 --- docs/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/index.rst b/docs/source/index.rst index 7af76293..fec557bd 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,6 +14,7 @@ Contents: manual/cdms_3 manual/cdms_4 manual/cdms_5 + manual/cdms_6 # AbstractAxis # AbstractVariable From 85c05daf747a2393faacf5a408ff50a744b383b4 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 25 Oct 2017 16:33:29 -0700 Subject: [PATCH 024/239] cdms chapter 6 --- docs/source/manual/cdms_6.rst | 1789 +++++++++++++++++++++++++++++++++ 1 file changed, 1789 insertions(+) create mode 100644 docs/source/manual/cdms_6.rst diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst new file mode 100644 index 00000000..735d1e31 --- /dev/null +++ b/docs/source/manual/cdms_6.rst @@ -0,0 +1,1789 @@ +CHAPTER 6 Climate Data Markup Language (CDML) +--------------------------------------------- + +6.1 Introduction +~~~~~~~~~~~~~~~~ + +The Climate Data Markup Language (CDML) is the markup language used to +represent metadata in CDMS. CDML is based on the W3C XML standard +(http://www.w3.org). This chapter defines the syntax of CDML. Read this +section if you will be building or maintaining a CDMS database. + +XML, the eXtensible Markup Language, makes it possible to define +interoperable dialects of markup languages. The most recent version of +HTML, the Web hypertext markup language, is an XML dialect. CDML is also +an XML dialect, geared toward the representation of gridded climate +datasets. XML provides rigor to the metadata representation, ensuring +that applications can access it correctly. XML also deals with +internationalization issues, and holds forth the promise that utilities +for browsing, editing, and other common tasks will be available in the +future. + +CDML files have the file extension .xml or .cdml. + +6.2 Elements +~~~~~~~~~~~~ + +A CDML document consists of a nested collection of elements. An element +is a description of the metadata associated with a CDMS object. The form +of an element is: + +`` element-content `` + +or + +```` + +where + +- ``tag`` is a string which defines the type of element +- ``attribute-list`` is a blank-separated list of attribute-value + pairs, of the form: + + ``attribute = "value"`` +- ``element-content`` depends on the type of element. It is either a + list of elements, or text which defines the element values. For + example, the content of an axis element either is a list of axis + values, or is a linear element. For datasets, the content is the + blank-separated list of elements corresponding to the axes, grids, + and variables contained in the dataset. + +The CDML elements are: + +Table 6.1 CDML Tags + + ++------------+---------------------------------------+ +| Tag | Description | ++============+=======================================+ +| attr | Extra attribute | ++------------+---------------------------------------+ +| axis | Coordinate axis | ++------------+---------------------------------------+ +| domain | Axes on which a variable is defined | ++------------+---------------------------------------+ +| domElem | Element of a variable domain | ++------------+---------------------------------------+ +| linear | Linearly-spaced axis values | ++------------+---------------------------------------+ +| rectGrid | Rectilinear Grid | ++------------+---------------------------------------+ +| variable | Variable | ++------------+---------------------------------------+ + +6.3 Special Characters +~~~~~~~~~~~~~~~~~~~~~~ + +XML reserves certain characters for markup. If they appear as content, +they must be encoded to avoid confusion with markup: + +Table 6.2 Special Character Encodings + + ++-------------+------------+ +| Character | Encoding | ++=============+============+ +| < | < | ++-------------+------------+ +| > | > | ++-------------+------------+ +| & | & | ++-------------+------------+ +| “ | " | ++-------------+------------+ +| ‘ | ' | ++-------------+------------+ + +For example, the comment + +**Certain "special characters", such as <, >, and ', must be encoded.** + +would appear in an attribute string as: + +**comment = "Certain "special characters", such as <, >, and ', must be encoded."** + +6.4 Identifiers +~~~~~~~~~~~~~~~ + +In CDMS, all objects in a dataset have a unique string identifier. The +id attribute holds the value of this identifier. If the variable, axis, +or grid has a string name within a data file, then the id attribute +ordinarily has this value. Alternatively, the name of the object in a +data file can be stored in the name_in_file attribute, which can +differ from the id. Datasets also have IDs, which can be used within a +larger context (databases). + +An identifer must start with an alphabetic character (upper or lower +case), an underscore (_), or a colon (:). Characters after the first +must be alphanumeric, an underscore, or colon. There is no restriction +on the length of an identifier. + +6.5 CF Metadata Standard +~~~~~~~~~~~~~~~~~~~~~~~~ + +`The CF metadata standard `__ defines a set +of conventions for usage of netCDF. This standard is supported by CDML. +The document defines names and usage for metadata attributes. CF +supersedes the GDT 1.3 standard. + +6.6 CDML Syntax +~~~~~~~~~~~~~~~ + +The following notation is used in this section: + +- A ``monospaced block`` is used for a syntax specification. +- **Bold** text indicates literals. +- (R|S) denotes either R or S. +- R* denotes zero or more R. +- R+ denotes one or more R. + +A CDML document consists of a prolog followed by a single dataset +element. + +``CDML-document ::= prolog dataset-element`` + +The prolog defines the XML version, and the Document Type Definition +(DTD), a formal specification of the document syntax. +See http://www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML + +Version 1.0. + +``prolog ::= `` + +6.6.1 Dataset Element +^^^^^^^^^^^^^^^^^^^^^ + +A dataset element describes a single dataset. The content is a list of +elements corresponding to the axes, grids, and variables contained in +the dataset. Axis, variable, and grid elements can be listed in any +order, and an element ID can be used before the element is actually +defined. + +``dataset-element ::=`` ** dataset-content`` **** + +``dataset-content ::= (axis-element | grid-element | variable-element)* extra-attribute-element+`` + +Table 6.3 Dataset Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. csv-table:: + :header: "Attribute", "Required", "CF", "GDT", "Notes" + :widths: 10,5,5,5,80 + + "appendices", "N", "N", "Y", "Version number" + "calendar", "N", "N", "Y", "Calendar used for encoding time axes." + ,,,,"``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard``" + ,,,,"Note: for the CF convention, the calendar attribute is placed on the time axis." + "comment", "N", "Y", "Y", "Additional dataset information" + "conventions", "Y", "Y", "Y", "The netCDF metadata standard. Example: 'CF-1.0'" + "cdms_filemap", "Y", "N", "N", "Map of partitioned axes to files. See note below." + "directory", "N", "N", "N", "Root directory of the dataset" + "frequency", "N", "N", "N", "Temporal frequency" + "history", "N", "Y", "Y", "Evolution of the data" + "id", "Y", "N", "N", "Dataset identifier" + "institution", "N", "Y", "Y", "Who made or supplied the data" + "production", "N", "N", "Y", "How the data was produced (see source)" + "project", "N", "N", "N", "Project associated with the data Example: 'CMIP 2'" + "references", "N", "Y", "N", "Published or web-based references that describe the data or methods used to produce it" + "source", "N", "Y", "N", "The method of production of the original data." + "template", "N", "N", "N", "Filename template. This is an alternate mechanism, other than cdms_filemap, for describing the file mapping. See ‘cdimport -h’ for details." + "title", "N", "Y", "N", "A succinct description of the data." + + +**Notes:** + +The ``cdms_filemap`` attribute describes how the dataset is partitioned +into files. The format is: + +* ``filemap ::= [ varmap, varmap, ...]`` + +* ``varmap ::= [ namelist, slicelist ]`` + +* ``namelist ::= [ name, name, ... ]`` + +* ``slicelist ::= [ indexlist, indexlist, ,,, ]`` + +* ``indexlist ::= [ time0, time1, lev0, lev1, path ]`` + +* ``name ::= variable name`` + +* ``time0 ::= first index of time in the file, or '-' if not split on time`` + +* ``time1 ::= last index of time + 1, in the file, or '-' if not split on time`` + +* ``lev0 ::= first index of vertical levels in the file, or '-' if not split on level`` + +* ``lev1 ::= last index +1 of vertical levels in the file, or '-' if not split on level`` + +* ``path ::= pathname of the file containing data for this time/level range.`` + +The pathname is appended to the value of the directory attribute, to +obtain an absolute pathname. + +6.6.2 Axis Element +^^^^^^^^^^^^^^^^^^ + +An axis element describes a single coordinate axis. The content can be a +blank-separated list of axis values or a linear element. A linear +element is a representation of a linearly-spaced axis as (start, delta, +length). + +``axis-element ::=`` ** axis-content`` **** + +``axis-content ::= (axis-values | linear-element) extra-attribute-element*`` + +``axis-values ::= [value*]`` + +``linear-element ::=`` ** ** + +Table 6.4 +^^^^^^^^^ + +.. csv-table:: + :header: "Attribute", "Required?", "CF", "GDT", "Notes" + :widths: 15,1,1,1,80 + + "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates." + "``axis``", "N", "Y", "Y", "The spatial type of the axis:" + ,,,,"- 'T' - time" + ,,,,"- 'X' - longitude" + ,,,,"- 'Y' - latitude" + ,,,,"- 'Z' - vertical level" + ,,,,"- '-' - not spatiotemporal" + "``bounds``", "N", "Y", "Y", "ID of the boundary variable" + "``calendar``", "N", "Y", "N", "See dataset.calendar" + "``climatology``", "N", "Y", "N", "Range of dates to which climatological statistics apply." + "``comment``", "N", "Y", "N", "String comment" + "``compress``", "N", "Y", "Y", "Dimensions which have been compressed by gathering" + "``datatype``", "Y", "N", "N", "Char, Short, Long, Float, Double, or String" + "``dates``", "N", "Y", "N", "Range of dates to which statistics for a typical diurnal cycle apply." + "``expand``", "N", "N", "Y", "Coordinates prior to contraction" + "``formula_terms``", "N", "Y", "N", "Variables that correspond to the terms in a formula." + "``id``", "Y", "N", "N", "Axis identifier. Also the name of the axis in the underlying file(s), if name_in_file is undefined." + "``isvar``", "N", "N", "N", "* 'true' | 'false'" + ,,,,"- 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s)." + ,,,,"- Default: 'true'" + "``leap_month``", "N", "Y", "N", "For a user-defined calendar, the month which is lengthened by a day in leap years." + "``leap_year``", "N", "Y", "N", "An example of a leap year for a user-defined calendar. All years that differ from this year by a multiple of four are leap years." + "``length``", "N", "N", "N", "Number of axis values, including values for which no data is defined. Cf. partition_length." + "``long_name``", "N", "Y", "Y", "Long description of a physical quantity" + "``modulo``", "N", "N", "Y", "Arithmetic modulo of an axis with circular topology." + "``month_lengths``", "N", "Y", "N", "Length of each month in a non-leap year for a user-defined calendar." + "``name_in_file``", "N", "N", "N", "Name of the axis in the underlying file(s). See id." + "``partition``", "N", "N", "N", "How the axis is split across files." + "``partition_lengt h``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." + "``positive``", "N", "Y", "Y", "Direction of positive for a vertical axis" + "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." + "``topology``", "N", "N", "Y", "- Axis topology." + ,,,,"- 'circular' | 'linear'" + "``units``", "Y", "Y", "Y", "Units of a physical quantity" + "``weights``", "N", "N", "N", "Name of the weights array" + +6.6.3 partition attribute +^^^^^^^^^^^^^^^^^^^^^^^^^ + + +For an axis in a dataset, the .partition attribute describes how an axis +is split across files. It is a list of the start and end indices of each +axis partition. + +FIGURE 4. Partitioned axis + + +.. figure:: /images/timeLine.jpg + :alt: + +For example, Figure 4 shows a time axis, representing the 36 months, +January 1980 through December 1982, with December 1981 missing. The +first partition interval is (0,12), the second is (12,23), and the third +is (24,36), where the interval (i,j) represents all indices k such that +i <= k < j. The .partition attribute for this axis would be the list: + +``[0, 12, 12, 23, 24, 36]`` + +Note that the end index of the second interval is strictly less than the +start index of the following interval. This indicates that data for that +period is missing. + +6.6.4 Grid Element +^^^^^^^^^^^^^^^^^^ + +A grid element describes a horizontal, latitude-longitude grid which is +rectilinear in topology, + +``grid-element ::=`` **** +``extra-attribute-element*`` **** + +Table 6.5 RectGrid Attributes + + +.. raw:: html + + + +:: + + + +.. raw:: html + + + +:: + + + + + + + + +.. raw:: html + +
Attribute Required? GDT? Notes
idYNGrid identifier
typeYN

Grid classification

"gaussian" | "uniform" | "equalarea" |"generic"

Default: "generic"

latitudeYNLatitude axis name
longitudeYNLongitude axis name
maskNNName of associated mask variable
orderYN

Grid ordering "yx" | "xy"

Default: “yx”, axis order is latitude, longitude

+ +6.6.5 Variable Element +^^^^^^^^^^^^^^^^^^^^^^ + +A variable element describes a data variable. The domain of the variable +is an ordered list of domain elements naming the axes on which the +variable is defined. A domain element is a reference to an axis or grid +in the dataset. + +The length of a domain element is the number of axis points for which +data can be retrieved. The partition\_length is the number of points for +which data is actually defined. If data is missing, this is less than +the length. + +``variable-element ::=`` **** +``variable-content`` **** + +``variable-content ::=`` variable-domain extra-attributeelement\*\` + +``variable-domain ::=`` **** ``domain-element*`` **** + +``domain-element ::=`` **\*\* + +Table 6.6 Variable Attributes + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Attribute + +.. raw:: html + + + +Required? + +.. raw:: html + + + +CF + +.. raw:: html + + + +GDT + +.. raw:: html + + + +Notes + +.. raw:: html + +
+ +id + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Variable identifier. Also, the name of the variable in the underlying +file(s), if name\_in\_file is undefined. + +.. raw:: html + +
+ +add\_offset + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Additive offset for packing data. See scale\_factor. + +.. raw:: html + +
+ +associate + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +IDs of variables containing alternative sets of coordinates + +.. raw:: html + +
+ +axis + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +.. raw:: html + +

+ +Spatio-temporal dimensions. + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: "TYX" for a variable with domain (time, latitude, longitude) + +.. raw:: html + +

+ +.. raw:: html + +

+ +Note: for CF, applies to axes only. + +.. raw:: html + +

+ +.. raw:: html + +
+ +cell\_methods + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +The method used to derive data that represents cell values, e.g., +"maximum", "mean", "variance", etc. + +.. raw:: html + +
+ +comments + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Comment string + +.. raw:: html + +
+ +coordinates + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +IDs of variables containing coordinate data. + +.. raw:: html + +
+ +datatype + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Char, Short, Long, Float, Double, or String + +.. raw:: html + +
+ +grid\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Id of the grid + +.. raw:: html + +
+ +grid\_type + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +"gaussian" \| "uniform" \| "equalarea" \| "generic" + +.. raw:: html + +
+ +long\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Long description of a physical quantity. + +.. raw:: html + +
+ +missing\_value + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Value used for data that are unknown or missint. + +.. raw:: html + +
+ +name\_in\_file + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the variable in the underlying file(s). See id. + +.. raw:: html + +
+ +scale\_factor + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Multiplicative factor for packing data. See add\_offset. + +.. raw:: html + +
+ +standard\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +Reference to an entry in the standard name table. + +.. raw:: html + +
+ +subgrid + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Records how data values represent subgrid variation. + +.. raw:: html + +
+ +template + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the file template to use for this variable. Overrides the +dataset value. + +.. raw:: html + +
+ +units + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Units of a physical quantity. + +.. raw:: html + +
+ +valid\_max + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest valid value of a variable + +.. raw:: html + +
+ +valid\_min + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Smallest valid value of a variable + +.. raw:: html + +
+ +valid\_range + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest and smallest valid values of a variable + +.. raw:: html + +
+ +6.6.6 Attribute Element +^^^^^^^^^^^^^^^^^^^^^^^ + +Attributes which are not explicitly defined by the GDT convention are +represented as extra attribute elements. Any dataset, axis, grid, or +variable element can have an extra attribute as part of its content. +This representation is also useful if the attribute value has non-blank +whitespace characters (carriage returns, tabs, linefeeds) which are +significant. + +The datatype is one of: **Char**, **Short**, **Long**, **Float**, +**Double**, or **String**. + +``extra-attribute-element ::=`` **** ``attribute-value`` +**** + +6.7 A Sample CDML Document +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataset "sample" has two variables, and six axes. + +**Note:** + +- The file is indented for readability. This is not required; the added + whitespace is ignored. +- The dataset contains three axes and two variables. Variables u and v + are functions of time, latitude, and longitude. +- The global attribute cdms\_filemap describes the mapping between + variables and files. The entry + ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` + indicates that variable ``u`` is contained in file u\_2000.nc for + time index 0, u\_2001.nc for time index 1, etc. + +{% highlight xml %} + +.. raw:: html + + + +.. raw:: html + + + + [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] + +:: + + + + [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. + + 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 + + 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 + + 303.75 315. 326.25 337.5 348.75] + + + + + [ 0. 366. 731.] + + + + + + + + + + + + + + + + + + + {% endhighlight %} From 0783e17be92cf4fb9fbbac65d440c974679424e7 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 31 Oct 2017 15:16:07 -0700 Subject: [PATCH 025/239] fix TOC --- docs/source/index.rst | 1 + docs/source/manual/cdms_1.rst | 15 ++-- docs/source/manual/cdms_2.rst | 131 +--------------------------------- docs/source/manual/cdms_3.rst | 11 +-- docs/source/manual/cdms_4.rst | 26 ++++--- docs/source/manual/cdms_5.rst | 4 ++ docs/source/manual/cdms_6.rst | 4 ++ 7 files changed, 40 insertions(+), 152 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index fec557bd..356f74bd 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -15,6 +15,7 @@ Contents: manual/cdms_4 manual/cdms_5 manual/cdms_6 + manual/cdms_7 # AbstractAxis # AbstractVariable diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 73d7f24e..4b73df67 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -2,7 +2,6 @@ CHAPTER 1 --------- CHAPTER 1 Introduction -~~~~~~~~~~~~~~~~~~~~~~ 1.1 Overview ^^^^^^^^^^^^ @@ -834,13 +833,13 @@ distributed computing environment. At present CDMS supports one particular type of database, based on the Lightweight Directory Access Protocol (LDAP). -Here is an example of accessing data via a database: +.. Here is an example of accessing data via a database: -#.. doctest:: -# -# >>> db = cdms.connect() # Connect to the default database. -# >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. -# >>> f.variables.keys() # List the variables in the dataset. -# ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] +.. .. doctest:: + +.. >>> db = cdms.connect() # Connect to the default database. +.. >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. +.. >>> f.variables.keys() # List the variables in the dataset. +.. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index b6ca3763..b42df836 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -3,6 +3,7 @@ CHAPTER 2 CDMS Python Application Programming Interface 2.1 Overview ^^^^^^^^^^^^ + .. testsetup:: * import requests @@ -3574,7 +3575,7 @@ remove the singleton level dimension from the result array. 2.12.1 Example 1 ----------------- +^^^^^^^^^^^^^^^^ In this example, two datasets are opened, containing surface air temperature (‘tas’) and upper-air temperature (‘ta’) respectively. @@ -3675,7 +3676,7 @@ results are written to a netCDF file. For brevity, the functions 2.12.2 Example 2 ----------------- +^^^^^^^^^^^^^^^^ In the next example, the pointwise variance of a variable over time is calculated, for all times in a dataset. The name of the dataset and @@ -3814,132 +3815,6 @@ The result of running this script is as follows: information are carried with the computations, so the continents are plotted correctly. -.. raw:: html - -
- -`Previous `__ `Table of -Contents `__ -`Next `__ - -.. raw:: html - -
- -.. raw:: html - - - -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- -Project Information - -- `Mission `__ -- `Governance `__ -- `Acknowledgements `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Contribute -^^^^^^^^^^ - -- `GitHub Project Page `__ -- `Wiki `__ -- `Report a Bug `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Press -^^^^^ - -- `Presentations `__ -- `Publications `__ -- `Reports `__ - -.. raw:: html - -
- -.. raw:: html - -
- -Info -^^^^ - -- `Animations `__ -- `Design Documents `__ -- `Use Cases `__ - -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- --------------- - -.. raw:: html - - - -.. raw:: html -
-.. |image0| image:: /images/uvcdat.png - :class: logo - :target: / -.. |Diagram 1| image:: /images/diagram1.jpg diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 0c965d17..18a9b365 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -100,7 +100,7 @@ The following table describes the methods for creating time types. A relative time type has two members, value and units. Both can be set. Table 3.2 Relative Time Members -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------+---------+-------------------------------------------------------+ | Type | Name | Summary | @@ -190,10 +190,11 @@ Compare time values. >>> c = comptime(1996,2,28) >>> print c.cmp(r) 1 -# >>> print r.cmp(c) -# -1 -# >>> print r.cmp(r) -# 1 + +.. >>> print r.cmp(c) +.. -1 +.. >>> print r.cmp(r) +.. 1 Subtract an interval of time. diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index c2452c72..011d345a 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -1,5 +1,5 @@ CHAPTER 4 Regridding Data -^^^^^^^^^^^^^^^^^^^^^^^^^ +------------------------- 4.1 Overview ^^^^^^^^^^^^ @@ -86,7 +86,7 @@ is generated at line 9, and the regridding is performed at line 10: Notes ------ +~~~~~ **Line #3** Makes the CDMS module available. @@ -309,7 +309,7 @@ instance of Regridder is a function which regrids data from rectangular input to output grids. Table 4.1 CDMS Regridder Constructor ------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: REgridder Constructure :header: "Constructor", "Description" @@ -324,7 +324,7 @@ SCRIP regridder functions are created with the ``regrid.readRegridder`` function: Table 4.2 SCRIP Regridder Constructor -------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" @@ -363,7 +363,7 @@ missing data, or the input and/or output grids are masked, the logic becomes more complicated. Step 1 ------- +~~~~~~ The regridder function first forms an input mask. This mask is either two-dimensional or n-dimensional, depending on the rank of the @@ -385,7 +385,7 @@ is obtained from the data array mask if present. input array, it is used as the input mask. Step 2 ------- +~~~~~~ The data is then regridded. In the two-dimensional case, the input mask is ‘broadcast’ across the other dimensions of the array. In other words, @@ -397,7 +397,7 @@ overlaps a non-missing input grid cell. This is useful for calculating area-weighted means of masked data. Step 3 ------- +~~~~~~ Finally, if the output grid has a mask, it is applied to the result array. Where the output mask is 0, data values are set to the missing @@ -406,7 +406,7 @@ variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values Table 4.3 CDMS Regridder function -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Function", "Description" @@ -466,7 +466,7 @@ In addition, a conservative regridder has the associated grid cell areas for source and target grids. Table 4.4 SCRIP Regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Return Type | Method | Description | @@ -492,7 +492,7 @@ Table 4.4 SCRIP Regridder functions ^^^^^^^^^^^^ 4.4.1 CDMS regridder -^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~ **Example:** @@ -641,7 +641,7 @@ of the result. +--------+----------------------------------------------------------------------------------------------------------+ 4.4.2 SCRIP regridder -^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~ **Example:** @@ -680,3 +680,7 @@ comparison. >>> fremap.close() >>> fdat.close() + + + +a diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 2e269ac5..0da06c4f 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -204,3 +204,7 @@ where: "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." + + + +b diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 735d1e31..98fe67d5 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -1787,3 +1787,7 @@ Dataset "sample" has two variables, and six axes. {% endhighlight %} + + + + c From 55e419c8bb2857b34ec7bdb0e4ce04cd2ba7a391 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 31 Oct 2017 17:47:53 -0700 Subject: [PATCH 026/239] add chapter 7 and appendix --- .../{manual => }/images/cdms_classes.jpg | Bin docs/source/{manual => }/images/diagram1.jpg | Bin docs/source/images/timeLine.jpg | Bin 0 -> 13754 bytes docs/source/index.rst | 1 + docs/source/manual/cdms_7.rst | 165 ++++++++++++ docs/source/manual/cdms_appendix.rst | 251 ++++++++++++++++++ .../manual/images/curvilinear_grid.jpg | Bin 0 -> 105315 bytes docs/source2/manual/images/generic_grid.jpg | Bin 0 -> 86702 bytes 8 files changed, 417 insertions(+) rename docs/source/{manual => }/images/cdms_classes.jpg (100%) rename docs/source/{manual => }/images/diagram1.jpg (100%) create mode 100644 docs/source/images/timeLine.jpg create mode 100644 docs/source/manual/cdms_7.rst create mode 100644 docs/source/manual/cdms_appendix.rst create mode 100644 docs/source2/manual/images/curvilinear_grid.jpg create mode 100755 docs/source2/manual/images/generic_grid.jpg diff --git a/docs/source/manual/images/cdms_classes.jpg b/docs/source/images/cdms_classes.jpg similarity index 100% rename from docs/source/manual/images/cdms_classes.jpg rename to docs/source/images/cdms_classes.jpg diff --git a/docs/source/manual/images/diagram1.jpg b/docs/source/images/diagram1.jpg similarity index 100% rename from docs/source/manual/images/diagram1.jpg rename to docs/source/images/diagram1.jpg diff --git a/docs/source/images/timeLine.jpg b/docs/source/images/timeLine.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5fa81e42340adc7be959acee12b27f76311e728 GIT binary patch literal 13754 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 literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index 356f74bd..860cd577 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -16,6 +16,7 @@ Contents: manual/cdms_5 manual/cdms_6 manual/cdms_7 + manual/cdms_appendix # AbstractAxis # AbstractVariable diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst new file mode 100644 index 00000000..ca533760 --- /dev/null +++ b/docs/source/manual/cdms_7.rst @@ -0,0 +1,165 @@ +CHAPTER 7 CDMS Utilities +------------------------ + +7.1 ``cdscan``: Importing datasets into CDMS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +7.1.1 Overview +^^^^^^^^^^^^^^ + +A dataset is a partitioned collection of files. To create a dataset, the +files must be scanned to produce a text representation of the dataset. +CDMS represents datasets as an ASCII metafile in the CDML markup +language. The file contains all metadata, together with information +describing how the dataset is partitioned into files. (Note: CDMS +provides a direct interface to individual files as well. It is not +necessary to scan an individual file in order to access it.) + +For CDMS applications to work correctly, it is important that the CDML +metafile be valid. The ``cdscan`` utility generates a metafile from a +collection of data files. + +CDMS assumes that there is some regularity in how datasets are +partitioned: + +- A variable can be partitioned (split across files) in at most two + dimensions. The partitioned dimension(s) must be either time or + vertical level dimensions; variables may not be partitioned across + longitude or latitude. Datasets can be parti-tioned by variable as + well. For example, one set of files might contain heat fluxes, while + another set contains wind speeds. + +Otherwise, there is considerable flexibility in how a dataset can be +partitioned: + +- Files can contain a single variable or all variables in the dataset. +- The time axis can have gaps. +- Horizontal grid boundary information and related information can be + duplicated across files. +- Variables can be on different grids. +- Files may be in any of the self-describing formats supported by CDMS, + including netCDF, HDF, GrADS/GRIB, and DRS. + +7.1.2 ``cdscan`` Syntax +^^^^^^^^^^^^^^^^^^^^^^^ + +The syntax of the ``cdscan`` command is + + - cdscan [options] file1 file2 ... + +or + + - cdscan [options] -f file_list + +where + +- ``file1 file2 ...`` is a blank-separated list of files to scan +- ``file_list`` is the name of a file containing a list of files to + scan, one pathname per line. + +Output is written to standard output by default. Use the -x option to +specify an output filename. + +Table 7.1 cdscan command options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Option:, "Description" + :widths: 20, 80 + + "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. ``variable_id`` is the ID of the variable in the file, and ``alias`` is the name that will be substituted for it in the output dataset. Only variables with entries in the ``alias_file`` are renamed." + "``-c calendar``", "Specify the dataset calendar attribute. One of:" + , "- gregorian (default)" + , "- julian" + , "- noleap" + , "- proleptic_gregorian" + , "- standard" + , "- 360_day" + "``-d dataset_id``", "String identifier of the dataset. Should not contain blanks or non-printing characters. Default: 'None'" + "``-e newattr``", "Add or modify attributes of a file, variable, or axis." + ,"- The form of ``newattr`` is either:" + ," - ``var.attr = value`` to modify a variable or attribute, or" + ," - ``.attr = value`` to modify a global (file) attribute. In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." + "``--exclude var,var,...``", "Exclude specified variables. The argument is a comma-separated list of variables containing no blanks. Also see ``--include``." + "``-f file_list``", "File containing a list of absolute data file names, one per line." + "``-h``", "Print a help message." + "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. ``time_delta`` is a float or integer. For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." + "``--include var,var,...``", "Only include specified variables in the output. The argument is a comma-separated list of variables containing no blanks. Also see ``--exclude``." + "``-j``", "Scan time as a vector dimension. Time values are listed individually." + ,"- **Note:** Turns off the -i option." + "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." + "``-m levelid``", "Name of the vertical level dimension. The default is the vertical dimension as determined by CDMS. See Note 3." + "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. ``cdimport -h`` describes template strings." + "``-q``", "Quiet mode." + "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." + "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. Each line consists of two blank-separated fields: ``directory suffix``. Each file path is compared to the directories in the suffix file. If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. If more than one such directory is found, the first directory found is used. If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." + "``-t timeid``", "ID of the partitioned time dimension. The default is the name of the time dimension as determined by CDMS. See Note 1." + "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list:" + , "- zero is the initial time point, a floating-point value." + , "- delta is the time delta, floating-point." + , "- units are time units as specified in the [-r] option." + , "- calendar is optional, and is specified as in the [-c] option." + , "If omitted, it defaults to the value specified by [-c], otherwise as specified in the file." + , "**Example:** ``--time-linear '0,1,months since 1980,noleap'``" + "``-x xmlfile``", "Output file name. By default, output is written to standard output." + +**Notes:** + +- Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. + + +- By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. + +- Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. + +- Adding or modifying attributes with the -e option: + - time.units = "days since 1979-1-1" + +- sets the units of all variables/axes to "days since 1979-1-1". Note that since this is done before any other processing is done, it allows overriding of non-COARDS time units. + - .newattr=newvalue + +- Set the global file attribute 'newattr' to 'newvalue'. + +- The ``[--time-linear]`` option overrides the time values in the file(s). The resulting dimension does not have any gaps. In contrast, the ``[-i]``, ``[-r]`` options use the specified time units (from ``[-r]``), and calendar from ``[-c]`` if specified, to convert the file times to the new units. The resulting linear dimension may have gaps. + - In either case, the files are ordered by the time values in the files. + - The ``[--time-linear]`` option should be used with caution, as it is applied to all the time dimensions found. + + +7.1.3 Examples +^^^^^^^^^^^^^^ + +- cdscan -c noleap -d test -x test.xml [uv]\*.nc +- cdscan -d pcmdi\_6h -i 0.25 -r 'days since 1979-1-1' *6h*.ctl + +7.1.4 File Formats +^^^^^^^^^^^^^^^^^^ + +Data may be represented in a variety of self-describing binary file +formats, including + +- netCDF, the Unidata Network Common Data Format +- HDF, the NCSA Hierarchical Data Format +- GrADS/GRIB, WMO GRIB plus a GrADS control file (.ctl) The first + non-comment line of the control file must be a dset specification. +- DRS, the PCMDI legacy format. + +7.1.5 Name Aliasing +^^^^^^^^^^^^^^^^^^^ + +A problem can occur if variables in different files are defined on +different grids. What if the axis names are the same? CDMS requires that +within a dataset, axis and variable IDs (names) be unique. What should +the longitude axes be named in CDMS to ensure uniqueness? The answer is +to allow CDMS IDs to differ from file names. + +If a variable or axis has a CDMS ID which differs from its name in the +file, it is said to have an alias. The actual name of the object in the +file is stored in the attribute ``name_in_file``. ``cdscan`` uses this +mechanism (with the ``-a`` and ``s`` options) to resolve name conflicts; +a new axis or variable ID is generated, and the ``name_in_file`` is set +to the axis name in the file. + +Name aliases also can be used to enforce naming standards. For data +received from an outside organization, variable names may not be +recognized by existing applications. Often it is simpler and safer to +add an alias to the metafile rather than rewrite the data diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst new file mode 100644 index 00000000..70e4c29e --- /dev/null +++ b/docs/source/manual/cdms_appendix.rst @@ -0,0 +1,251 @@ +APPENDIX A +---------- + +CDMS Classes +~~~~~~~~~~~~ + +Figure 1, "CDMS Classes", on page 175 illustrates the class inheritance +structure of CDMS. The classes may be categorized as abstract or +concrete. Only concrete classes are meant to be used directly. In +contrast an abstract class defines the common interface of its +subclasses. For example, the class AbstractAxis2D defines the common +interface for two-dimensional coordinate axes. It has concrete +subclasses DatasetAxis2D, FileAxis2D, and TransientAxis2D, which are +used in applications. Abstract classes are denoted in italics. + +For many abstract classes there are three 'flavors' of subclass: +dataset, file, and transient. Dataset-related objects are thought of as +being contained in datasets in the sense that operations on those +objects result in I/O operations on the corresponding dataset. The same +is true of file-related objects. Objects in datasets and files are +examples of persistent objects, whose state persists after the +application exits. On the other hand, transient objects live in memory +and are not persistent. + +In general the concrete subclasses closely mirror the interface of the +abstract parent class. For this reason this document defines the +interfaces of the abstract classes, and only discusses a concrete class +in the few cases where the interface has been extended. This allows +applications to treat the behavior of, say a dataset axis and file axis, +as identical. + +.. figure:: /images/cdms_classes.jpg + :alt: + +FIGURE 1. CDMS Classes + + +APPENDIX B +---------- + +Version Notes +~~~~~~~~~~~~~ + +B.1 Version 4.0 +^^^^^^^^^^^^^^^ + +CDMS version 4.0 adds support for nonrectangular grids: + +- The following grid classes were added: AbstractHorizontalGrid, + AbstractCurve-Grid, AbstractGenericGrid, DatasetCurveGrid, + FileCurveGrid, TransientCurve-Grid, DatasetGenericGrid, + FileGenericGrid, and TransientGenericGrid. +- The following axis classes were added: AbstractCoordinateAxis, + AbstractAuxAxis1D, AbstractAxis2D, DatasetAuxAxis1D, FileAuxAxis1D, + TransientAuxAxis1D, DatasetAxis2D, FileAxis2D, and TransientAxis2D. +- The getMesh and clone methods were added for grids. +- An interface to the SCRIP package was added. + +B.2 Version 3.0 Overview +^^^^^^^^^^^^^^^^^^^^^^^^ + +CDMS version 3.0 is a significant enhancement of previous versions. The +major changes were: + +- UV-CDAT/CDMS was integrated with the Numerical Python masked array + class MA.MaskedVariable. The MV submodule was added as a wrapper + around MA. +- Methods that read data, such as subRegion, subSlice, and the slice + operations, return instances of class TransientVariable. The plot and + regrid modules were modified to handle masked array input. The + specifiers time=..., latitude=..., etc. were added to the I/O + routines. +- The class TransientVariable was added. +- A number of new functions were added, notably subRegion and subSlice, + which return instances of TransientVariable. +- When a masked array is returned from a method, it is "squeezed": + singleton dimensions are removed. In contrast, transient variables + are not squeezed. I/O functions have a squeeze option. The method + setAutoReshapeMode was removed. +- Internal attributes are handled in the InternalAttributes class. This + allows CDMS classes to be subclassed more readily. +- The class Variable was renamed DatasetVariable. +- The cu module was emulated in cdms. cu and cdms methods can be mixed. +- The code was modularized, so that Python, CDMS, and Numerical Python + can be built and installed separately. This significantly enhances + the portability of the code. + +B.3 V3.0 Details +^^^^^^^^^^^^^^^^ + +B.3.1 AbstractVariable +'''''''''''''''''''''' + +- Functions getDomain, getSlice, rank, regrid, setMissing, size, + subRegion, and subSlice were added. +- The functions getRegion, getSlice, getValue, and the slice operators + all return an instance of MA, a masked array. Singleton dimensions + are squeezed. +- The functions subRegion and subSlice return an instance of + TransientVariable. Singleton dimensions are not squeezed. +- The xxSlice and xxRegion functions have keywords time, level, + latitude, and longitude. +- The input functions have the keyword squeeze. +- AbstractVariable inherits from class Slab. The following functions + previously available in module cu are Slab methods: getattribute, + setattribute, listdimattributes, getdimattribute, listall, and info. +- AbstractVariable implements arithmetic functions, astype. +- The write function was added. + +B.3.2 AbstractAxis +'''''''''''''''''' + +- The functions asComponentTime, asRelativeTime, clone, getAxisIds, + getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were + added. +- subaxis was renamed subAxis for consistency. +- Generalized wraparound was implemented, to handle multiple cycles, + reversing, and negative strides. By default, coordinate intervals are + closed. The intersection options 'n','e','b',and 's' were added to + the interval indicator - see mapIntervalExt. + +B.3.3 AbstractDatabase +'''''''''''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.4 Dataset +''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.5 cdms module +''''''''''''''''' + +- The functions asVariable, isVariable, and createVariable were added. +- The function setAutoReshapeMode was removed. It is replaced by the + squeeze option for all I/O functions. + +B.3.6 CdmsFile +'''''''''''''' + +- The function createVariable has a keyword fill\_value. The datatype + may be a Numeric/MA typecode. +- The function write was added. + +B.3.7 CDMSError +''''''''''''''' + +- All errors are an instance of the class CDMSError. + +B.3.8 AbstractRectGrid +'''''''''''''''''''''' + +- The function createGaussianGrid was added. + +B.3.9 InternalAttributes +'''''''''''''''''''''''' + +- The class InternalAttributes was added. It has methods + add\_internal\_attribute, is\_internal\_attribute, and + replace\_external\_attributes. + +B.3.10 TransientVariable +'''''''''''''''''''''''' + +- The class TransientVariable was added. It inherits from both + AbstractVariable and MA. +- The cdms module function createVariable returns a transient variable. +- This class does not implement the functions getPaths or getTemplate. + +B.3.11 MV +''''''''' + +- The MV submodule of cdms was added. + +APPENDIX C +---------- + +``cu`` Module +~~~~~~~~~~~~~ + +The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 +it is emulated in the ``cdms`` module. It is maintained for backward +compatibility. + +The ``cu`` classes are ``Slab``, corresponding to ``TransientVariable`` +in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. + +C.1 Slab +~~~~~~~~ + +Table C.1 Slab Methods +^^^^^^^^^^^^^^^^^^^^^^ + + +.. csv-table:: Slab_Methods + :header: "Type","Method","Definition" + :widths: 20,50,80 + + "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device ``. " + "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." + "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." + + + + +C.2 cuDataset +~~~~~~~~~~~~~ + +Table C.2 cuDataset Methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: cuDataset_Methods + :header: "Type", "Method", "Definition" + :widths: 20, 50, 80 + + "None", "cleardefault()", "Clear the default variable name." + "None", "default_variable(vname)", "Set the default variable name." + ,,"vname is the string variable name." + "Array", "dimensionarray(dname, vname=None)", "Values of the axis named dname." + ,,"dname is the string axis name." + ,,"vname is the string variable name. The default is the variable name set by default_variable." + "Axis", "dimensionobject(dname, vname=None)", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." + "Various", "getattribute (vname, attribute)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." + "String", "getdimensionunits (dname,vname=None)", "Get the units for the given dimension." + ,,"dname is the string name of an axis." + ,,"vname is a string variable name. The default is the variable name set by default_variable." + "Various", "getglobal (attribute)", "Get the value of the global attribute. attribute is the string attribute name." + "Variable", "getslab (vname, \*args)", "Read data for a variable." + ,, "vname is the string name of the variable." + ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" + ,, "- ':' or None -- select the entire dimension" + ,, "- Ellipsis -- select entire dimensions between the ones given." + ,, "- a pair of successive arguments giving an interval in world coordinates." + ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" + "List", "listall (vname=None, all=None)", "Get info about data from the file." + ,, "vname is the string name of the variable." + ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" + "List", "listattribute (vname=None )", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "listdimension (vname=None)", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "listglobal ()", "Return a list of the global attribute names." + "List", "listvariable ()", "Return a list of the variables in the file." + "None", "showall (vname=None, all=None, device=sys.stdout)", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "showattribute (vname=None, device=sys.stdout)", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." + "None", "showdimension (vname=None, device=sys.stdout)", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "showglobal (device=sys.stdout)", "Print the global file attributes. Output is sent to device." + "None", "showvariable (device=sys.stdout)", "Print the list of variables in the file." + diff --git a/docs/source2/manual/images/curvilinear_grid.jpg b/docs/source2/manual/images/curvilinear_grid.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f09fe0d64c7b7ec234b2b2e3b798cbf1076535eb GIT binary patch literal 105315 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�U%Xb{X$A!pF{r8%bg_XCA&#c_ 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
x-X8tY$yi~!0O^*-Bexv z&?73}OOi*J5-HSTQ020(3o8j4&NX~0+WlKR`xnzAVe2=2vSSxLN+89%#~{2|2D8Td zsl8(RqRKvR<6N!RC667f2LsRb|_m?ct0=u>%)f7498yf zQQ6=pvNby6{(ZOvxuGTc_m74DMQTG}<>|4$%_)m6)Qg8?Q9?QMo{MDqL?Oml6Y;=o zF)*>+SX}yRrg9FyL@i{CXBV`H)HJ_<3RJ*?zjQnJsNVQK_^UHKEb9WDr$nJU$hDKm zH&@wO7eI+u!i`8HanNh^+y87@{pBWxn_~m(mL&TM#}?$e>2NP71tH#Mw`uj6Lvlrz z^l_!tWdSLb&VZ_gi44rp7B&6K{5%9%s4RY-UlRp7t-izU=8n(VaFeMj+9vng7ao0X zEexGKd~9!nx2QH`x7jFq%pHY{XitcBcTJ8FBsL{@!!>xayFI+PZ5cBa`7mG*3cllR^fM=ql=>(LcurWxVR{a`U<$Fx`;5 zFnO8p%EZMt@p%2RIFbJ#`@O=)*KEgofmnh%)mb}ldlz?gB%dwH=`4}@ylf5(Hv}3=7{MAFLadf?E_@T4~~lH@|_#n7_N4R?7RGD8Yl1?V@GRBM5%go<1J0GE!fLocihFQ-(xESEN(O8hC|7 z2NcMdxE&t6#<$?F!Xekw5RaRuMsR-e%$9uQ4ypgNdrN!z{3DdHmPX_<_=xapxfqL+ zB(9!kiV%%6(XF|Iro`uk{ms&x{+@p&c=xCw zN|ap9V9d%@>KAi5>M%75yIj$Em;3vUDwnI~wr$=TqJlg3!xdTk*I>0wejh7h zoe?fMJ&P+#!L9Rn|8q_COs1A2qCaPQ*L1&pBmab9;|1C_FXwD^FA+E*D&e*Ub=hG` zcjr({?_6DXyT+WIT}yR%y0WqJrsJPpQi-u#xy|GcZP*lHZ0rR*b=h_@a+ratVG7&G zYK{p>du2-DtnJiXS>~8Q(}G@uq;&!Z!ic~7L?lS`NyjYu1I09~gv!I`dh3r0W+@7S51&WMX=MLbrUo)9~0yUV2 zawcv<|A5>a-MAQuQT!1-OlJ{a)0|d#LPE}Zf&LdZ$FTunZQLs%WFC^4_s2fix){H^ zjzM-0kz9w5*gk?FHGq0x?OJN|4oVAuO|BODyuGWPLAy8huLb>0lGbp!Fj@oy7C zEyQeA7T=m|BEui{!RG3$FJWKF{2I=1E%WAalh?4Ti0A|GnqI0jxXy-(#@Q*q@mOre zIrICDOMNM0;OT8G-hRnx`twlm*_8Ys<)f#c40=%f$`S;>cCC0AvQrNUk zykL&JUhD?cf}V|}dji5j@d~u7uwcw^VV5eh8R~Fvc~8W%Ae_ePi+FL6@XYY8ds=la zr{+81z3(cbG%#_zbc(+ml7;Cu$t>{-W1#SAwOZkt-3BeQ02nI~c{RE_?Gww5R`B69 zJz)vKVCiz?tDxqbEBbO1%lvZRRqvIy=)-HC!QMp1a>RmX+0|~e-<~V29W2)3>CaP) zf_&C9V~V(3$(^%a?6>G`FyVSN225J=q4|jINpgPzX-AuUA*+VCEZ?8QYg+u=6B?=+ z(z#<_TlBvg(&3DTm7Ko=)+8CsSu9Qj7>x#BNpfVb3J2e7l*7FTK9@z0v_vB};3`Bd z`z`>9?>=Gyv808s{Bh&n$}%c*PZI2wp&yED-Ku-i?d=6zFiByTE1$N8x*Tu+2N4dX zz3qp0rG^bl@-Nl-@HyN+pd3$|YjPbY#k`~f$3PCitnQ#Wi+9o5C1P`?)g4`8uG9O3 zdeisHRZnvr)2?)6-xYYCf7ey5ux(U4PHtg#2m{7vAI8LpOOg!#mE|Lf8Z0B<;RUnh{8KcHD5oD zmES18-m!Ta95cUmVa8G)@7@fEjhrqIiHM+E5~Jls6ePPuyDx*Lx0n>t5iStC1!w(> zcLoK*^(QmRPi7mACp-LJ9$zm=_(};TGK>1oj)RZ)bLCx!=D|C=k(rf;m!vdPd|v0dabyw9AIBZ?3m0F?~w z@`2)}s=%6czeRSR3yZ^%Pq5I!QD}zHZ>nf+m^aQxh-1_PBJyWDf#8*a06)3{_$88a zW%FA1l)Nm`TbDN5qeJ)fXNR!Y$s3Soz?SKt-JYhh4%}57G1N|LF0k?;5dpB$ zx0yvh{G*9`ZPhNv?#HJGj4vL1s}dgX5-8lgdwKE4Yj>ebkVD%+Q6ZEHhbBnI7A1IN zARbdHX~*O7+BR!HuZins^^v0@7UL;eKE;z6P(OU20E}ta;dyDqm2K6nGhWkxZ|bsT zcS@bUm%N@we?Rpd;g{i#${D-xCq}IcSR_{UccHsQ(^2At41b+9gJrjqMv(yrZoXM`Xv~Lz|;nRiS9FnWEE*5r4^c5lLzk(j}P8| z_R(lmTDTqogq^7X-MGaU%8k01UVgaodtVV-Y+yw%vSn`nJ?d3vyCU8Q#00I~|J6B2 zE|SQP04a>&!|M>>(3KYEK1|_URCbifdaQMBpvw#M-BrgSk#xa#>bY~jT*Ap+3FY*^ zc9SLddHd}RP@s%$4bPHZCjNE+h0x(q4$zx_zu0kjVvpq|DK3O8+w;lL7t%<&rlXQ& zixFY#DCrl`$gt>gHh9?X*mxnLalcICt&RifIilAqt0ivD+mgpFZ(&cD2dRM=`2-@K z`at4{N@il3X(Dgrc}dQ{E#~*`bARHZymHmSg$oxYS+5UH^18yj@RRBO;zVM~?Y2O6 z?6Pl5HzH`&iRIUw&zdnOtHGbQLd|Njr}*kfwy6|l&_}({jAwB;#cgGTYKx4SEZ3*m zoML`4RO2_~1yER4p^hsp$`l3g75_lJ{^l zOmn#L=}@sDJ0e&<#M4-h)$u#o5a%D>|35>e^~QP@S{%Ga>nu3F-v6WCpwb;xbn)Ju z&k@F2N;j>kC%0r~d(4w5iX>N1{7Y_gFwBf$grx_neMN!NxxiBu6Q9E-$*7E!8-I6n zCzSJ5p#_TtWoSo|+1bg{1*juVSn~)|?1d>AU$s5ZoS-yUuEOqZI`ngmmLs4R0!q*P zZJz~0az8zKzDd1=VtEID20XxNvB)Wd=4#lltNIhqNUN*fMV1pXZ#;98O+IYqRfj(g zH(--w6q0hx`RYmJkP=8a{l%!0qUb@2I!(1k#Gy>4Qhss z4>?F@ft_6kizBy^&Dp*49VehRtfWuB4?Gz~mTP+~E2+PHGrR}+GSjR>dpC%uJXz-^ zkb!$%CH=2d_4iuf-&kF1S{L2uWY%IXg} zh|*7m`kY*k@Q13@xc+V*K7J49PKZQRL)I4rtfAB8WCu4 zWdnUZRAAA21zGg$_U^xjpi3xEdAbgkyl7Q&z!z|b#1JM?7+9zUQ#59K^Nb%p7F|AM z8!G@BS4{I_}6EaFAL&ghbB{F z_=)?G?FliWuqFzN#j=BT()ft>QU|i5?Yi9I!DiMyM${kAH}O!0At6>RP;CQSBHCiv z5dK_vwf(=9nx9NFx z=(&!cIB!;s1KDCmjx*}@f^uQ3Q@Z#%LVYd+vc~#g(apq1AKS!Q9AkBhMb_qycnr>L^t`sgC@V>(vKucmG8ZHy*GcD z96KV!`G4Q;CkT6A7}*~u6B9C!cVxf&5YT=hKLVuVai^Ujw%7jr*_echWN( zF#gS;FdnC(nSgu(sJbbZ1@ew)uXR37&2x6vNvqNBr((3Q@ys)i9t%mxbA9;#1aRv= zf@zJ)XKxM;T>il-y|NditRr4u(7P~rRf1F~7Bb57_~UL@Xe9bggu84jhG$NJdfZQ| zUy;s|(U?8iKmhkL9{f_$A%6!5C&Qhyh!3DxfhneKs}N}ksdnZeS@tB(^c5bSobc&- z(j5{@%H{ksg97rgKf+(|d-j5hD+9}yLy?2C&K{4maXYNs#V^+HoanefID|K z;#^(6ley&fi%!WDLOA%V>yDa^Qqe@aqGrI-yWPWb#as+?I!yZm z^>Y0;O5aN4x4%#IQfniiXtYr6e4LwhAT>H{g8zKE`DHDXfik(UJJE0!hx>J-$P zFv)yyR_}pd-b*cNHVUXNzC8Nv!lP6A;te!AToy<=&uW6D=mRZLf%5H*Yb)xD$AW^m z;M~y@t%%YJlkmq23!g-LW&m8o+(v7VG-LRdyv~YpWH{-adeixDjgZsq8UX(dZWnwpmz~I- zq@j}Mej`yDRADU%oLku_%FiwNYt2)v&kTw*7%p%^BvilQ0ivM zmJt^NShU|sG4KFCnOR1UEFWGIY56?ec=RV2`vbo-dpFYE#GB)B2g6XNnr-LyEvJxz zI942-g_L9P++Pjs^pKc5PA2GXX-v@+<@V;8DPq);YA!MUPu%rpB zYZY9GVTb)%U=bN$5^c9Hk#m;h80H>5%cw0)6U%qd9(?Vtq zIirwvEO>rZiq3o@=)$#OL$Tc88)gR4@u*Y6k5SQ!f1+<*dQ##7gX#)8*2!l@X*wM7 zZ~Alb$&oJ`LoY&pf<}3TR0DCvO+!Z?&tWBkohL!KGEp?et}awrA7v%ZmBVf9@J8d7juLw??FcX%@{E|beo1_A`R1Jizn@8_K{Jldx6mb1;eo$ zvJB0l#PaTWfg$J}jnnIw26 zATqjf1aoRw^0yfQ>4GzJOuG$dlJ%&ZtZne+ZF3IRGBT)k4@@rA;)*h3#L3nqVNe=D z$Xrz!oI0Mx)p<;(XE;9L<4kUaWfQ_w#<<>6wnJRNuqN~0u=hIPaZI)bQr_`=`@T6} zIbZM|5_rH6z@G!KYyU3uiv##R!XJU^TeE)K9GcIEB9>3`oIh*|)#Ww_@aRCjIef3c z^OgO&+8eD+MmyH8e&|4~s@%1=upC@3D1AsgD#|14gxvv~8qK20v_}?eAkSiWh+9L; z<>?|y=$RO?Z5^>_8pmxxlnJg#Z{N+NQ`N*jh_jiGoz6`#-iqHcQG^Ke5^Rzob2>sW zzrhC|eg?9^DhO|Y1KNoO-|7>Qpi`AWGUNGsG*AD=W{Dk;RJC(yxHC4Q0i`2W8oCq| z^6ZyBJ6G!I)3nM=cZt-0Z@FA=dFx!AMp^p?ggU!m?ArKs!ji_!-fjt1h_{eGP;X@^ z5vph5-t&KAIYF~EItRqc=vNsmVDI^HI+{Kk_<3MFyV;>7z}cTnXSVi`oi>uC_rQ&q zcW8+{8~zuYB3~LW*PfQ|e93a8a=+WCMCbd2ADq=*fvoTmNDfUk#mjk~TG=LU8VCM- z?Jx9}xxkO5MW>WXjN0XeHpy#=?_cbz3!Iz z;~X~cpzjX8s%n0kDnpy^9bf(p?!E4?B)lZ?H&eZT^5f#Sb(UT)wj_%7beIBLf}M{O?zR?r_wpDKGSd__j=UvfF~S<_+l@AoSL z=HK!#zGJI~Z@&+lh34$HY-I505_48yV8>GKLsmy=5A$T24dd)+M;00)qM)q~%gbKgRFTYaj7PSXz(JK( z1ePrhYRe!RxoFcfBMCh*Z11!hc}&>7`GvlGdz}I06++5!?3#*E@Z*!iMe7J(UyJ4P zDby^uD>=%iX2B(7VT`DbjN1HSw^a~_+!jPbz5U0)XY5;FEtQkFBOvyDT+q?tY~!1SYwn3iQNufH3z<>)x*p?F1xy|e5vOoHvTL8k;Q^>-C#5sY(dl=i*hWeY@X5AB?Z ztp6Vyn($@`B7I*h9Z-vV9=E1Jq)$dhds0?*!B9;08`_`a-L-xtaUw>)VxyJcZg@4( zJ|aIjFDG*lk8mStpdE_I=N~9J{LvED@o6}K-^81ot9ZV>cJt1aY}{k5b>F!0Y)~76 zc!74SH=u6X2{p&}0(u7sUf(uKL{OCrjl_dgeD=;$Vp=RJ_+BPLgAS~1YQKoU$tMg zmHP{$Y#fk< z%&9)WNxh@vL5oBLQxeT}&JRYAIO+Zz7IMH0MR=!pJ|_b%gBNc;T9iV9GoB!i=ORBc z#~Pu0%n80-@7KkDFwm>?5@IuBd1FLiRyK3U*u;~_H;A^!MLK*WS@0a;NR-n0&{#s7 zo>kx3*|)mx!j`7X1%*}$+ioCEZ9ZkaKwZXbY0Y1(%Bl}PQ59bn7J*$z}i)MAoL;j7Q zGOKxD6DQ_pO#P#Mbf;-(MzRW!!8zFs6U2yI;cPnY=$UCeo-_(Fu>s`CPxUY|F`1p7ms)x-u;zm@qm14$p zFY^9qQeLNbggwTUM3f8^DQ)L;pDj0Rrf#7lw~E1d0wbKW7X<hrHm+2Pa29_!n{;>@zTm-Uj7#@ZlF`LkQ)uK?=4jy_@I?89uxHeAHDKa~2BE2Np za+Xk0&JldpJ!cn_BUT{yuJ%Cgr-5O?*W$Nm*l&G=pNxGhFM0<7jfc2MScc(WxCt?8 zxXYU*A*@EOtdUB1=`QL(Ri}k|o9!M>hbLxElzEoI=^rv!CZWUA3C49*2L13QT3L$9 z$V?``r^X?d#B9@7OyX7q%Ar4zG18Rze6kKG>zLZw1Ac@_R@bGS-^NenLpzQxM`hKx zWlng=lA8Wryz2Rg4wrxZ6f=pH+2~DxUIX8kjLkX6SqwhUZ}?0(0`UejHEx#}`j$h* zADgY;FY~4r$J>JLE?^S;Wg6Tb9CP)d)fQw!cMconmA&_WbQeY^8stq1FgN`2w+Lr7 z`q>7TIg|DgVIsEW)WE`r(VE1;Hr_nPqFIzlP!MAnbx32+QZdg;Uq0^*4QQ~RAXvXK znW%dS8B6QaRwhJDNiVTna7T5{J#|AC+ch@kH8Dku{`U9bWOz;eTXs;W?n)QwOb$>o za|LRTQ1&<}8vjdt=}7*|7D^*aUnkhC%KyZEoua2DDfQ{{a1DyE5Qoc22J3@u|FS=J zC4Pd{-%3P1TVg}hw=SuC3OY$d>UG~bKa6C_T5C?#(eU=xS>BkW1uE#Mii}7sLy04E zsZz+$f1ZKnmWH(N;S!`x(D+_b%7tI63x=vyW8Py|f%1DTb8jTO3l8`!9`pOZmH#3u zC}rT@{mFVV3Vdg6-N_9C`R6yU?omqLb%RvsbagE)>40>XhHZv6p4Ta}F&=4uFx;-fyGj2rabPjuOR+Ad|9a6cFglRwR7 z@ccf#tSJ2Jmy`T$H(SZrB}04-U@wYGu4>2+D*W6&S0$@4vigQm;20WZt*+}e$>Lis zz&i^XbU+N(K0=sL{&x+KeHay}`ODTQ(gO(X~r)cg9idmT_8>KyNWq?1UDn z!MpeP{GHL3?#Vx@5nTCgCy@kF$OtFdjilPz3>RMvXbja-52Xc@IiCMU9yn?&^M%Xa zFVL4s6VD&Hn41r6icl9O0rn&%1MxFKg6a9DQHLGb7Plw3aYGCF5qtAr;bh$*%r!o| z{8ANBvN=uGA4Nql5#=0LMYn4IILwfpUTJ^B=ydma_Z@>9@BV{a{2=ib3Go2OTSfaj z;Wg{N6jk6^mrku;phUe|Dw!qBO=qK~%@DSL3w~yJ_(OR;UX&Tl>$`S=__KWDDDzVO zo{u}eBkA;nHwV`fh?B4PQ0;DXux}`q zuXn364CA(p{`iyIu$a-r*v~(h>KC!9U@Cov0`cN#Jd{d>c znL}7x;pM(b1#&jzDmXi79yA9WbQp+~JW{yT+{}y?=nWsTs<3y#aJ=ALlPK7)_de=u z7Kl^Gcl)+qHyK)-Gm^zSppzEVbA_QUbX5V-B=Vo-Ts+ z_;1lnBQ|Ju-n=CrRfp$!__NZBcR~$2iXSFPr@gUTHOLgOS92s#z1o|H$8NAhfddd` z_-(u^9o(JNaOC5r+@>0?b}6QocCP>45Z@c^`tje!Nn>AF%{7Lvg3MFbObHTiM)NL3 z1z>FUTR>l4knTM*MO|`f@tyuS;>XLr5;1aWvorZBUV|pV#hKKm@ItlAEBQE!4+Glr z2BLcWoLk$_Wx{+m#ILFg3_qjV#zuI$kJ9-vvc4-_BLo;uqq#wgc?PaM36VvwM`}+% z_9&Pj(#O`8ZHeVu0|%rkDs;oQOB)HJ=L+nviLX&Vk^wmQA=P^C2_iS~&N4$fjHJgCb*ec(eIrdLGV^QFVD@)DOXchK{J3b;?Rf0~(LWm*{@s6Qje2HT%65VqnqdY}KOlC+HwdjiYOBeidU zSQV5?)Bf+PS_`biY>{(j$6D_3gOiS}$CJXV8_=z%0g5PVwq>o8NT3Lm z8xt!D)-~mpZ4FBl=np4Dk-6U`(tkk>aLpwH>vb- zP)i0Gu!bWxT_^Sak8{_&b0;NI8&A?6PI!e}B8MIQKlS>hS z{`<;%J$h$n@^YdUZ#KQMwY&rh)jS|8Wpo=j21~_0>IT4&6b5cj<(b&Bl>|Bs59%gG^G4b|rg)w|F39IOi~0*W}6R|kqXYE}`2 zv)4Z-Q{nTh2~R~H%qhN&r=qblaFR8D%ac}q%LSn zKYJ2vMBC0WN^2zZEARh1u0g?hZZ`C+q&?dwe@*IDReM@ZUVOaK9Sf72BNwS8h}Va# z=l#9VvkG#J%^tG>o=JrC6B@(()%08m>o5;VV;VY3MGcyuTOxw>lqDA~;*ZA4y-3#H z$~{Y8)AuXhwqOZe_OJOutq3O3<7WBT{9kjajb%Qs$B~b{jCnN5Gs+Q112Ujd1#tt-x13ij=&D41DN{oS8kclO6#{KzuNL+}Y)L9Cyc&b?1R+yn|RZ4Pbq ztW~wUTla}|?Vk(BfLrpEiNKRKZ}}&x+dnaR`&S?P!?X}VN{Jleyzz8z1g`xt#8bO%*{aK_a>vmVq z&-%ulLPw+)!uhgw@bbxq|V4ZU0#LuVX{>2*1<45lX`LSyIVOcRFZ*YmZOKIX8$vABaYI4BFMn?vyASpcPM4sKZIj9AK z@^_f@uk=%OkJZDg1Lyd8sqSqic$6&ZQ-B%1ZiR^7;`@+xFRz1c#pv1_&Ve|EK~sKkd@ohvUq>}dfd@!W zK3M)M^sJ2G`~zCJpO7Q!Cn7fAgi4()mdFy~>@*e%oGRVM@G`MJjc>4nJ zAB3NqYDF}`MPnv~Y^V<(xv zAR8+yt@`cw$>)XDs0`XnM=*c>)X_<6ee~|pmyF-3z_5N4TZ)b*T$Pl)zAu`p!@H0X zOjq8pY-aBAW$Uc*ujsw{8U(g|B!~U}w8Hmef4XlojO`w%y|mi=&|!5dF@(mXRu?mK zoEz9OlJQT6u7+4(Hs2@In+&xV8p_s^TjA{(J?J2mnG4`_6vz?zr{>`Hp7N(RMVA9A zAEq5Ss6qLXVc{d*UUZN@TsiERk0T)RjBc3?Kfbwue$%YGP;6>TNJ*9*9zo26MjaS< zKtG$y=Jp3*rnt`@{RfeXyD@U$L9C=_tOHu0%ByT-i4!$Vowf3)gP^s%C(?XJm0lvdr?tgD}`h0Bi3Y)QAb963Ixhw-XZPg@9OMk<rhD5rBON4<$|$+-3+q8jCymJXIB}ELzL;=%gNX^ zV@vDb2W18x9gYu@bD6cc@*(fos{9dtGR`6_a{h!U1~Tl%^|Vpse~@v`eJQm>pCr7B zm=)B+zA(r(QT&+McGuYFQ#g&r>Mdcfl>Z=4$}a-u7>9rY+(GPc86WTS>E-4V!weNF z2JFX9#|RIYZS8G-p)+O=uvp$}FgAIe4Q|*3gcDeMKTg*A{C0BO>7o?8caHd#Bzf8X zO7iN9=h(Q`x4fg$nW6PyYjg1v_p|Vg=FEeLpZ?bgrgLrwQ-;qawf}?sC^Ct*QdA?psME6&ns?G8EW+X8L|Q!2wdUH z3804fEr&31aeQ#gyi8lod{N%)jdIcbq{mi5I3bq(?oZV(3bJLkHGi9D6&A)^2KRaw z%J{)a*J7G~W*$`M$s-3tIlzaChIZXEqhR%A*p)cVW=JXB`hbH?DX#lW=3LqonLbAU z>5W8|r82`i9tl>yTI6GR*xdVBG$$-iE?{QFV$Od!&*Rx9q{ud)t!=BUcA^-{x<%dN zx#!wSKcK*F7NDSW32;3~p}5K+KKLIR&Unu|MV=paXy1)!AJkpy#^eI!eV5o$R04Un zIb3`v!^2r>Gs1Y&wfy`dByH2z?4P76t}xwTxZCGG39+C@?3FW+Iq;=AOu|tEmqdE~ znPo0W)xXDts$NfG`dvqWTm-!Yu^^OL%bZqNO^=A#=JH!SDZbW5q|}AIzcuCbHFqUB znbA`1!Ba2Ei?75uGP#^dfG%NGlH0pn5Nfd7`&^X6N7J9|-fSg|;>;_zXWVBv=!ap< zftht4D0LOOWuuwLw6^gy)lJ$2Jxy?DHug$e_3E@VniF{G4?%duXT61l*AWFBW^PmZ zfPTX2wb*2)&V8hM%LvUXc3kSlO-#bk=p+@%eIS;uGM7r!Lz z|LR7PLOlGP4aw&XJXRUHJ?7HoNadNxcdse_h!|eakVo* zu74j|?leV{a`G9l_P>$wkYr38-=cw)n{`j0{LU%)-`PN~@$F{9wr_b7MFI>66peH= zfh)CC+O>TOrEbZH=(#78>XH9%gOBM)C-ZhO+^gcclu*`|&a4a9#!;d!8$|~63AmC( z6X6>8aew{6aMgu%Z1G*>mltxpS{mY(+va4rqmzbo>9@56h)56KoZegHCX%;{lJb79 z5Tn~U*C^g$7D?PlCn{Ws8SiBd3ls#-tXhb07vAJW>lD+Lf`Rt-OV_TkAOa41-Sg#Y zC(FYAz4t@LE_vaGUw&Tk;RTPS=XH`~HN2^zN!Be5jcmplMXlU1!*-rQGAE#b*U;hH zF8-MUsvZu4d%11M6FCDdrcGC*k{M0>&-wSvG*#kXX@s)lAXF=CODDfgf+-?EGl@-4 z%+0;%VT$$b5dq3nJTCP=$P2Iao@f6-XyJ0CU~|YaEawjJ1~>6|c~Hr;VdT6Um!M?M z{fjsGwhD6Pq7qx7;o+Aph&%r@P~k@E?iXc+-;H)BfC31RIO26(pRN`c(RlbIZ?3_& z6$4}E+)r0x91i(*<2h6-id4`iB0Q@c2-udfFC3q1VrA3?4M_K=OhE8o#@U4o+?ZAro>r2u?6LRum zZ!BO8Rr|2>L1X0K=!V^wy)Tc|p+s-$@fdB&4EQ)_2IIOziU&MYz5z+Q(dSYJxO6*kwwmK|q9!>1cPLD97_j@Slb$!e;f*Yh;ANPn-%;O}hj za9>g4=(C_(A5=&L;a2rzTD&Xwjw`p$mF;QoVvlc?7JEz|Gxa$N1OqENS{PpB>G```Q}5E-bWdl2_brNidfN zrWcowKz&cOY6>7( z%-gcp)QC+zwQC>cap{~+K}?$b@>kS}cnM*71O6WYy55=8yWlTP{}$nKC|$0Hw_q;YEdN5rU+aI^-A zx1hp%$14KQSowe0I`4QY-~W#v*;yfb97U~*Y!BpGF|3WZ~29~?V-C82EDJ9{5l z=aB4`?VKaB&xyF>@cG@}|9^k`$Kzc0ecjjfdcR)JS3`DRBN!Z@xfyY%Cf8&yOZv!w zvL6iY4K3s24hQlWeUOr79tm(0@+J0IjYg0*iTZi^S!=Y5D z8(^I&sxV-EoMI>MX4^EbYsUR}NNg3y6PG!ft~z;*<)y7QdFtd-GI9t9c;#U2Ao%x( zGOvLXWwR6?6@$Gb%6IaCM>}6-e-!InQ9xNNd>kTHkVP_od+`)rGNsB+G9`p$JHIR- znNCZ%)(AWjXeA22E6TZdbKhje*%O{JgeR|4#H-#78AUNQ^$>1H7TW^-kM!*a3@hR> z17{ywCN8qLJU(brG{WvS@8K5DspkF=$0+^R2qh%@QUPu?^f)J)32>;AjECy9BA5Hs5KI!2^JXzZ%mY&Gl+ zR^|03+Dd|{YjHffRzUtP1=aRrn0)p#hLGQw5yck~OZ?#gZ`d~-+;91Fn&W-%jzGtoWuzogVlae)fKD&kfl?rC7)rC9*>b#o&u7^j zYY3_rT@|0Qjh6&JQnn(gMB#mMtc?e5E-X)oa2kJ{3w=B#@ut0HmcSan+FeKEbI zf`j@Og*qzTes(O%n1UA|V$oXavs>!{t3H$Hk2Zy++^8TY5(lwJ zk79vjNSLdHfZ>)JKxIV!sr=IF07s89qx8fCbqbUR(8PqYBmK*Pwe`AqS(?4|uM?YJ zdk8hCrj|7HhZV(_F7xC;m>{zCuXpNw#$k1Xzd^+%2zq7Lbn$hPH{sBvC&>q}6k|0Z z3`Lc_f52O$b>$^;W#E1<=a4|+S!N%fCO(l{yuP|Dri;3+wyJtisg2rjG zVM*t^ws-4W>O|80`AZH7G?dFJ1Ij0x&m>+EOh#ClOT){|iq-BL&(TEadV0;@6Q>xJ zigjE(rwGz?6ACh>Oi+$MT9n=05 z`BGX1Q{j<8XT&)gMGvHWS#=J*c1eSnS+wbU`Edm>JAeGpSTa56c5ZsKE`5wZ9ks&v zNPgp7^SRn@K_f6s-b26OBtKrhDi?#>z2FY!YtEL73NRO)&?VSn!Vg_5}<<_r&0l@Mov{Q{X*w^A9UP2y#*_=j}MMG*>wb= zKEWczJ9A2x>5diKncy5XJLszQ;;QB2hJM)7!VeF9g`^tZYhKZyV76sGzp0B=ECu>5 zsb*izkwjOe5*OAqDo|e$0Y{l>f|Yu;~(S@rlCvN+E~Px~pYwSUn` zE1-2fT$YJv!HFS<8AtPaia5l3Q6h*jnx6@ro6Q}XRdW)vWTgmmLUA=My?w^qXlrBb zq2>DLn>pItKJ0gBd^bxN4CIxg4afofx76(rE^w4e(z@MPvAyW6QwG1UpB+$(wTk{O z?I22Jib2{7@TR=2V*}a=X}zoR;N7vmTg{lz5>>A4%hUbfjHmk^?ci*e-?PDAs9$P# zGIlu5%BgD^HZMM0GNT8pVazWJzL*C zoRv&wPXvvBAlp8FGnCR*Mv#99d=5%IV$|VXl-N2(EA6jKzt7xS@_FHj_Xb%C$a#Hi zXR&JBYHvCjBzh+-fzUx)<)$>_S)Ucr#Zlb(?$0Nzwwk7LoDG#9rq-F;1XpJ(%~vh1BUr_X5t^W`ozD#!Up1NUtC2Q~c+(zZ*VZ+U z|GaS|uM^}eHiK~AVR58Oz7jT& zO;KhctE~q=yf`GobKA#-ToA9e@H$~IiDIWB>}jNIm5SVy$fNAXM8^RZ*JN3(D|f5? zj%}qS-YT=I^Jn7hqHURog<$6Js#D;$N0+aP5>MjsZnr@JsjBai{c* zFFk7MAoBg{{z~}!W6^S{rn2N?D&|Bd#p%ecOo$2h;pv|D@+h$tZ7J3@4bP__*<6>r z`=))$m*Mt_0F|zSeClwr(!bz;gPv=Yp-yfb4*@%HcCf#86~Jq?ceE-c%|!N|rO&oy z{Tdy3rw1PXnwoz2v!-}Xg(>S?o5_839lQ^6S%yM--WN)(vy>efD+AI#&Q@%ZcJZQRAY zefH6~QQdu2*;rk1xYY_toFV4XLYhw2_|ZFI2nu@iwm?Y1dFkWKBpIevF~E&28c zdW{`}=6iZ*2$+?)G&n1%bf?-e0u`@mroT@OJzuf1a`+lAk(ubqo0AwUY#TtxyWKH| zy16SR`B@gq^5}iU{hNAlc+i8$P-!2*<%FvH4u3Yu6C|y7Oi{emka;*7SkM9e6KN80=jY1ZVU}t@f`3 zzuY2Bss77iP9)4>YCyWAW2H0PWfHsK@p6Rm>Fl_MI`oNIJ{;`^Mkn7@r<;HYX<@^e ztyjy%2Lug|@Z{g8$PIh<`(B>WYmM%o9W*9ko2h8lv`W>F zE(QV~$99UYi<{b3<7}R{VV0>O6PMkG8gw09U6REbWbG>26R4UuU zu+4v~^_t6>O-2=Dn{B`2Nzwbj`-0`r_jTk%=-wcq%nDd2wCDv3mz9w09k=%P_c~1T zGUORVM%~!zrPP^YueNHY9q+&!+*t8>p9(Z^hh*>_C9$>WLs22vX{toYv)&y+KFMS+ z1twZVHtv)pmcqX?zMgUwh~Gi0DEFT_mm(?=$msanT~`z~8y79ojEr@CVFHSf`;fzw zz0m^mFSSv)e13$7(?8HZe0nsH8>rCE zSpsTdg%n}_No7dCDZkj}!^%?;|hOcu8hy_@<-^ z(%tE1t8qqzuizSXjWzD3V^7=2b$Qd1^&XO5^fR?P4*!xbRk%k^Y5>Kc`|n6k2!lz( z>sBs-Ii}B8$FC^HOKy+zdhXm^qax{+0zHF0EV8+3X4Agr;1&uuKDDf~8yW-^YzLrc+NuK7UF97!kjf%$SNUr$flW z{v-^}&CGIE)_}=k$=Q_K;o9yc-;B&=wA<16Tbr^dbxOzP-SF5EhYE^d5nEq^-S7-Z zJ*XR`jcd-oZr2s{G4e*U<8=Bza)FZg7snzIw44Rx4=#!>S%FVcQ>fbr?Muzxcm}V9 z;%Cd(*V>@3q;&~nzmOVukJzj;8i!Ul?KR!T_GoonP*9Nha!xo}xUIwbO2~ot7&S;a z1JUAx^`HKZ(&^9Hi?qHje8Y?9CB{%E8*IYAq3A+Jzy=YdE@57eNFPEwnPKB+RpY{^ zr=PHw)+BGnviyME>8jjdvctpPzAxpRkgJe0%Pt=5VJ}n68VgdTdN<@Q;ExS9#Xp<( zy?YbBFTVOKs>|QlYN?}9Cw+xpQkD7vhPvCF=zgZ#=2s;wTe{`Uzq3Mg zT<+XrE>avYGky~0nL~*oPi`+F9InR~w)y%j~h6)B)$(2xY{l zeeC-r46u?t^TAu4$3MT3y5HvN)XwSC#<{M0?+2!&0q=pVj8Em2v_e80H18PO1d^#V zuCyC~st6fU%brlwm+9BT2J^<&n4Ug~KKnE3F4{~Z*zp;*5YFNEL6YAgDJ|VT!i$dk z4SFAnPtGRf543n9@V(scXIz)`lKlv?vq?V;yh6qjYb9Pk=q)jp=Hwz5*zDwl=@EwEg0({WS&yH=+SFLHO zHuK63ialjt)onQe&aCUU6=&2x_Q{?#O#AVDT;~Wa=;yE;<1r_x5KaeL{3b<>YFg@o zidAPh$&6}h%@oKZ*1c!!^Ob-#qTOIe1pxNK{|~QYUxM+*Ezz}GPT}=?bf<K{flnu;WH|!O`!c<(( zpdHUx9xFILjYToRC;o?7i5>-seAVWw)teL9CmJ12cFyczpA6eaH&~nIYT3S6;Uf7( zD^>yu1VIC8yP%=o+{e4Os-Fq){uN7BI<6HqzNiRchlg^LZd}j5hEyzdZc(x=@)bUr zU7y~NcR#7Osuaaae_GvLD<#|FCt?qI0Pn%cI2o}}y}2U6x4}w(l*6>i#*9*4G2!lz z_qwY&gKuEqDMpP+W{vq+j2rW4(u1qUcetm~)~fTf+Z5lItr6u6g<7g*hkxBIS*KtU zc&Q(CKVfvjcVF5n#eM(Gcf+5Y*ZZSA=10$`zqLBOZ!O@Usum)=*4^-ULaz)6e4PP{ zGv+b!<48Taqm*zKrpMSBmT7m9i(&&RpNZEImiht{Hx5{roiax6wc7NaxKj)LVRRy= z?q6dfDG~+IcFfHN*AaFP=RtQ$Gj7^7+o&Oa*XNq0M(2%*^@Nx-Fll;A|ub|ZbOk?5Y~ zA`dbuVKlhyUrUsbL$e=&bRQ@ydYI~L$2mCT8CH%GAT*bJgU~}lzR#^jmMWhmdh#na z0YCqPFo!^$|5qhEUn^F7@VBiX{`--x)w}4G{hzv@-D3?sie9$n{{E~W4B=Z^Kq96& zUFTH!fK;8+4cCpPy53R-#gU%ILB`Hn%I?IS%#aXx_m2s)UpWHW- z>~k(Er`F(i8ruxRV+YDaJyVzS`H`=t<&re9a!KXkNu$_9j_QHqu}N>Z$6>EZ5I$=i zELZF_Ou@YwV1PddwD6r)LyP^Ixiw;O6}?%3ItW_&#K-9(iGyP|)6G5Zv| z@%9{v4hc9O(S2Y61qD@EsD7wlfScBN(k-V#+@j)4p9y$; zMu>b+sGU0p{cS3Eg`$o&z<+(kidP3Alkg_h^J3w_0d+F^D@xoN!GlW#3!!af4A?PM zh-8X?6!Mi7Zr4wXTUW`X;Z0lQ;?%}ub2Dm=5|NgPHPT24LP^btZ~ND&m(8D!F^4xz z-0w?{bAm)T(iv;4HUM=uo!FZ;;Jh?%qeMZ~Y#l z?}NoH1t@cxd$JLP0%d0&=Hom{eMfJ`E zZYnA{tx=2USK@vndl+73oZ#8?OX9{2u1AI%hVm?dYHTFYITRGovzixGl|dXnZJF9D z?M{`**Y8Picx2PclOUhQ`D_wnr%nkD3HS*TgH43Aoeuv&H}MUZz@&Ww_u;#_-%2V! z@~l`reBGbgFHDn%hZVS$Uy8P39!`LmUYuG?$IqF+HA<9!98uGjCVHQ?GNicN)fsrD zDm=2Clv`Tl=F0k^QFfeNw1nM$OYK~u+Jmm-{wFQ1<}eMcPP=Cdo3+fuYM=Rr*9MF3 zEAKo>lA{DVAmk2Gd8)RMK-C@WC*DWuXI1?1!hp@wcj3Y*3&c=!eJvhpbg#Oas z^0W-;Ek!5x^jv=}l53UVY=fEuR6o~G!yfb~urm18?jCx4Et zvGnWx<^;d$)Zpy>iS7xOl1^>AA>EVmS9)ZE=__0!tTM$Up;6%lv(Cebxle8E8p3!tL0HCq+raQ{k*^+`uIN*F(|5w zyvtii7oeitpqQjI>sr_`-86cCkT2oN3zFEg-N1)&Lew3f^uxu*n?-%YUF`Hzi)4nd(8OHRVX`FBmN1%QD?kvA&BExQ zx{gXGC443lr>q7F`&OQEed3~d`SoqT^G^52&_<+E;6R7YKuT=K1MMr7Da= z{~Lraqyq1eWXnBua9D?eB1E3Iwj^!(O?SQY<;^zHgRTsh+1EpNX}2-f2$PxrAlznH zgWj@fRr)o!ssO=eu%%(2zqRyMZN-ggakr9RwQRW6`9zZ7doxbg&2D)-QxsU*6iQ37 zt^mmlmLH!vXR;Sc!1x4mf5h4wHt2+u*Xo70p+|D~J`JguRIBkdA?(8i0q^R5me}d7 zp6RiPBI**%6MMe14W9yfwFT*c#lu8*)csxl+k`F@{k%KUp0;CRv%{*i*>S=rihR_> z5E~IqO&-k!neQV5uf@*v{R(2qZI)Z%*<$sn`R z>B`D=BX!E_rXF!7cKunE-MOn@qNfa9_k{i&2=g!<;DWcCm%ilgMrbT|t5c;T*7mO~ zW+5=^kxrAA`V~xEZN*{aii)MqZ1s!ePEGjq2gd z;*s|5m!chUuCgO;;&+Pdu@}~HWX%l``s-KP-iSmi8oyPi%Ix0{#XU#CfVgsNgna*L z#z;l)i?l^Vw1%Ll+}C;&ohHNQGE*-ysXaZzAofcjM4PA;HFJL%DMA$c;r=M7TkiBp z)}8v5$Q8^D>XsS%d62+CT{Eys-#sJ#+15?ZdbW=3{WW^AP=(grv4>X#f_u?akmIY6 zf9K{vYjH0T)&G1J#0>80OpxSZujxXWR(4o0Crjl4k`~n%uIVAB2n8gs`*^_$DHsSY zSyDmQ;1X1>Q2hEeuetp_ayF^2lv=Q^yc8j_x0pFN9>@LB)@pe%^!4v&O6v{(O!xiD zF+W|D!~TPKC~OH&{3gec{@2z9oDZte+Y`3pWo+!9y1fDm39RUT*Rnhk{MxqAoC;2( zY{VML$JE!oQ}@_5Y=wbPaI}L&OwK=>Y+89dtxs6lHE{NKyk0+aDlgY3|KhusiCdY` zzTn?+9zVOrwf^9nKdrV^>8E^XK-sde_acu&SlA=Ak@pA_5;$>%^j4mOpT2S0%}6Nw z+1zo}Z5<(Ua=QoaO8(bqV^7J;jDE|m^UDH)B}-tLQm{uceD&Vfqh{y7bVCkAv5O5i zdO7(!U+x?T`^2yskiVAYT8g-jI5+_B0bh2wT)|UGk3q7OZu6hxk=PQx$j{ZQPnb?@ zbPx0)mcVvUkUhZzom8sJYgyf)KiHh`oz}?v9w&B85%Xz#BBi``#GoNT|7%NQm|OI! zY#iBMB?MYfM-NPc{(h)6B2;rqR8_#TY5wdos~%NRD7tWe<<=zqjSRl;rYn)NBn!O9JlTZ zySf!3v)jWg0j8Jhbcsw6KIS*(US1BcIN9C~%DC${;#zh(*YeB!bL=;Fg?@j&4d`{> zpYA0Q=h!z1t}hattlBoF-EX|-?_?K2rzM{k*#e^w`_{eBge+mPGT;G}iS<9ogI~YE zzjZM+4D(Z~P(M|n^i*po>+AJAR|9m+T8V1$G7Eo)UeEjAt`|dV?GI$S3|I$zekDBo znxg)ddA(u{$Q{gYV$a5|Mde93PIg(qtHfhMZ+#iY25S^b-|C8DD>Jveek%;p8K%p5 zyNV=#QG{YZ2!2!LAgo{pROqz0pJu{e6j`<@y}feBgqnnOy~IL|lAFku7f4FP*BOp~ zRPVwU!~8|#s+|{oz6b=~{Nz^nikef@qGKa(S)x~r6&KtZB`$l1^bG4}j4_$1YrgZP zed0|tQqNx`Y5Epk}6YA(g-#U(+%wqW5kvSQ?7u_SyuAxe4 zhHCwJ0pDIz@*UkRJ#(Qf(}n9UHrW$oAK;M}`J*#y6kW{z!EPsF5B`Jbw$6yxw8s1? z%cYpA#r9wObAM=eE=&v&ijV2fXJ_MvrjR76GtP?)=G@B0DTwvsFG2;MhtNLlXi31? zc)qxwYc`OTy@5ZiqU^W82vZOy7t!BNjg?F>2_O+gcz}IgKIA4LFREI|Y3e&T?4#Hs z-xNB0ww*=Hk5p?2?dLgs7ee1NqYB-&6z>iwT3oSHO+fX|;U1-KknR6)z$TO74U(4uz-bAYJneva>bEm~4wURfHEY40z#hwgV^bXh6T zin)YFpckz&tU|e6q#sts|9G1z{WxAS4+44NGw47P2SC6z6Hs`OOUOHf;0-(0t^jPe>7ib0cUMdEj9cBS zWSj%b4@h@QwqQ_?koN}!o|agK6COObdv__`oQ?HOZyw#uRQaeBodV*^rdFL(za;CY z4Z53)bmVxZ{zlYxtl|AC3Klfnf(iCG_RQfO!nR z&@`z3=z?OJ75j2cFW|~k^qbZ{vF2GiB5fbo!i*8MXX7WefTF)tAGjbe$(L_2bRHEu zMhlNIZM2fw!b^OZ@&YDhU>`3LKTN1HpCsuJF#Yp>mWQbYj~6-OS2w@xpKx$+R$9{uujn6B2LFCv{a}gz41A zam$RXx!Y}pF`Y~i5r-EW_KDu{(?p@VP|!Ka{WdCZby{y$*7-KQByZ(h3-K=Bh}dW^ zb!$eT!<){o`j(j&PU8Exj_|Kfyajv}wtI15unrGyr&R@Day>|&)#U5ko|sR!+4B#Z zeShv2C7Z~-*Y3HiD4Hq#UPrx5MLYNvD%2xPjR8!bbq;!hdp1LtVEMKmH~**i*-6}s z55$YJ{+7bZzW2$t^fP5|s!&N!N$iynzRyNFcZe4j+*hRTKRYQbb=!gkXCa6{VE!|8 z?lXoDyHKvK0Dr}EtsEuW%;MlIEe1|sP{HQ4|1jc9BXFX%?(l07q?zv%>IRKvIxzne zX}wzv^1Z)U!NQJ)yt2bL{xE6|o*eYg@n>ur-!M(Dw0F?^i&3+3(76=I*1sqL6cDz;{*EY5q?9ERtFHVBRFcsqGqRrNRK+)_m+ApZ8-0-IiC$y=V`!zuBmi{^idg_rlJ7gc6Zi7^1j-80N9X|II!X?(NR8DR>5~!sY#kH7WHbR&NM)NklkeG-Zk5onwa+d@~6*s}`?f)Qin{8^5Yt4533Nm8u;8~u?tIE|egVd5>`I z`h+k(&_m}Ue^#0+p6z~S3Kmt~)O`z!a=g0#y(#P%mK;+Obhm!W7p&W|q|-OhzjsBX za+H}oS^9lY{E=M>7#i4D7|Pz z-aB?(d{kvv8Jn)_m!LPdZoQ3vGHu`RG2fW*&h>n2elASWfE!5;z;OmidDo|EQJjdU z2j6}#<`o6JJ=3bi-qU@<(2?5cdFypA6DFy274;I2-HZ#v$6f(NXo`#o?7n9jdx$YF`o?Ez`;Bh-0&tOVrv5`eAeeh+=y_eVT zr!fsrGUS`=Qr+G~fWyMHswhco8lq_Es|TNGQ?vulTe1~S$3hci$a+bF0Hu8>b$oL! zHI5@i#>gM1@&E*<+QJ(}79YFnJ#wG27Yuh1TwYK}(hjknB+g?)lYBtVtWtAg50`JQ znf{zZ^Mp_nkuk3HNh95EY;~VxYin4}=Wm#|1N`lb0MEKwtYvr~HuO+H6=Oi_?5@Hv#j9+)j!Ln=>}5jnzARASPv5&VJYJ=lOD>@;tUnobo!wWm4LyO#Y+*si{M+*cv=mMMV0l{ohu zHoATovsh0zo{Fp5m3nk+I$gqh#?JXy1s+K-7=*^Lk{$sG;4eVSSmbRVEke&UmRCUYyzRZAK{-GQLOTSw9Km`=Aqu0q}S-U5Avw zU)&IN#YM6pI7~lZyGbd~#6ES0oX?A6B2}HYE+y2dj$ubt2JmD!`HZ)@qAX?^Y`h8P zd#POP$C5@nVIi%XtUmNY`1Gd){-mns?66Uv3PsgWHJD`_>b%q;@;w3>k zGr@X`+C7voaIP2r_pos(K&jHYJziP)`AzMP_*Z+kEWTnW?wV}e5pMfm{;{T>3iEij z$&a(&=~8fJ?-Aw!JqK-sGXHEZiQ^*gMK{5BmO!jaKCY;h-FL=YNwBRxiC#N@{OiTC zaDcqphkAGK46(KY#f>W%v_urYYGi+wTS*x@pLqxBHt$pZ&=QqW{8;kjr^WCeQLGS! z_6sUS-W*Sx280^kB%*ZzbsKm}g1nWrqx|tBSk=jwGfcRBQRho?OeBy>NE-}%6Bokc z+~F~J$h$0Ff@9aUJW;v#OU#r{_0PI~bp3J&;#CS|{rNIpfcqe&-ylAt_#zE2y$tax zdQKS3Y5&Wx@ySc+xc5|sEahBc1#T92irykJjOF@QmnF0Fd~W(A6tNKRl=YY)POy{l zI(Y^xLWh&>pqXg4m$IJ13ydA%qYes*dIKTcJt;WtA`h7m{`#q?=AU|2l6+$$oq835 zZxTlSQFK0s+^2aJ@_ov+bh@cZL@(hy$rwjtd{?4&PB!aTy1JA?5;M6Z*9~SfA*}j0 z2>b6Z@sK-T8j*UQd}T4R7MtyzjqxJ7HV3XZq^%zo(n_#UcpWHJzI*kE-1)b_egQgENNAll?>8a}D>C(!9S=)_?eJhGR|4!b=nIy3Mm&u) z2K!F^{aTKG0&)kpn^Q?@Rne)fE_It^(5yo3Wo1E!cX!tL=6myLktP$WoQQi1FnerJ zr$UpmEJC77@@=NJ-7P)o$CfBJM=~8BoNfaLCprG#9PwiBvQjFx$#5O!~HMGI+Wg_h~VR8Xo?1J)v@CVSQih z##d7|=;mA2mSPB);Q1tPzO8yYUTUp#f0%MYBk-{41@tr9S5UAGA3$eu5` z)dW}`X6tq|3Yo=Y_6s_K#lOuPOo#%GHEdLbN+r58cfh1 zE~R9KEVoFh%QPLvUs4ed(ficK6D0ovIJaLmc7)jZboNCatx#J>v*A)|tmv01tsTit zd1_eDa}H)3olVVqk8|Y(si2?g$nw|i2I&rYc2@78h~xb$+DAsyH8Klgb*j)6Jr8cH zVXvLvWoASE=g&lP-aquDXDCzjz8v8uou#=5AvyGQr$^vFL)b=n_wrYy#A`Y0$P@A5 z+v@yf#H-`yVE0Ymxt-F(bM~@;swStOEY*G-?0{!vIs+nUY4f?_5af&xSyFR3#1ET? zX_f7OQ`&}O{kwZL;%>%kT2rzss`5v9R8s7bb~^MZb#gf6O`YYMKj|xWVLd$i@5NFu zD&hl-TYabVI!A4@8wE@T0LFu=!Wj#)$xP3lPkIIPQjUVryjukW=!9g3f?bk&?-43VnaZdi|G zL!IW!TL{MWE#(aY+qxQX@RbtcO7d%S00QTn$*psrnM@s*CP9QS-k~1!i5h$LLwms= z34vw>^KoGMtq1MF!Y8qB$4t7KP_~K*iQ@>DfTT{yO)ShYeWztWGd}lDjI0BFOIzU5 zp4|xrY3zhZ6d1N1g}e!w1Rn(w7cS*p$erdHm{^gujSKsmC(+x-K$cS;_8rY+yRk{6 ze!AfM0M06}%V9ODgy(QKH~omgka#BudOo?7_+cp%vgH zRr$**xKOXam-*(IL{o4cb>_(0#n&Z&SM+`v*BH}d$T%>4E(h4_0HD8jkIxQm$+yvg zoIBZELkBi~yOj`kP&6zB}b;$%LxA zPZg-^CK9v8iJ|=xiI>uoY5E;t6L5k#<*yQKklhtqYI_e)UM#KK%jkJY3Rj3$oj;?xVGgbZ4dhCeJ^w8wB z)Hnf2SJ4f~k`)hXmwU&xNg~;nr@pnJX%58?&zP$hl@!g=y386hQRh-~X~#VA2f>lA ztH9t%9omD_DWznEq)U)tKa^pWwgOlP(gDwe3K{obBvl)V(0f&@_ing`_9+s3F5{tK zyn!Te*z?a@omU5K$BFcu3SmKXTYW<@X5egY@6bpzjk8-f>WH9+c>-9>bv|%qUcEKK zJnM}yDMLOd*2Ns32U)F!U*0=cX@aw$QYxJ}oGRPMV>;u8(5gGE^U0rUaQR^9kgLn) z%W%mmQimXFI;BTn`+^|0(-`1Y9sbleLatt&)BgPmOG1=xz?2^_gqgJlKLQ9qhq6urIF zcs!^TiOkdFZyGdVng_Cx3fYA#%b4QZC%kT3q?%bCZ@(e z1|XGmERfM4P~{Eg8AuK2(5|ts#3UXzwChGoC;rkspsC{}=J!b?@T)d7HqIe^2`4*? zbANaS<49zF-}iZ_OkOPZ{?jEFuotjb81*{C>?Kv~{^9cFkqDpn-nto}%KFIh8Rj0? z^tbepphyjprT_LMUo$92ywRK%D?5j^uHKrQ{dDKmq)sTq!0<3M@Q#D^U!DfVE8UDJ zW+37GHW1UlDg{_Lzr=aaIhC0bMO)&Libe21OKmgVnOd@!j2*N_8`mh@c&J|Z?=$h{ z;zNelIQN(QKA&rhlw9*_oA!l&Q~drP1hd*K=XnT%^w@VGCt%}hnt?Nn%`%YdF4z@;8+X&ZC*Acd02}pMGPN zKyIB{e(~8>=gLzA_y~uCcD$q;WiECMpbzUOAFJt%_^+=7#o6X&m~rn^MMi?-Srj{Di3KQV$UXuCMak zcqOPx(e-B**0&LUQJ*`In&%m&z`JGj|7`|GD}pEf(+Pl$dj1HiMgZi0eJKs%4?tir;2VIiBe$~JwscRZ zlO^$A?OIXG4GM^TELW{==rh^2abOY4^Y}o3uO<6j(`FQXWxi$b~pfKtVyo&FI(t|r8qr;E9oC(iLEE2547H2e7Qb! zG`B*-C%-{p2!xUZ^LhS*{4OM^fnP+%^Zy{3vgzd{1z@CN7u--J20X6N zef<~L+)7^krtAqbFhRANe{MwLorOBK4%$(6^&hG)UQ|Br!f$E{yaeLG=@{?t5Lw{7 zMytdnBe2-gAbRheKYJ#v=#x`y!Xxv7T5E+7NUa?hyYUWT2zVSg4*T(AxE3{C!}ASTya9Wb%EHO^>+zM#g%= z5=icj3+=v*HhL|7x5At*h)_rf$CTLiNJGcE^o%A;*V{I#{L%j}Us`fP|p#>&WQH65IZo zW;nT?#-UF~6Zfh!=1|TdGEZTPtq{7GK!{$vu4h2*ylAAg)T1NiytR9oJRG5v=%a`h z8J2}E=$%B)>$GEd?u zs9;~O^-$%%xv`~qF?;5{G`$!mjkG_P1~gDN0BVD;voOcfCT}|z-3`QusV8mnLV*O! zu-7naXvvF)umNR8OP^1k4QZ zf#X(-7Xn|$)PR!h(<~pkk#+cZW5@Ea>!D!X3HnLG$-}D}oGg!Ml%wT)u)M(9e-JGu zFjsVW&3}#5Ucdwcf(fU%oKCP4q^-1>qunvNKslbxMElD~%jZw^YBX zRn^=Bx8;G;L%I+o`s-MCpMjAz%k<>WB{r+0x5lFm_KMB%aXD!MGeS?+q1i9Uxq7$F z*C_VDEhDl&@SwsCpMPbMi)2uaC|FW6>c&JW2ffJSd3X#f6F?eWC*~PXg<| z&s?OAvTM^Vxv6CeT9|$0%|1=SrhjDKplrnuyf#wwL(c%pb%bvOE^A^?Mdcakpk2 zUU115ac9BjYhydD*fjb!B>?x4I*>ssR6I)59#wI;?ev`x6I?TffdR z1)H5!28;dc-OCA_K-KzrKt9>c&bgZX4dn4+gHjrBb$}S!H=f8ZKkX*!D-jz)A$PKv zlu=s65$>V=y16}hlXuG;Mtk#tPOFjSsVXZl9YEgii9d`<>%%kf=8<(fzWl8*7f?VC zVt*_N`Ejahz!x~!i5PhP*p9(j(qhHZ<*n}4n0xc>Hg(P1B{sKl@}w=HlVbyZ1JKSv zZ8__Hqkh))f3-Msx`Gz?KJ;My{CS(gaUEORMJCds9B$cCR_UJ|r!{6Bo#a_zspsMw%!AdmvRev>eKs2XvXZ6Y zjv~c|1AT--0h0}(Zf}8rI{FsE*EpxjgU~a{;FFr8<^K<&(VU)B3_oqv_VSYcTgzbz ziuUXy#I^qS<_L+$lgDi^#mZstH$~{Vdw+&~UkHRQOS%25Uxp}!5bLM94sn>h;abvN zzzi?JWw8@NqeVDK2&xK>d^F)ZdjF|F_~su?%{oYUi~Yg-_Ay40g0vG!Ad|oCtR@Bh zPv*SHwPmCQdd=FEY{Z=kZfUxajcm; z5^a!q((vxREEE^}W*GL4kgiL#yDOyt7ei^*eA6Jn+KmR9vx&1G=UDmrVzcFQ>4a*>CFts1* ze6E+I+IMHYH3E+v&0rTYtl~Gt>O$^pDV`SmUwdcX4|UuAag;2RnC!AI6kk>@&51u5fy5TTQb63;5RNY{){JuN@V-#Wr^&9oQL-;V#%PZ>>gQhYm7Th zO?Pz+Gqoui1Z<{bHULyfp{}2e*M{@Dj0VqPl@PJ$;Dp(Y@0i=98gIq^x+r2zZOh+lD&SJr)v2gJyFOfzj!H_TN+tcwYADSsw<&aoWIzUzgbT#V{XZRSG{H~|Bk!8=-%tElFZt2J|Efn>l+J{jsp z3dJ!2qh|LGK^>W9;g2m9vx-3wNcQkvtt?=dkX z*zf#iDH*~wU+19il|b>wr+XTK9eFGlt~pCYH~7mCL@)H>diOKkc}L@z`TLP>>k%)v zx!Dh3Lc?za26C$vZH*I$lymHO7Ptp9CoyW6wolPqFf0o(^fP|Ov=Nuy}0oc~2 z`sk4}&NDaRJmhj0v&$QwD~dlMl~O2{8wnNy3hToPP)I9fAcLv5r;!oIQ3r|hu9MOq zs4|(>25sqoyK+nS)b=KK)?b}FwSiwRd@c&g@F{tDe%MWn0|koxgafrZ`B|p;_i2YJ zcvh%a;<3wm{V)C(>J+QfxkZg(5Ho04UCBl{(V!rnSEW4uI#7*HsUM2}yt?;zr90}l zf916c?$J0^qkc}jQlMYaJ70=)qYq){2sOFx;H5kUx$(;=!moedse7VFiq#S5Js3W7 z{IR`hm9ip10#{#j-dF2wa4bt55yC9_IG5MUJP`~&WYYJJm;XqWr-IQZOD(N zPj%ObfQ`a~vQL?!b`|50pnCzR7WA_?*5 z!(?qU`~ApjJWqST0jq0%GhkWu3Uox_k;SQMSq`&o57rcH<}ins7UnKFQ%2uyhbZa8 z9HZqT3TorB`rS?~d$ZMx6GJBABb7QC?+H;exD|h#{f8cpevUcrL=T{Jak% zp&~!dr&za7N8XHDZjuailtTB*U^+C2B};;)W%I74=rZ>U;z1j|Q(uu4=V(w2WfSQk z{~&BZ0hWp?{J}mn`0FO?-IwoA$5wxHs8HwT{5{BoLT>cVAi1Gz`~Au`KL zpoj}lIyo6~3!*NaUu6oau}z-5Tv50k7Uz%rDtIy`s4?1j^=E+RmqhrNsTirzebUY|y; zQ2&g#cU~YpY{Y9Qk7s@2R1tSG-tcs!jIvLhXfrli2bN9)#H7ZiJR;e~EKlrhC%!}R zRQ_2-e5sGC&f^||nVJU-oi~=J+v-KN27yqI0{8vDL2!wP|#8? z`|3lX&fLZH%?>>_)f<~4bW1fZuWW0ugs2A_nfHeBT!`HrCpEP%R`nM3<2GsQq11oo zmh*>)xmwJC5n-Uqk`ZUgNJ$O3Uvr|xcr`$A+rTvFJY~3;Lco1jf!M1~+(fpmXAA#^ zR-)Z~RS!t@7DSEF3uBxkV}AeSWzLN5}RX zpp6-8v?Hqg)Q?b=+934y!F!n8&Sna2Md&Z`jkd=T`# z6gzQkrNh&3p<7FQti&~VetG&~r!|5)e(9}8gGrKXfq58PEbRtIf!p9CwXV8r3~W3k zxb6hnFcV4^{T3F*_gsGa_+}M=E0DhMQm?uHufp6bdt&T8I=t*ekRVi2XbJC~^yln1 zTZCbf_96$MIl8xlUeokaUid#e(#^Au+UE(Xn~}6usO{I(p}VSNL;HUVRH^cCT5d-> zJpoo;Ib!0Zv+4mHB*BS-9}5vF`-h)Pj}*<>Z`P!#9z&M=m#xDFgOPLSFA`ITHXstm z4fFt#_C=zKJmP6P>7Lmcc*r0d+*HWsjBe(M*&m?^z;unzhNFsgZe_wg$swbymEtyUYleIQRfv?r4gq2%Rc-=uFJuJ{o`?DSSNn|N+)X5mDy@RTsEARKM~a2x zpW1yKJy8lWnvPJ^bgbOBo{J3rCuqR>!5fjX)K6LXa@rX;Q;N=0JO|2Au?8zXzq)>1 ztyBJ~+UOy6p5(%a&0qO_Z9rOiqM~uiCN)r*fc6i*fL6$~r0zN;D8d@X8^yB-aUV-sHRJrA`MCMWD!axHz3$E5wHLVL6u_dbEYq?g;3BN=7 z9A~E@3W0Sq`I(>@st6D=I5f44xR>MUzX92Qwa|18-KX9kuh#RL1Nag6#er9LQG@7g zp3x;(1MKp~R-vosT%E5J$R&!-Y%lhV=^HQknsCJKbM8tktR!6`@>!R~PD_h141v5o zmZ4Q+cW2M6R)qHOW_0&Wb~IY0Fo>nt;Zi6+s-N|r;WtrU?bmUJePn4GZ1u-Z9DrU& z!hD^%-}KN!K4QHt&oy9ZLJZv3zo@4R2P zXYk^WRqC*+9t$2_tzLIjZ-2}W$o`O!$o^4-h(66SA3}lgb^PC=dYV@6bWCaUIZA2C z{h93UgxB{;@KU zivSI2P%?h{P5$)$=y}&G<`+Mqj(co5jvM)1*QtT#L{d1?4bO$%#rUUJMplMqbw0OO cz!(<>oaGx5e|@gtf0h6L=l}c${Qu7X7rnBb@Bjb+ literal 0 HcmV?d00001 diff --git a/docs/source2/manual/images/generic_grid.jpg b/docs/source2/manual/images/generic_grid.jpg new file mode 100755 index 0000000000000000000000000000000000000000..935a1de237e0206569c987e0a790e2d89d657ea1 GIT binary patch literal 86702 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 literal 0 HcmV?d00001 From 49c79e11c319172e36fe3c5ab6983f86f32c04d4 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 15 Nov 2017 09:29:43 -0800 Subject: [PATCH 027/239] merge docs --- docs/Makefile | 2 +- docs/source/Lib.rst | 6 - docs/source/MV2.rst | 6 - docs/source/Makefile | 192 - docs/source/api.rst | 6 - docs/source/auxcoord.rst | 6 - docs/source/avariable.rst | 6 - docs/source/axis.rst | 6 - docs/source/bindex.rst | 6 - docs/source/cache.rst | 6 - docs/source/cdmsobj.rst | 8 - docs/source/conf.py | 124 +- docs/source/convention.rst | 6 - docs/source/coord.rst | 6 - docs/source/database.rst | 6 - docs/source/dataset.rst | 6 - docs/source/error.rst | 6 - docs/source/fvariable.rst | 6 - docs/source/gengrid.rst | 6 - docs/source/grid.rst | 6 - docs/source/gsHost.rst | 6 - docs/source/gsStaticVariable.rst | 6 - docs/source/gsTimeVariable.rst | 6 - docs/source/hgrid.rst | 6 - docs/source/images/cdms_classes.jpg | Bin 0 -> 79617 bytes docs/source/images/diagram1.jpg | Bin 0 -> 13530 bytes docs/source/images/timeLine.jpg | Bin 0 -> 13754 bytes docs/source/index.rst | 62 +- docs/source/manual/cdms_1.rst | 845 ++++ docs/source/manual/cdms_2.rst | 3820 +++++++++++++++++ docs/source/manual/cdms_3.rst | 235 + docs/source/manual/cdms_4.rst | 686 +++ docs/source/manual/cdms_5.rst | 210 + docs/source/manual/cdms_6.rst | 1793 ++++++++ docs/source/manual/cdms_7.rst | 165 + docs/source/manual/cdms_appendix.rst | 251 ++ .../source/manual/images/curvilinear_grid.jpg | Bin 0 -> 105315 bytes docs/source/manual/images/generic_grid.jpg | Bin 0 -> 86702 bytes docs/source/manual/images/uvcdat.png | Bin 0 -> 37672 bytes docs/source/mvBaseWriter.rst | 6 - docs/source/mvCdmsRegrid.rst | 6 - docs/source/mvSphereMesh.rst | 6 - docs/source/mvVsWriter.rst | 6 - docs/source/selectors.rst | 6 - docs/source/sliceut.rst | 6 - docs/source/tvariable.rst | 6 - docs/source/variable.rst | 6 - 47 files changed, 8082 insertions(+), 479 deletions(-) delete mode 100644 docs/source/Lib.rst delete mode 100644 docs/source/MV2.rst delete mode 100644 docs/source/Makefile delete mode 100644 docs/source/api.rst delete mode 100644 docs/source/auxcoord.rst delete mode 100644 docs/source/avariable.rst delete mode 100644 docs/source/axis.rst delete mode 100644 docs/source/bindex.rst delete mode 100644 docs/source/cache.rst delete mode 100644 docs/source/cdmsobj.rst delete mode 100644 docs/source/convention.rst delete mode 100644 docs/source/coord.rst delete mode 100644 docs/source/database.rst delete mode 100644 docs/source/dataset.rst delete mode 100644 docs/source/error.rst delete mode 100644 docs/source/fvariable.rst delete mode 100644 docs/source/gengrid.rst delete mode 100644 docs/source/grid.rst delete mode 100644 docs/source/gsHost.rst delete mode 100644 docs/source/gsStaticVariable.rst delete mode 100644 docs/source/gsTimeVariable.rst delete mode 100644 docs/source/hgrid.rst create mode 100644 docs/source/images/cdms_classes.jpg create mode 100644 docs/source/images/diagram1.jpg create mode 100644 docs/source/images/timeLine.jpg create mode 100644 docs/source/manual/cdms_1.rst create mode 100644 docs/source/manual/cdms_2.rst create mode 100644 docs/source/manual/cdms_3.rst create mode 100644 docs/source/manual/cdms_4.rst create mode 100644 docs/source/manual/cdms_5.rst create mode 100644 docs/source/manual/cdms_6.rst create mode 100644 docs/source/manual/cdms_7.rst create mode 100644 docs/source/manual/cdms_appendix.rst create mode 100644 docs/source/manual/images/curvilinear_grid.jpg create mode 100755 docs/source/manual/images/generic_grid.jpg create mode 100644 docs/source/manual/images/uvcdat.png delete mode 100644 docs/source/mvBaseWriter.rst delete mode 100644 docs/source/mvCdmsRegrid.rst delete mode 100644 docs/source/mvSphereMesh.rst delete mode 100644 docs/source/mvVsWriter.rst delete mode 100644 docs/source/selectors.rst delete mode 100644 docs/source/sliceut.rst delete mode 100644 docs/source/tvariable.rst delete mode 100644 docs/source/variable.rst diff --git a/docs/Makefile b/docs/Makefile index 2aa9c4d2..61c88bb2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -15,7 +15,7 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source diff --git a/docs/source/Lib.rst b/docs/source/Lib.rst deleted file mode 100644 index 8f8e34d3..00000000 --- a/docs/source/Lib.rst +++ /dev/null @@ -1,6 +0,0 @@ -Lib -======== - -.. automodule:: cdms2.Lib - :members: - diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst deleted file mode 100644 index d9c3a216..00000000 --- a/docs/source/MV2.rst +++ /dev/null @@ -1,6 +0,0 @@ -MV2 -======== - -.. automodule:: cdms2.MV2 - :members: - diff --git a/docs/source/Makefile b/docs/source/Makefile deleted file mode 100644 index 314da453..00000000 --- a/docs/source/Makefile +++ /dev/null @@ -1,192 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdms2.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdms2.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/cdms2" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdms2" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index 5a561c63..00000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,6 +0,0 @@ -MV2 -======== - -.. automodule:: cdms2.MV2 - :members: - diff --git a/docs/source/auxcoord.rst b/docs/source/auxcoord.rst deleted file mode 100644 index 892cff84..00000000 --- a/docs/source/auxcoord.rst +++ /dev/null @@ -1,6 +0,0 @@ -auxcoord -======== - -.. automodule:: cdms2.auxcoord - :members: - diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst deleted file mode 100644 index ae0cb3ca..00000000 --- a/docs/source/avariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -avariable -======== - -.. automodule:: cdms2.avariable - :members: - diff --git a/docs/source/axis.rst b/docs/source/axis.rst deleted file mode 100644 index 1d0e9aee..00000000 --- a/docs/source/axis.rst +++ /dev/null @@ -1,6 +0,0 @@ -axis -======== - -.. automodule:: cdms2.axis - :members: - diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst deleted file mode 100644 index 84f1d88a..00000000 --- a/docs/source/bindex.rst +++ /dev/null @@ -1,6 +0,0 @@ -bindex -======== - -.. automodule:: cdms2.bindex - :members: - diff --git a/docs/source/cache.rst b/docs/source/cache.rst deleted file mode 100644 index 9904d1fa..00000000 --- a/docs/source/cache.rst +++ /dev/null @@ -1,6 +0,0 @@ -cache -======== - -.. automodule:: cdms2.cache - :members: - diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst deleted file mode 100644 index c66c4576..00000000 --- a/docs/source/cdmsobj.rst +++ /dev/null @@ -1,8 +0,0 @@ -cdmsobj -======= - -.. py:currentmodule:: cdms2.cdmsobj - -.. autoclass:: CdmsObj - :members: - diff --git a/docs/source/conf.py b/docs/source/conf.py index 4d994678..4b1b3e01 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,6 +15,9 @@ import sys import os import shlex +import easydev + +html_theme_path = [easydev.get_path_sphinx_themes()] # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -22,7 +25,7 @@ #sys.path.insert(0, os.path.abspath('.')) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) -sys.path.insert(0,"/software/anaconda2/envs/uvcdat-2.6.1/lib/python2.7/site-packages") +sys.path.insert(0,"/software/anaconda2/envs/dev/lib/python2.7/site-packages") print os.path.join(sys.prefix,"lib","python2.7","site-packages") # -- General configuration ------------------------------------------------ @@ -33,12 +36,37 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. +#extensions = [ +# 'easydev.copybutton', +# 'sphinx.ext.viewcode', +# 'sphinx.ext.imgmath', +# 'sphinx.ext.ifconfig', +# 'sphinx.ext.coverage', +# 'sphinx.ext.doctest', +# 'sphinx.ext.intersphinx', +# 'matplotlib.sphinxext.only_directives', +# 'matplotlib.sphinxext.plot_directive', +# 'sphinx.ext.napoleon' +#] extensions = [ - 'sphinx.ext.autodoc', + 'easydev.copybutton', 'sphinx.ext.todo', - 'sphinx.ext.viewcode', + 'sphinx.ext.autodoc', + 'sphinx.ext.graphviz', + 'sphinx.ext.doctest', + 'sphinx.ext.napoleon' ] +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True +napoleon_use_ivar = False +napoleon_use_rtype = False +napolean_use_param = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -73,7 +101,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -118,19 +146,18 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. #html_theme = 'alabaster' -html_theme = 'sphinxdoc' +#html_theme = 'sphinxdoc' #html_theme = 'nature' #html_theme = 'agogo' #html_theme = 'pyramid' #html_theme = 'epub' -#html_theme = 'haiku' +html_theme = 'haiku' +#html_theme = 'classic' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = { -# "rightsidebar": "false", -# "relbarbgcolor": "black"} +#html_theme_options = { "stickysidebar" : "true" } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -144,12 +171,12 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = 'manual/images/uvcdat.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = 'globe.png' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -186,7 +213,7 @@ #html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True @@ -233,6 +260,7 @@ # Latex figure (float) alignment #'figure_align': 'htbp', + 'classoptions': ',oneside', } # Grouping the document tree into LaTeX files. List of tuples @@ -245,11 +273,11 @@ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +latex_logo = "uvcdat.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +latex_toplevel_sectioning = "chapter" # If true, show page references after internal links. #latex_show_pagerefs = False @@ -301,71 +329,7 @@ #texinfo_no_detailmenu = False -# -- Options for Epub output ---------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project -epub_author = author -epub_publisher = author -epub_copyright = copyright - -# The basename for the epub file. It defaults to the project name. -#epub_basename = project - -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. -#epub_theme = 'epub' - -# The language of the text. It defaults to the language option -# or 'en' if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} -# A sequence of (type, uri, title) tuples for the guide element of content.opf. -#epub_guide = () -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Choose between 'default' and 'includehidden'. -#epub_tocscope = 'default' - -# Fix unsupported image types using the Pillow. -#epub_fix_images = False - -# Scale large images. -#epub_max_image_width = 0 - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#epub_show_urls = 'inline' - -# If false, no index is generated. -#epub_use_index = True diff --git a/docs/source/convention.rst b/docs/source/convention.rst deleted file mode 100644 index e4079a75..00000000 --- a/docs/source/convention.rst +++ /dev/null @@ -1,6 +0,0 @@ -convention -======== - -.. automodule:: cdms2.convention - :members: - diff --git a/docs/source/coord.rst b/docs/source/coord.rst deleted file mode 100644 index 0cb886a2..00000000 --- a/docs/source/coord.rst +++ /dev/null @@ -1,6 +0,0 @@ -coord -======== - -.. automodule:: cdms2.coord - :members: - diff --git a/docs/source/database.rst b/docs/source/database.rst deleted file mode 100644 index ae772ae8..00000000 --- a/docs/source/database.rst +++ /dev/null @@ -1,6 +0,0 @@ -database -======== - -.. automodule:: cdms2.database - :members: - diff --git a/docs/source/dataset.rst b/docs/source/dataset.rst deleted file mode 100644 index b59562aa..00000000 --- a/docs/source/dataset.rst +++ /dev/null @@ -1,6 +0,0 @@ -dataset -======== - -.. automodule:: cdms2.dataset - :members: - diff --git a/docs/source/error.rst b/docs/source/error.rst deleted file mode 100644 index 8b37e9cd..00000000 --- a/docs/source/error.rst +++ /dev/null @@ -1,6 +0,0 @@ -error -======== - -.. automodule:: cdms2.error - :members: - diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst deleted file mode 100644 index 18b3288e..00000000 --- a/docs/source/fvariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -fvariable -======== - -.. automodule:: cdms2.fvariable - :members: - diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst deleted file mode 100644 index 41b08364..00000000 --- a/docs/source/gengrid.rst +++ /dev/null @@ -1,6 +0,0 @@ -gengrid -======== - -.. automodule:: cdms2.gengrid - :members: - diff --git a/docs/source/grid.rst b/docs/source/grid.rst deleted file mode 100644 index a40f294b..00000000 --- a/docs/source/grid.rst +++ /dev/null @@ -1,6 +0,0 @@ -grid -======== - -.. automodule:: cdms2.grid - :members: - diff --git a/docs/source/gsHost.rst b/docs/source/gsHost.rst deleted file mode 100644 index 4ed66a10..00000000 --- a/docs/source/gsHost.rst +++ /dev/null @@ -1,6 +0,0 @@ -gsHost -======== - -.. automodule:: cdms2.gsHost - :members: - diff --git a/docs/source/gsStaticVariable.rst b/docs/source/gsStaticVariable.rst deleted file mode 100644 index e173b1cd..00000000 --- a/docs/source/gsStaticVariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -gsStaticVariable -======== - -.. automodule:: cdms2.gsStaticVariable - :members: - diff --git a/docs/source/gsTimeVariable.rst b/docs/source/gsTimeVariable.rst deleted file mode 100644 index 3ca7de75..00000000 --- a/docs/source/gsTimeVariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -gsTimeVariable -======== - -.. automodule:: cdms2.gsTimeVariable - :members: - diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst deleted file mode 100644 index f39233ee..00000000 --- a/docs/source/hgrid.rst +++ /dev/null @@ -1,6 +0,0 @@ -hgrid -======== - -.. automodule:: cdms2.hgrid - :members: - diff --git a/docs/source/images/cdms_classes.jpg b/docs/source/images/cdms_classes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8084dd72a7ed675c935c7ed1b418963e9616d8c0 GIT binary patch literal 79617 zcmeFZcT`hd`!;y!ASLt;Q9)1vL8V9yh%`}9EHnWXr3#3E1PFwV(juU!w19vph>@-c z2_39-keUQgx+Dl8kdVyb`StgCzgh3hA2aKlHCZ_;$;r;y=id8n`?{|k<_{(T5Ik#c zWe%`_4^)sQ5u!BzyZVnE1c8+~qT%6o|`}p{H_wn-b3kVDH3kV7D z@(PLz3W6R`4D- z&M93z(=%q~7M50LFI~QJ)!xC;$^F)C4^J;|pP=B7`=Ri#@VNMd#H0rglQXj(KgoXj z?0L?M;*!#rWv^bBSJ%|m)i=EV(Ad`A(b?7A^Xc=z;Lz~M=#Q~+;>_&a&tLNki%aD7 zKO38rE$a5po?I*d+rNqRpOXE9Ttc8+tnBP;>|A?tv9N}M2b&N($AROV!X_8FZUl-P zJQ2e!dOD-1s+C9Kq#a4@=Dq%X;)-nfawC)%;B1Bqobk;rqTUpcn~Q@%N^>pO%#vUFM3klHVjIv?kJ zg@~;4$hd)7L-bhltW(VSgq#S94Hq7+b16)Vs5#zb$C z522ZWY$>dEzO|1BCT<`AEFp;sHM30M;6#hWNWx)Akq>~#*u`{LQ!fR!IP`VP1rGy3Cuach-D1^7&O({m9y(4nrfxG6V3!GG5H48v$&WX z&yIkE0?~e~2vy$>)%Cz%ei32lgT4{xb3&Ls>=UG=b-}l;Y7}|Ve6cb3O zBV60)rYmM6>G!dIx?mg*ipjuA#$6H*{CvTMj ztfzMDi+n?I)l47}S=IHL7{ET>Tkc%hSsOrf2-VZDlfwnBL!L#hgcL$9Kx>&mYqc>{ zyot|BYOkwE*xKsh-7>6zNDSGtr6VQ}*=FU*1iDq`QE5^7R5nrkx$^?jib>fvpK~r^vwi#-0DcCgm&@(15UN;lofMNo-B87kN z=&!Q1YJ9r!3jBBtLOo;3{z0Y{^|N6=da6OeP{mIj=b?fU_hv{3a8uPnQmEO!@MBGC z(mbN6M90Fez#j!eEK8<)N*#`HA|0QHuAgw+++YIEr=te(T#7WDID!vvE9{8geeD`b zm_UwIbmydJ+$e;@TJ@g%F7rOL`9_H9Bj~DmJkjH;g7@wc>4yP2e3*(ML5O~+w%zdc zL1J&bpR%=G|F?i5XY-zWdP0&1qYVez7!#MPW7j{=sC=~Qvl1npg3sBVkaDy^OdAzL(Az2H5mz5@t?@mAiEN z3C!^DHup%i7`p8^7< zKgqDkHeY$KH3%L1LexASYa~I{VUtZ`9fYBNFR&z03aOgM(J4_JQm3F~JI8y-wbdhg z>cWPiIva6*QgmksTN@Q)=(QMhlZhv>8QIM^K*G1%M!P`_tRRVFm+Y{^nialq`pP@6 z0~1112cO*e4FrzllY_d@HEV4!?rSbfcs>IKznQrz>*7Ld;zXFdZmwj)T)MWIzfF|? z{Q@sGyv3?1$t&GRjVk&FwJoKJqps>Rq>+T_862s;iT`~Fl$7Z>hn#cTX0*>BSBiWE ztH@jlbpBF!`jnIwzY%PoYV36I0T1J4|I1I@Q{%q*U8A;BY^!t6C%bU9tOmYvR-~*H zh*~%*giOA%Y&a0gl7W*u%r=JHa|?+ROn}$7Wuhi^&oa=vG8S}A(1x0ea6~`2jQ0YP zs94j@NW(m~?_vnM?fXGLol6NPap2n1%qjX2Qa=YO6U#L3ao)=PyiU1ZKEF1f(Rp8< zgKW{FE`e|&d&UG9$-JWG4f+yLWw9LZ&!u7hx8B10|74@&jkF=PJ6%=*Ifs1h&7Ty z93nTQBAj20BlM|ZLGDFXVzvFPg`JcKF9S66zBB^QIbbol*ubt}m8tH`!A1-#dFnNq#vpCQKdp zTBXQ`ES}sMt(`m;*cG&%RS=7{-z}l5ypHN;D10E@PY9=sM2V)*&W6!P(r#f5jAOFY z*2~7(f?HKa-*FAB`|kLf_vhR6JFcIce`ztAvn>q!QG7-(VY35!ta`nU-|fN>X20Xp zFCQG|_$40&BUSy`bi4kzW{`@BThXw66Q50IWPK`M^$7EPLUq^7-`@)o};Uf+|cYL=Sua=?0Z z65e}hy7{H;SX_$;B=`Ks-ohc}Zbp(N6R6&5-(q7NYPeBtv$o3f2Tl7OZEza$gJ%AY z+?6}yi-Sos9Hbwiy!-C z&idxgJT-C;NKFblm>1a|t>>A%bC>bel|?nEbW&&`V4exgG}QqXac zSrkI}II6Y4H(!n|tr;vx$!v(6SN! zFS}{Ss60`d3A2I#Ux?J7ZVWieLbH$`yPM5HSEcPc0eA{0*>-V&kekTW{zkL4Z&*hEB*QsM`&r&Zl4wJ8oBC7Z$YUZ z>MT;c`FhLx4G`)xTRet*2}yizz-q&vFdG39LpZ`jhgCM4WOU6L^@`I?tf(^l_y`eZq6D zV4;Zf)U25=H3GSwuY80}UN~R7X5JfcXF&f%v}AOdP$)xs3!NHHc@`y3O;sxP*{!w*9^#upHo%A{K7_o2DzWI4vq=^r(gca~) zh}p+)$)Z=jAa)T|E>G+Rf|ny@Y#OTS(r(l>n227)m|f7|xHfs1#j9lU@W1?W1bbbo zSF(_+|Ge;#@A?sTzeRysJAYCCe|TY;h1Ds32_VAw&i<}?0Z$xz{*1)+R4W`!`Tcn5 zN}Y<1l!4~r;Gc4NU6N7?S;k!Y>PIhi)ibfzbCVwt1i2Lo;zxyXH4@RHRnmSVw!3GJ z!KjVEA7@nbc)`<3I2OiFw?VZ}%agB`YF9+nGcH~0R?U>Sn+bh(tKmYsz>>2x=x1tg zq@cF(`&q?Q)3*B2`T}*b*{8ai0-5bC=Pu4$dHItZhd7brVy2WZsthp_(&4I1^_;mf zbZj$HJOF0%G4kwP|Jp4N!F6b6a=FYdc_dnkZb;K!(s8ngqaUB?eUR zhhCDvM_|3HBfD?w*X~m~Ysb7TRxavy=_!V-Y1CIER(~1WrU}rB9;MD^E&l1_Ql=g9 zvS^Fq9jU_zS&N|_&@YzvR=Rcu28sVXQFWL5>e1uPjaNrkwgdU`DU2i5?4Jz$-hO~c z_2_20ZWh8kpe%ZP4z2+gINdJhp*z-oeN<(}AGOtmKGeb?LK@~oMi}y#Q?VrqRzRff;$>ovbj2FL+a zHzN%u@Iq{MjRp#aTn974zh5!uFk2^%h@iGJ9@wLBYm5vg@M#FywoOjj6~sW1_+14i zkX146RR|FW*J6KWAv*_LjhFy#$ASqcgR3;&`7Y?j>840!4m$y> zrf-&ZC>14+2r2T{#_Xp*wN{kQtBMNykDsJ`g}$FMR9TQFBNNc;ckz<2<@78jP&jpg z&3+b_%F0LINB%v#Rb`Zw$^-}@>VKP#!r;>XJ;%=u*|tUYzVVS@kK(*%1plrvR>|&it-EYs`tXje8G!f*uKlOHLCr_a zC^LX@Ca`X%Z@&AnR?gE2ZS}N8UTaX@?tq5#M@g%R<@hIQktVLkZ-dHs3CRSmLwEBJ zv+a)>Z4{(U3zKi$;d?UJ1=~34M)h6gVkAI89VP%^Vz!Kzz>R>W#LJMTnJ|GOi%uLB z07D;)h^d9{h$5VsKr|Z@NWnyc>iqvV`r8ncdeZK|ZJ5A?rs}wM?2(8H!%72{ve-`_ zPjUUCz@9{kxvG=O7}i@|kS$I0&k$oN1xi!jm0ZRVsQ6|tJ+7MxNLYij99hT&`if`p zbO1_si5TD78GOaog8PR#DE@~z+8RIn|7fH7l0pav2qR(pkP8>d0So}bIEMO1eVTst zAB`GO+*FLw4jk07^2*Uw4AEDA!de$`awh&mqu--q2bSh$PFHOFZjiUghk{1p0UU0AAYJF?IT$Ni1Dq0t@HJwhUIYJw$A5^e;nlV@SL9GU9vpZeG!ieh)?Uj)3im{MCO3lKh#H z48|D{;rgGyJ`4`)QxNDZItfa{BLRY|7%x!9f9Yawlt8T1nX{s0xe!lYT@Mi&yq?~n5>LBTK8#JLI=V==g;P9qQ9~qb% z3Nd#RFw-5RaO+q+AbKoob4hNW2O@K#4#N$s;%2@HvYz~2%ndq8d9dSY!5iJl8=xl* zltfa?w`p!<^vY`@ZQ)J;LZ2{^@=#dEtd3MZ#hO~uWo_Z#!pgGbn?d60QXk9hl$Sgo zaET<55bPXLvF)dN@M)XnfXh+Y05eOOdyh=$UTjNiR7b23s3e#(AjFgkqhA4SYn6k{ z)vgoX&=z)pES{lxpP^ZsbJcp`*$du?M-IfsTd42Vs&q%%5xkGnRD3vBtlb~8hcB_o zZoG;fidXkpPWkKHGu{pwX_}u2?G6|#YwhvKMGku=m(~qI&vjz%YxaW zPothH|01|+vTS~J6Ga?s`Av3BJaK}1=tej3&jq{){h(k2{ZQj!jtA^+ZAgmG_DQ08 zijgeB5lt*j&m#G@s=tQES^4=oxUE?GHTu05BnZ3HzIzb(cH3Rn;U6jX*1baGa=fh> zR>b$Wp4z3+HR5{C+)bTq{d401^jLTw7Z?uPdPxtU>)H#5JU$-{@*@4RPA7!>^%N7} zaZRZirJa_Ck(ajf;DeNV?}z6<)RB6lkwo#T!ExHfOt*cFQ)f!bvWff{mDnkP@ayt{ zs99W!Tg^yZIh@r+y(Nlwm~J=|n*VahzWwkwz6;wodLQps&-;vSH-I0^u(u2Y17L?*x%r3Ak>>O#WD7)X_ShpIgLT};}n-nnafMp8ap z5G)GtmvzASeRM94k5RL%J~ZDG^Lx>pHuj9dVx>zMwR|IIA_vj>5)XFO6_G-;6}Twv}0cQCp8W{JG^R=Hk1u51C! z2E2#XDmQ3%68`v?I*ck$<_SCr>pp66ZMG7QTy=iwxWtepMONctE@WH`z7W!giaxy_aF=03-E6 zdG|evl7{O(i{{be$1njIjKXe7Ej|IqVQ~EAw=%jC>3+?OoDJDeb63+VyEtt8>-Q)d zQ9l4pNdO|c=^$3kRe&TO>!TXXUW{h~D`1A+M@rsZ6I-}0(xoNY7(pK<&mpCZ*xKJ9 z^dw+>24bG2aFmIk4`Z=OpAUV*eNJ+aM+ExpEIlKpCaVW?nyiDu-G=eur@gld@;ch1HN9Aw496L``3@fvw{A@|* z+>Q#FH(bWNBYUn?zJA-R>I8{3>6a6xArpn9we@3PaRS%qmC+v-yx68?Wgf4J?vG>UmAUNjniViEEUc}0iL?*{g zRpY0r*SU$u^@_K1{T^O=dX4Y)hZcPsEjl!Urb|V4YQRkpP(m(7f?XxZ_crmim++OA zM?6lG$Jk`=nG{06$eNH(1YO+8tI1J0dxH76QJ^kSa?%v`YtkBgMycMdz+3US^L9`HHX~RNX|5(TI`xoB7SF zd0RW-*1kc)pZJpfetxdjIFMw+T?h#Qd(9=v%2I30dQSCHQla!K8gx6-LjaS!v0r~} z=q49wyF!K`HA{3NKoX-Mit9mzU@}f_Oq?Z1v^_ZZrf#fHwhBSJ-9K5lz?^4EgbZulp6$$0mc!NFmA;O0AP>Kn}W6sFq$HBEQ z`O11KR08HPluwvY?=EP6VVw36mm z^uuS}OCECm1U19&-n3wwb?U8HzefHqz0E+RWRx=Xj0TkSWC5983}FIdr|Gt&xO4;O zqIG!JUng84GZ^8hFRo&^k5yPwL%h>c@9y0?5^7vnd;X_q`qX22h*YoGT$CvF1F3iB z8#duKX_nv?U*{&eEFaP~;p4%rglFHY8vAl7S;!_h@sOD>vY($+HO_fk;C8?pcKyWl? z#u>g^87vdg*=*Uv=@oym=8i6Vz`ncY#ubJyrHo(hh4#TkWD^B3b#$mVHm zMD7f9CHqtGVi8==U9@W~-c?u)Yf>QL*YGV>HsjH$PjmJKaFLm0@-1kP^gqly}UF;+0&~F z=?oYvr_G#^ht`lF@jnNgEu}lgKapxx{ABqqxu2B0r^DGZTU7{oEdjbCXNE^JBrcEN zTpqnO3<2Gd%sp_nWBM{)od#n+NwUeBc69d5neF@r?sFK;pO02) zdt>T%s%7L+TbbK;{j)2R}q9rzf2_Sv?)TU6`EjnAIQCzaMfHQ+pnzNo;l0|mKl4R^cs;9 z0rK$Klk+Qw=_2l*!g{H3*AC%V{*X!ukCAP4 zq-Ys|`wQBI46ZM4BPizwS2ys9q4o8T%=~->>fjls``9lV698Z~8K5+Rh?!vC75+=k zHGQi&^B0@y-_>4^V3UJP-g7B0f95m zfP|`ONV^-?yV7081uPhbRv_qQ+IF<1Aw}~5^jyBVY8DfSwC@>(N?=(X z;9Ko_9>t{PR&8mevO=Yr(AUT|eUWW>&&M~RifYlOFlDx%vZLNJ_y^ExRQx8t^|@x! zTHO4Q=4ODNq=Diwv9o!CE^41WjW$>|^yn8zaeQbouVjmW)x%-nYOA8hNRn<$`qt1L zkP<2kM_E~i4W3=U9kCGGbJ@keb?W;Gm>vO)!IrzZO)f+V7U%gK9? zY9)R1fk@zi{nwBGQjem0G}NMGqCV@5WL5aw&w<7kj9OXh~y}vi;h&V~rbRxMb9vx!P?$w3iuH%z?S^o!w`(0g?-P zhroXM@fL_0!_GmtuDi41gF;mz;cC~ldo10ETbHp?Pff`q4MlF=Fcu?uG^bCEd4Kcp zlgHtOwYOD|HO0O^lGfxI`qjwwJ+SkJevuTxhm!D0<~a(X#OwC%ZrZ>^nhwhBsp$3a zzf=@^bEGMdb_##Z(FyL^j)xq=rEpldump8)0aZhX=l1OL4m?CbT@ z^h4NHo(!t=j=t?R=hGKYn_oZ_r-om@z_Dit(qp}ni_=)d;3o7TPB3aeeB_H6xfGjF zx-c3$Eop;hFXJeIh7~LBwoYT?Jb>tk(G-Npab#NywIa2|{i>^ZnEuN`z5r1ZGH>fu z-pESCt?GC69^5Zy&(^tt;jWt9QEfFj*K{ySky>Vfx;TJUcXD%l&*51=P$}sywH<>} z*;u|7y6Q}vPnp?jLyP%3oyoz+Y&;CGx2s7OxvP->l~XEbzW_l@Ne(i-_$>^RvKh8o z%P+sx+9=;ZfF+INANrRLDG$DQx~ju{&;9uU_S%c@RPWyiY#G-FBG!^L@edg4gWrpa z5pH$38b>FkY&Chj*KOM8lj86{)(&beuL&=N2Rpeoyxt$oZ= z=w8~n&pK%S$0}eR&Dvsl7m&TcHS`XyGPC;ih=H4^-z^K7r_$%K0}$MkobP0vBqI%K zMEmG?4#K+OL+1EN^~b@v*DF`iN3p^Eh)d*`cuIWj;7e?FZ+oAcbEmua{`Wjug~D8? z&K#eMS~j{N2k+IQ^mY`&h`?yoqpsl(@^OpC{M3sx&b{IYEmBtvQaL{|@&@0Z_r@Rd z9|;@F3fTG(o34dMjX(u#F$p1SyU>@T)+FwE!qXTB7W9hm9r?*Fl^k*sJs;JMriuO4 zppUCo9a*V%aBFAaf0TY$TZI|ir{MT+ zXPYH!lAk>Hya!yQL=;$QEzNg0*&yeRc;XqZB6MG!?rETpq2R5th}~c9ye#SA{N!}! z*`C5^6L$Gj--pl|^=Q86{G)%cL9efcz(_D3U>17}!PXb0L$@3Z!HZDqaxMB-p9eSV zbzhEfQ~KHV``NSS*3hSHfu|KYf_#(-^&^GDBg^1Xet z6m{>W&F**pNDC&w*GXamjF?a)^~8J7gD!w**i9;kVjF+N(WR~-$-yjtz9p?(@w_op zq5o0+q4G&#+Js96GiJ^6uIOl%99srI>wupD zM6)lA(`nK)OdCU%9;aRQb+{h8?%4foKz*n8)a*Rp>4MOED#LfMte-+>*ZASZokoU( zb+0#uKR&D_Ju9n^*ze(>^yWw4lzphq`+&a zm9zPt)+EKPakGYazwt2T^JgO)biTIVjQsN`Ig4%Lmnh2;x(2s0K?E_(MuFyi@VB6a z+Ye{#M_qIrsw)vn6f%=i))zH8zM?nNl#ZteCc@QiD#!x87aDO@iET@S&lRfuq``pw z{GDS8y2@1FDXbX%5Y-!`8HK|hRBA?i2@Lf|9jaLpNsRd%+y74Z?q?hR5cJ+~fVhT4 zC=-ZNL4ieS1LtmZbsZ*^ejDR^wZNcyAYpg4LM@M9+Js^$93uX;@H%GgazlNSBcc|q_b&n0V9{`De|IiN#htLAwI91;d6EcnRHW4{)f4lN|BuE;O5zwrtj)c{|g@HBy z4(gwZA9#2!fqs9qeoI(ARV_dB$dw1IJnNQRWe1zT24gh(k)8pp3*p1*rQRj)uvL$3 z*=t;^kC?a4`MWQ>7JL{#IXWIK{_j@I`9aF95{_9lIci!2KQb3$<|aCx`SmWa?uqew zc1ucZ!n!=)MExIST3dKxTx zpE2;iu&Z@S42|!6=?}v=#Dywn-C7k}$XBu{+c%1XJ^#CEl0&&jk8*(4Tjb66>UGVo z+eV5L3!fBEw0h;7?ex!7Iq_`TtM6z{`D^w^R@3*+M}oNfKQ-k@y!C(0rTmrRsBhsO zxfKicrk&xDwT+Mj&=%zfN*XePJXQ|i^;m&PL_+KGXldB@4BEaiZ}PRtDJr9l=91{5 z_iOzA6KUnlY28Q9`%*34zHtSq2w%k}k|kOoi3QSqYazZ9ydCxRsh?MO%L4m?q05HL zzc6fc@oEz8fq~&HTI5(ELx!A(5v+N7@x6l03BSzIyZDyN!mqc$6$XW0fsnt7>8Moc z3P*RS!LALj2GhRWnBNX85uP+q!x~of?i3FNPP~3AV!r!e!;Rkse$sgW0bib3Rk?KD z`7-w7(6m>8f4zpcLD|jd?EAX=AX*!I&>H3T^)kjG`?#?>m2^Wa6Y$AmNTqe1Q9)tedBC5;eXdSp7AE0Yg%8B(oN3sK78Yp7|PB*Fj`2NvZ@pjww%GFYDImfxoL;G^q^96P2-EVMP-=| z1jt61@5lGMPov~|Ma+(&0#*IBs}1SD%a(X&>q4*xsh&i<1pMkm`*=Y?%>w1;xeFC1 zM8~-$Z^R1l%w6Cdr7MP8jhnx|9jmun1nYY5mU>?u>^~_7msD#j=HwOHm>Oj}QT*Wo zxr{8P@F@J=(ekLTNXUJ5=_`F^3$R*$&^$p4h9%9TS3Y9?BQU^{VFYx6r1w{O2pLZ~ zmZ6k%EJdyPcj4%v;?RV2{BiVkC87NHy;6%#()gA8I|SU2BAJpEh{30Lc|@c*-%cFo z7B@@t>p52>f1@2JV|#^p0sE(s;eWb9b+g^fgQO;>4RJT&Z=1tgi8uRJLsS+s-X07A zxgcS!e#Ht#Pi$vwR~*Zzqv!iKe4%n<-choHnwJL-3^bU#UkeKhArMj7Mgh&+IXi5B zQ;7b*n-W{s3eH2OnahT36Y~OLT|J1(^INSl{#k+zqGz z+<#!UeaF5--@!m>RAUKxJ?nF(_o1{~mmvo@hDFb|9Ie+~Y{9(1;5?y8(vh_d_S!nf zP4-Esjz4Ju1WM?e>zASXG?!g$)YDFyyoSXDs53e=i;&v(*1BH5DQio{Hrv~;*aikE zhShxr>V(4vIYLWX)U?~|jRj?45urc^pAM@9=fsh;4+-bWIW-Ihlk3W&I>!0r zxyS(tZxJD~+2LI&Web!Bp1T!?-rO%=5+u++ho%bz)r$0pts(!FFsSQ|dxwovdmQdj zH|uaL*tg=<+YnzFnO_NS?F7HDpT2VRCy;$E)`GOT>Tmla#jLrOtP~eE`!lz#@q6j9 zSCo5hQl6PE-{u}Fx#NBcTk=c>eQb{8_`9b4J^v!;C9UL#RGL({xWXq)K8$Ed2Gev- zn(~^;iuZs1C@Q)wb3*-lq0X1lEZ0AzldaJvaa{Xvd7nPm}23Kv>4>MBOAUV3B_7<+VK z_jwdl@j<(FMpogx=;z6?M#wI-%4jTT1d6(w_5K|rWacgxZQ^Z;zLG_ zmyUpIHs_NZY!1 znhY#T9=#t{MeQ~zQ%AqS#E`dlA+yj9{)kSa{p4J&c1K<{;pyHhnPaLZy7!Hok6HVn z6wn`Ci^1{zMB4HJomS};Nx(;k4FqDqQc$Zf~+Um-Wy_ zuAKNnHy=c2OzlZ*Tk4lbmG6b`@r-}?<~jts8B^{PrQC#kII`n4r1mm)nqT)uL(JFo zH}YP69LI_@1R!{S-v#{NhT3EoOnPS-CZQI~uO{~r>tDi*@07~7(>@~w>Q#el*GY5X z;wVMCGPYvh!eJ8^L38@7T8-_0t^&`}Vv`ZYy>fVVQ!Fh+4O|}2}B-7S4t=kvY zpHcTE?8Birk^1K4PBbf4k_u~=82|p-J(T0g8`oQz{5EsJi>a_nIolW_zV*F<#0-v~ zI@)!AtGJz^|712&ckQQ2=_jQzwF`7QP;gh-FaZef#H|eaVW?mw)`c9Jz8W&7rN$X~ zboFwlaJOQwNDpas-~BAXo>L1ND*EmC8oA&3Gj9Aoqd38h*FQ-k1;I3)BFh)qW-Q{` zkIU0quh@RJg6i0CL|oW?ZUn74&iK-}e;q=30+M3%LjQ@0vw~ynCg5wtMenBnwV$2x?bKUK*_iUYfIeS05X=M= zK0j1lotWYmIc|lVg*S=5+ji4hSb*tv<$q=j`RjA);JjQvA6cYrf}2a;M?(1$TnqpasP@Fi-rPwhP)w#?N`=br zJDdqiV%!Z(qTMFW=AkxaJyD;V>p!3#MCnvhLkO#G9Zw&f5AuE4;gKyV8gOGlM-b)& z{CVkya{qOPiflrB(0Q7NLQYQ}Cx)nn|`*sZMTyxs(*h^u;*;l2wIBiW`@iSs-#jY`_Vd|6Vfv$cu z6?4eSHsLn=inI%ekcRmhOVuEZsThOPAlsPJaN$ac^@7fk737Hh*HJ7F6;G<)8JTIV z`(mhKKPo?eRr|u&H7nZGZ|ZdCgQ>v*obeOxJ0!zElhkakM79D8Q)B26x+pmT*IFUx z|1B6JwcKupjo6C#D5)USv+|WD<^~9d^RdLlxMqM9E)}j_9#>_MeB=f0r)s45l__r0 zy~ZPPdH@+s^>%jMIa@oNTmb33_plZNSw>1 zl95i=Q79_hXT(MhdD;QtUSJ#= zJd;wkRG%@`a_GVvp&^Z4Ece@oVHdj$D?Y<+-*u+kp zZospWA4Yk<^34Dx71-70T${nS{s*sQ%%nZPf?`j9u2t;ls?^h0$9d|upl<7CCjbwK ziBdoWQj>^k>K)-%9}+|dLsWv_H%QoTRUGTOU{0tK>Pt^-NGzrqAMd8X+R@z?aUf4g ztCXgC09u2OHowc6=2Iw;ccyOXy-_X8A4nG@i3vcBRH^b??I$4YUW>u@U*A^`saqXA z*{wl#D1h!h#~!18u^J9Wf-Y4U#NVrL9p`mE&pNFAc4}%|@o;$L_zv-s&#Ui&lQ{v8 zgMOr2^(=X@)~C5E<(HZGstrzC3A2080Vf~n=iANKb|BE&6MyPrF_>QHyV#j3WpeK@-PQI*To zp^^x71=vYW1y~cf@n^J89Iw`NM_1oGXwel$vjY$Zh(%1`5=RwSdB4}k0#;mPX1Z*Q zWK>=egd+ENVnx`4bcdrRRIlPmyxCtov}j!e!dB^cWDxZN*LRq(KjSFfj1*Ny+#;!t z-wJ*Gv+i3Z-8q&PwS{VHqO~Av@SrOYbi`9_J6%;9`{<&Y)D=Rlv$f8tYy9P+vV1Jl z*l!LbP8-_>QSQg?(Sdyh=Yi`8Bhqt{dfWyE1c7YjP0eO-sLr2Yz!@;U?* zlpaj(O$hdj>NY3sb6BeP4rRUO=K7}aM63=A&&AQI%GTG6zEj{n0G)PlSOR50)bOM; z7%B^4q#`UdZw`55JaCa#im@C=Ht$^EN=14{^+7kds6ilv^;csH%F|VF6pfKdFzWHY zlyHR#o7My^4&Jxdobiv%(f{k_DfOU2Yo9Ep>k{S}r*)VB-Q%&3TP*-v=c0mjw14Z+ zwKr~e)*P~x2EacIA-z~(a}d(}9>BQQ{3*?v5)FD^&?M-Rc(5#=LqR~-q&1LDUTj^k zTAUYThmEcaqF`xEfC)&w#Fo*F<4^TtWx-0@jlbk^9sKL^l>nlOj3JhF<5RKR0RkWl z%&m>$dn@m#y0#{;B9PZUSn%Yh9_XCFEwmOL+D^D6x=Tgb1I;jYj|rNPUop3N7~hP} zrMOnv^hn>ecBmwK`u59b4|~7GB9o&HY;DM+os~wPdEH6Nt4fE5`FbO`J@?0nlR8?W z18-#kN&Ok24cWq-)%dr`fY^BwaeeSiam&>!cy8vgje#w)Yq<5;F+T(L4=7iRFlBsM&TnADD?nabocYClr z>vHKbnX~S#nfoiRh6eNC#)q?>+wM0J@AhpPm*wmf^im2*m-T|RM|s{9bDy>n>VJzm zHFwK`UhxfaAdF^2m1lfjJ4d2mevN4_-w1i>HmRyMmT~K}C@mR?U89WRaMZF2s&v<= z_47l{3mdEE{bfd%-|4BZH5_J#o>cgP-?9npLX5WK8s<|BSU~EX9wtS^bac~sN>___ zuEE=Ai1Y*{Ag(E-g1~EdxLQs;5-_y3#_ghO1B8@5dJ?Cc)a+Cq9=rL-yD_n6>bslI zo$*4#EtYhy(i`fDFptYM*~18h^3tZh-5krOwnL|%Rdb*7ThP$Z6BuF{I8XC+=_XH7 z)ixsd^{xFZXu9&G@1sHQ@U)Kg;TPlgH$3=zw!>$W24DfJwlnAi`fX@Z@Pg*Vj}6~S zi?fY_pQZ7i;6o{>k3Ako^Y7IOHp4Zfx0FMBF+)d4bIU4WG7q6^mwMzsdcW#5!J?WKSl z#rPBc6d$iK|Glq%F!t1nu_nt()duX6?aRWh$nT(s+}qoo)G*TIMtKcZktM(){kyNw z9rh=yTz@;s_n2j6c_g0pB4PP-WWTWhxSIXjA6WcjUC4Lbw-e{>ispl@gn$AKMC1Sz zB)RMovMc{T>Aj*__-!_j={zdIFmD>ATmtvGAV{#?SWxtSU)LvZ!O$bU#dwcf*ZPI4 zM$>cWV?g4a1Q#R43E0f}k34Yi^($GOo-+P)Hv-3q^|h%num=ARf>O!^T)_%UVGi)8 zckB}5d<8LdH|0KT=YYyE$TMEY{r%kkkqu*zp}#xUDDy)4Kd@)IDrK`p!#5WQ&jx8sCO+_I}7?HZUmH^K)Q z%@&Nrx|I{bP$%-*_&nqMU>ACG3AUkC2yt!z|EBsF9->3W=Ix&YmW#@5{l3kQ%N|7{{Z)nO$}QVfNA<;pq|m zGU+3%0maNKf>Q2lqqosPfaE?Rov(8ilXq} zbLFBA)3m4`O@~5qnE(sb*KA<$a-@!J7~I7+*e}k;o9CH4!#IEl+RZai2`I5BMHuvjOzfI(`nkt6N%zYq z1<@%>GKF0y^KyVK$k^75ef%9PCslfSw$n*bLda|6lcL>{Muh_R=>FI-&SnThyet;C z5YUGtd2)d_=f+K4o_!j-A?Ms#vk2vml6G4d7pM&mI2fsP;1#|{+W4F7Y1QjtVY&*h zF!vkCWh+%ixL1q3#c(PA6+4TkUr8(8QtLldW8{jsJH*`@ZGyT$9w?0H13!$~meqv1 zZS%B(O9?x$(mzOY+vVSZTtoKQ$YasrSPNI<{KIY_fZAmqiO{>ro7C|zo=>kCmw;fF)WQL*}yn5z-T{0Agc=tA%(_c<*Di&1qX&V zO>W;yYOj!MI$n;}8n90=jh^6SfrUpKy@rVyh&ChK3e)LJcah{P4JE#f{sO7i2{fu55?6b_jU7%QCdh^#c-}xJ{(vQ|QczaSq zh@uIiH9g~p>H%=~xXRBdt{HsWdEXiJl-kz}A^3^G_VFvFtKaj>zZ5&OL{J>v(>-X< zc%Qqs&g#EnTPBk)wVt^JZ#Pkp>ZRn#!Pd&%s7?jE;KCATvWx?WAK=YbSk#4PA>LMi7`+9{2*3$9{GXB#6QxirN8AMCwnRFm5l1saM3q{K!qK|xUw z5a}2Q$Pq+DL{yL#5tJqbq=g!a6zRwT6cn(~q$<6JUPPpKfdr6_BuELQoVPi*o_p_m zzM&y?P`7WNqO4Tju$||wduct+hVX*s=aE^><4+YTFF@waa4 zo`o}F;JO24J=gV-`qh=hc`q5vr_u|t_s*gYBfWZ=7BXRXXeo3t%*_^pjf(~5y>`XR z=^NAL6VI-XbuJ#tA2k4>GAI#*N*IN$1#BAQo(35Z8G8sxLvJhk>p0Kk+uBuP5}WBx zRXRv9#HY!UTi$zj7ALZ>A^|fk&pZL*c}fC6z7uU*QH=dYhHxe$xISZxrtKZktO3*TcF=57pAWr#9_AB&+L z>}9c2GENsVhl&bc%2MvgmO$DyZZn*0u-e?tgcSmQ&K@H}4_p7sL*M5IGlbLZ5CZKC zf6n&TX-RS@<+9FBEsTro)@bDDxt}|bB@h=TEEU=`(;$0l^2jyWbe-;vf&2-~B0fAC zn8+A3H9*PU0Q(%t&b3Y5e@vXXQn5qg8@d)v%nh)a;}`0K4k3wUR1jgb0>G1oCfme=2B*UtP$bNiKQgggo?QV{@9<7aL-2A}y=+Kzxzp!93jDzZ%pJ3v5t>im|KUY!R%t--)+eV1H+`(GXK|AvbBB{a8-MQBCX z`6)kpfQ4}sB{0fKm9SbAvqi+9=w~ThPKukmJ7l15zW|0k~P@-U%vLJJyFP z=~2n`!83FENayTzq+r;HMd@2H<1IP98#AKhV4mO~y!^OKKXC5OBhmb5J8-C@y`NxmN+ z#t#YpAhJ-EbWkJ`;}Q669&fE0(|aJm5sGU^1x*W)m*=K+VqrXgGW}rja|2@^0leLq~7QKYLtBD z#Qdg8hY{)~uw0O(s!e6AMMb-TP%W52R{<3&Iy|oS!*^+)gj{o5kykSs@XKQXZK;o6 z6)hWBk<s0G~DfXn2p@jl9ZqrG8HPGiZ-H^}L-%cL~6f3AO(Lwl#5T%GS%5I+AZ3HR53!-eco_r&*rSZ41leM{048jX8p!Kp`pL7#Qmo;A9D< zut)tr%erw97Y&@yC!RmtaQS@E%SPQXF|qdOrV7+crLowE%u7^i7Vx0g1OXsA!kNy`W5N7SZAMLn__yYMQLpC&8 zO;;v{MVE4|8!qOFd{=%d(GPU=GvS03O{kg?itw7S&K`HA>TaMqn)&Oz@^ z&fxSz6D*AHk=iqgmIF=<{=85Yb;;_!n7zQUfzm+s>LbNpTN8Toifw@74cY(5E&2R- z-fRWISe>_f%l!dBN%dAt;A+!qw}X;65Q4Zf%*Z@1vwrO`a)Cwj3_%6?#@lvn#*O>O zOsoCdgflTzL!Zw63S;}EodnZ7iY!$fwfD^2W2*hV>nM&iYK_N+*T7o})y;$%+b%d| z$M>A&_-fJn)Fg3LLs;sBk=|T61cO_*5)CH|hm@W_wNk?KSh;cXv`-vWd|%}}vV09! z$5wqaIaf9yQ~XdiYobT+iExL?c5#xQHHDFE_Jtx5;^$eT@Ot9(w>Vdx z_jw9LOP@x(^1TJ1zdCEGMgu*Oel zFKEq4-;NubkepKgdB5T0^612y(Qzlx!)13&(Bz(`fX=30krIs*Hn(vvBNS`1ie>A< zDx|ay=2;jJde?j%r>^a2iUQ-JgOGm$J!!PW4<9_>FGEi zt?J`d)$f|9)uG;S)`nW`E-@|kMj$^0yqd*v*op8DBD}1!fDXDpQCA=NH74ODYm08D zgzIKU&uDR8QHT~T75XfrwdQdMNqX`+@msOC0;L)8stD2X(9l%pcH12uxNp6$V8B-# z>{a!EwCpnNt?MYAk`3b4B@86&TaxRqry4`jvKd9xK4=ogXvdmZ9|}~O$ja>)Uh{#v zlY~9_C_TxzGbT4SS(UzN!CunwPp9NMj4b`L=`8}5;W=g<*?yX(1JXa&rKLRV2}jg_ zyn6T8E-C1aO4P^DRn+y$wGJZr81l0-ONaeRVPRtuFDI=aIWLq$wCzqqXEj1lxi}<3(F$V@2jG_?Jrm_#>*})%xxBXB1_>d_z#@YiyTkga=(+d z_LdTNY{&sWNLl8PF=cvRHCQtpU_Efcc1{rYzYteIZ*vbK9?h6w{=z4M{W8PbSPU2}y#DO5R`md#MJ>(vk3UQEPvA-3tN1_#QxpwIGY zL8IAkU1#V}4H1xeu}LQYjO2)sv|XCZd{AuyXrteb^1f(O>PSUU)l;CslYfPIsJOn9O!@i>=Qa z8b0(dBJsBDVK%ix5Gn2j5jk3xI-IIbI^7;rf52S+v&giKU?dIA3Isdj+bI)@n6wv3}PCZU7}31ak-5igZF`Z<4NfbViqlk5bu zC+)=r!g!!FjkLZCSViaWx1eQ)mS?d~P@x~Ios92Wx?pEt4uh%h0wPNRkS4esHoG@G zs=P`l1lTSimuWl>T?k?;AURK+0aIi361l~H&W2W^&eL9-ac=|yQixa9chr#U6Lq+q zXTUL#Z4Sn|yyK%bQtIo$lE*R7-XJ*i`@2IfW>U@!O=3BP5dS9!HFC*z=z0*b7U59S zq#_C#~)aFI`gxVIDV; z@Y08GKxH_HSjH@s?|4|~ST*rmUMJroU9DP2a6$V#t)UH@tWYsjxmUFgs!LHLmo@%YBCU!plX+DO*{Gvx7W3WW4_rUAP2~Mm-cmww*csq`KvHuUqp5ou_%q&F^U~*t{ zC@LSA8EP7^J%fp0`=O*_I)^-#uKy43vG6$LQV4kz@InGekPi!ALqkM@NW`}5`&nAU;p09GGwGU= z-U-wikKa{r$n(+Pa*lX`=Fn%p|gm7rfUK4fpR@Z8(E#F*;x6Ds5iepdEb3v zUEy6k3lGjH?Rf5vJYtG+R2+0j{g$~qD)7BvVZ)b4najJei@G8ugD-A$QuItm@uMvB zE%owrPSnKonK);u*f(53HnFa%{4yt{ zmx0fe?`h1e5nZR@lLFJt{;2Ci2=0Q0{7e%qw}QRf6Rc9s;!~8Ejf))k_i-s=Aw4dt zs5Kgq{Td2MKQ>Y|oN+7UR+^#X^Sd8p*%(=Ftc&dyev`9MdX8Ws8nv0qM9NR%xL=b~ z?yC;3w?6F@y2g=aq~-}zAgcP_V#x?YI>&Kf2D-B0_=a>rKKp0jRs@b!qCB0Ca=5el^pZR8%(aeQxd9d8cx>gZtG5y$l@eC|g9_86$0X`m5WS#~>g2BP98ui4A%7Ve8BbuWfl37_Q_ z=EP&G8z-J>YkO^@!f=QD3^N@^1U8}3fSN2}4tW&w za87T?si-X9F)bnYx|Q$!XpUU6%~PMwx})vhZ2;J?VVxC`oSA7I6N&)gu=%N8Z7A4z zEA>`2@=G=25n&Chke2n;^>%Y?X>p_Evmr68fF5$vs=EB?;I(V_UkOps8aJ6C9u zfk!q<=B^b1h0b)sZyVh5XKuPU{=Cmf1Cw~8W&m6-49C|Vhk}O0TsX=i7 z{UH>;5z*1+X*!&fD*Xd@jqPcIff(ag!F+d09qlaBs-A}n%O8+Bs5nE{cHU|tF{5>c z9n*WuQJB{>+^9bG_~j112Ui#~KXo$Y%Pd+v`e)6S`#)$!U;V$DP-%$t0=p?Rc`)}M z5QZ_V_78}t}k?^e@;=bUNUPOU&W>QjP=V{};t>4Uy7+x9$8-V$puY_BnRm zatOBy;P}>Y4H0k3d2Cm?pENk*oB?U~+i9P7{{5E5|7-NG<@y2~IB+`a^RS~(`rW+y z0TO>FFpFT+TqZ!c{bv~)keB5kg74vFC`^;srL5vR|BAc+)-KAT+vo4tfpd)8Q$h(~ zM~mrSCC6-*)XV2)$~&lO#WBcLa2Py3!LaHH>I6%;pOGYx4aCu}B02tmj5Qswm_Ldi zRQ{jTydl0Cl=kF!|GB@3NdI9D#_DSvO$`9wA4ia&#Q-ih&v87?fs_$9v#CS{T*;>* z7>!#B;;UxssJb2=zMi^j)KEF-1clqxBw61`AD0*#i2)u%j#eyL#9!CTYr-U>yvwVO zUCY*3S^aDt%ykvwbC_yQ)N&`~gnv_39u{2%E(5m$q%h*(OE=pR06e$@uuW9K78y!x z;Ho?M5fg3#TpkM7E}Xh_z2}`-0L1TgMi#_lZgwMB zyU*_tfw~L56N20qJ`XOPxW=R|Po&H*A}8WGV3d`H)8*uC{8@F*u33LKd}WCI%<(g| zTrc(|?Mg0-COxtdKY#r7m2vJh)s)tmaWlQXC*>+z25bnW2HO;F+_Q=MrTm7Xb}zKyNQj4(ZhTja`#o0z!4wiZJJ^ByyuBOgj^m1hVJtaq zjqWN|j9MPM$fm>*RK4CDD>u{!t%66TLz%H{;9*4;?;cE9@kx?SYX+Mx8MIk?Xyf9Jt z_6kpN^*xdzg+j^OU8AvJNy*H8Nq6aR8 zi*Z6!JzBcFY~iwLz;k@UteUjjBZP4Sx0|Ezmlqt5?^KAs&bMY>gz~pNLit@IpUcC5 z2T%A9=fci>4dwFj6yg`=RIU<~pr->uXJnQyqfBt8U3QAG6Q$>gS zIgzxxfl>2T+S&5JeDtHkt%1&Ifte6!39wCqb3lL7;}| z)^wiB&pPuM7mRuXKlcYjBn#Xt!<`H#rrI&Z!ggK@VdsW3fcYOUA>Rfb-oQQC)Vm{9 zVK6#hFmr@@imXqVI`!-JP#qgV(Co6!rS1!<3RSn>(-|~`VN@v`b0zhgCHxAEc1Uy? zM2|t8wiz&^?WWM1tV8%F7(owuq02<0As8YosAL{#&38O@sfe`GmIg&)`-EkSN^DeM=#Xws=Evepo zsUTVJjAo6PjW`CmEdUuu%>8I;YAX5^AQ8~5?Ia*UJm}6!GwLI7FG=Ua$7|cw$73%fduSa}- z--9JbJK8ds0~tu!fd<7pS-69*vg|n58!W;}tcX%-lVQe4HUm(4lJZ-Pf5mgo73Py} z(iF_R#j}!@<2{Zue!8?|_l=`nZ@=3$9J9D`8Au*y*rB1$Tx$}qrM_YtzyIt2-d9tC zvx~t-iE~KUIymuPGt*=A{(KL62k!yio3r!bU?JgMsHU{vCCW#nPY%`z&o3LY{d}a( zcNkGO=ks`GH)Kl5L!>+b-U=?*8LrdKMWn)l-}gOP&-AudKbo>W{bVv)={>dJMmf+fy_5cwz4fsU7^}!13E+o$p(2?cyeRO`m zOT?SSd79479+K<6S0bAS4YcAe=q+f+rRS2n+$D{@Nwt)lfdH*=Aqr+6P!!z?-d_zWp)dF!lKP=g^QXnU_r8UU6Z!1U6y9R7GM&FkQ~?Qd-M2 zfBzPLPW3Are>sD&?M)5r?cd<~AwOok`L z-jC1?oX=<}hqz`y%V)wW19-#rNrf5Dsj5jHp-c%CI4H@$Dx`AS&(hk3x=ZjA4a9@&UcOS?kFsCOGTG#KtY-=5un z-|&5Xujs}zYuDvb#IV7*mO+RfQ7K~m$@*+rMM&#Jw5#Uf^_UaN40k-4N=`5=x%x>F zZBs%BoQL>gJ?%^4XvqfwwY2F~FZGlue2}6lgk4e?d^e~5;a87ppvqOUA^yX+8P+8S z*e&@b4J3K}Ja{9wrTYoO?9N_?=sn?(ecE)x_OPJ_--J?#JdDe{{#(-9<(fw=Imv_f zCv=W~o)_Y|#l{br8@t!@Z*KVi;Tk(yHu_gB0g%XoS922-S^mvf{;VTzlcoL-NRbRR z#=Cee=T9_@r5tJkpmn5P60k+_3L7+6?7U+S_7M_rcp(0cNyBJ7WeltG|E2-uel?5Q z<1Lrj-^J3HN8bEJN+8d$nDIG>nr7U*LE%}$Ze20{C^5wi>iqvX_8+}a|E5YcO-h-? z{`vX%KOkQM0Z+4I`lp_jmlm{++qyma(Kw0TjRF}7BZyCGmGnr{?dyM``u=f;j?EkB zNS*Ia75HrrQVz`rXl|S9!~U*Z{TK15AyNqdlSmYOsTfYn1!R&Dv6mLjGqW#ky2Fko zZ=rUt0>H4Y1NiQYFznic3P8m@1#UI4I(z#Asp?-YmI^P&^mc6Q3DS>Y$3SKhnOy&J zr6kD8m%8l0|797>l@9{Qwis;$9y_jZf3>!2v!7~s8l>bScZiX5;AJ0 z8F%6x@n_6z?O>jRZ0pXt>eu_P>as=S+1%2#FUn5WOQS#msMYn_#`~`c!Fq{#7F&hG(BN%AXKW)eCpOGv}g%xdgsY&w}BK(S`1ZT7R98M-8D4>mLL{fH}tMD8pbAhsLzS(IM1XXUNK(yiWpm=p@m8Q7SnJka++m~2ri`PLi z%+XE!MGq`JFtGp`VeBnvuevNP9KkjV6P|ML3^?<7aO-le(>nYn<;s^+!J>2B8smJI zQ}TMhoNrH{h?y+AVvss$5tD8Ll6^(e%ldH-w} zFXkXdqXULF&-+~reHENLL=aC5R5vcRX*^`+$(t=Z@(E#$FBI(Xkxx~xek|j@XXbmg zIz?jT!_m=Cne2|UF@kaAw6RSVBDm(Pk|oY9ZJArOyn`>s?-*saWU9Q~ij3S?fgGy)hSAJ_{dfh94;azkEXK*snV^ z>3=}(3_aAd%P~uSV2Jn7xW(~BF(&^Pmone}<^SB+|6`}KCGKbsoFo>~!VLei>fP{2srC267qT`_-@z~k ztDKrH452KmK~L4Y)4$HZf-B_hn>uLB2Y(Q7lRQ8HtU!K*chWLXxmuNsNqkgawCT21_X(Mrf?p$zJ@3T4kExhl75qCrzy(gm4-(o9RCmOCMjTL{!;E@-GyY>c|M&Km^rc*K8dea#J~*rY`|h-8N$@1facSLb z{aCBulTO7Wg_JIJ!_d7Nm-8qtdiOpuJSI_R&hgyOG8}tO_*VY&Y+cUU_;kM(7nKVS zwhw%7+^s-d}IKH3V4P=&QfajXW2)%i-P2x;5IvORWcJ;u^G{Blbz|J(7M zMzZDCMhBm9hMG9G6;QB>0^-oec0HI5s={vb#y*?l3|aTjah?Ah0PJq6oF&LxIQ@Z` zGuU*Oe#{4)k*5aW6M#^78V!WL|NLbQkxrW6(lFo-KJTg@CEY_V*$?5i9^}TY`x5H` zsoC0X(b)-jN~3!KC7J$`2}G4)1F0toQvsZ}7cDB3RB7w;Q2J5-I~$QYhfIQ;I+%d5 zu|rPrNQ%O27sZl#k^Ps0>4IAy#^@fB;s~URVGU#eJ2j<1mc*up0-p>___me4JlxNVh;HL_aFT4P^m)^^rnv6D>irINUo`qs-pR$# z6R&HinTvVt3>}&OG8O#)(ewY;(evQ-VA)6y&{od>x9;czCj_=g*3PVVftL`v?lPQc+HeI5?Z3Wd80QK^cxiNAjNIH}^9~l z$I}maV4cD3yo)V_UOMv($f>#4niPqAb2F*tpb;5DimMFhL;fNhv@A1%JcAsmK1I>^ z1JWA~I+oeMPMnn-CxUL}CORn-#z*m52U(XooC`}lbI`CH@qT@#3`QmU0o>l0270wm z)n`B{?a}}HlN~Js`UJ1>z`2YQekt_qL5qCOI8L}=>+C~iMOB)bmIne6GkBd=Vc%Ji z&?2Sh1zQv~Yn>5k_gAAg>;+gbX7-O{zOfbGn2>BoK28$#)BEm)1eAKN)GB3eq8@lH z2l_%ho66WB6~St zkpG^}YugIn7frtivXzP$Ab%=fBdeD^09QbQi)q)$A)q*Qyd6$f?8ogXCeRiAG{)SB zfSkpSnSsm@2oR#-rrPjxy#|1d<($P%7`Lf&_WxAycf{vJ$*)UKdFgxZ$Ns*`w|ze4 z5$>er>LcZvvakoNTyIOpdY3H?D8|xAkS7Vcz8Dd=Ra4%+M&2 z_`-LTiP$oi)7m3pKo%<^=eNpYGOm*oIqNQ&30}sC4=yGv#H;Sv)y8u+&Zke8=Mlg~ zFVu6yGS#WrH>4{o!pDtk(>E7ybbFiqc+$Z2onD56QJILwO~>tEO0iiZi7g||quODc zvuNoi2-Cdg<_pH$LqQ0S`95Yi4Cye1Zbg-Gk0f~Ko9N?vw4L;B4xWtqa;(G6QT+Nd zQe8om*pZu>V~)KI9Q5IgV|5l1AFCN4VgQs=@F?H!z2Y=s(-bv9uB^Pe^3oq zy1vD!L{M7Wes32bP&&9xan#qkQlnSp@$8cSN1eNpzZ%q^EJ~=%8)y2R84lp`6CpZa zynZ8b22U1IzpgB3Utn4LWIh+9A##p5vlCCw%b{K*JCY<@Q)#$}vN+&2xLi4LXW&v)bem6;0XMEf}lbhC?{Qg@+QljpwsX9Ki2@4E9+5hPYycJb?N zrBF40$v7gsIU^{5EnKrar9(+z;Z^1}31CyaT1}1e4s1-cLtbX+=y`3kKkR=TKhtOc zBR9;n@}yt-19Cmg@s(%iri$xjv1__hO2yCT{F}8G1q&#o%;E=}Ecfb}r;^b1fCB z+hs27j>vR_GZJ@C-P^N9r&;??8;BupWPILT+jh(5RG;fek(Pt80k=Wnck<>e_4}&REPIrS^BFU5=dLFzF)r^#tcfh@&aV$c zHcr#Z{m$i3uN^eRFQ;awosO@uL#KSHjon@Q8A0HIdYQjEK^Qhzz3-#6zDzK~9d=CJ z$;))`IbHEexGajht*zjN1^=^9!{44(G&9?t(y!O4cUARjJaBq7j^s73Ahmw7xR7#_ zHQAzLog*5Ln?|(PCEk#lKPA zXt87&u^w88uctM~Or|X`WH3MAsKP(sAWDue{iDPVDdwW(c?jyC>L8T=*d9{67f&AO z`A}6AuOk2}{k{q8P4`EuM#JetsTQ%7kBAc;w@WLBF4&T?QuQ4@j&+@g0%pYgCP#Ee z0@ax4Ji9?qlmOY?4PYq~VDachm4-3I?Y*f3r$&e!7|5PsQWva3lF)V1fXd2L0LRWz z)MdXXpRwV<|6G!=4ks8icTXv`j_TXny836$Uc0ZY`}=w8w{*~}HGm^lQdwBA1V!Rc zbINFj|6Y{-)>f!HxqP=Sl5J|Oa~&Y`(rlqj=<>JPy*u2p6{z2)}jL0kz{!OPzl z&G}W*k)ZwN@RzK2-KVSB>R80Y{Rdy)lL!wuOJ%JfzTOA7b)Ul*Dn1@Tm*txj_$fMb z1W#)eTo>nP;kW3CsTKog(~=r`b~i|TK!)4TkuYM-{($oyqXCpw^9wf~KARFE-y7J# zURg)-47GRVNn@-tT5);*_Gppjq0gL8YdYEt#@$*{-Dbay67O zZ1+Dk{GlqBLBV9O0BN#!H8csTog zvgFme@avT$R>X-ZT`w=njEZLqJ2m&AP&~9}TxIuD+||m3?lF{@&X@!fgD=i>OEVdc@#76-lgB)_zd< z-pnnIdX~VwiSHq_LQwal`B}a7Ga49eu9&_& z+Q3Ccq8Pdhx<1I+r{2Ln2^xBRxghcc&>X5cP81Wm=;tSIbQ9U+< z%#XdWOH9w)ATbf*9Fih+t{NiUf4*QFZ09;*hAOBD-q46`1YHJm%!2(^48oBx>KWAh zai!$g&C8tIzp#NgJA?7sRul}JyX252AKtLoOui4tF;}Np6zBJzJ9n~}JTdFEiBW$X$6GmH}RaS_PUkngKIs>Wedsa%Je3vvchuPynQ zu)jB%>xgL_yTN1l%zC8meJe^NKt!npd5E0TjDsR%^9>4?(fKPpys8|AYFRbjrz}Df zyp9ZJ@`+z$jt15YfMg48!Xu7@Jh(FaB9|Pk@Ib>c0FSn0U=EqXaxq@UI{q2(=0(l{ zCf(KmYW~5rJ&53F{Nk&_kq|=ss=R)sy+%A-7PR*knb^il#ta6W@naj5rrriOTESWD zlWQKAxYt@a5;9b0&H0rvtsLX6*k)M`__d5^bw>W)7^<@DDE-U`6+5?G`W92EMY{fF zLb^0(WtC^<;+Tbw@{L9QiJNjEac_&2h)RJCN2r>_`Xbz0GH;8qkHyOKhsjv34yKD@ zh!3A6W8dd;KPO7IOrXNl75q#Fx11C^u9rmE*E$tAC371^rGJ5B!o2^@e1+k~->gIC z==!6;Is~xMrH6O;Rbhpg-F3jRomrhT*xv>b3s_oC{cqb4$1y2T!sy3NaRX>u4yQ&2 z@B`sg@Fb9IcWa3Bsgtrkz%hM3w+=~JTMYWC+3xfh8aKKo~UJc!uLf1aQVa&dd?X5d*GR_E%qI(BNz zu}7&_0yz8-HALHBkI6Tuh)vm7DzlZdY%URgmm$U?CzdTMJ!Uh;zjU|xI0tzXdO0Rm z_ES5gKFE=+pF9n}{e?MQCs`1({Q%tWR}POBVX_1bYWV$?KHyEN1j0N+UK6P@Tysmc z4Cp8PDhUR$V0PQ{3AiJUsT)D^P6Cs9!#RU&Xx3N9^rNpRKMD%}${>+`QOR0NExDe= zyYrB^@IJ@X!d`?w)&I(bWVfq5LCal0f?r!oxYmhTMCqu8$ZUWN8AcCBbAbYj;X(A+ zgvH`c)bV@I;zH5r+4aNjA#F$WBz5wxG|L~=OMWOA)H%ODWOVSFKZvMgG<9cU?o&0N z^a>^06B@sqwnUUlB!0>W*$h+T@-glafUfJ{Q4#w;%EQCdx&2i8M=7eldkdt;(Ne?D zoQ|C1Hz9uY`<6b$u)BDGdwv3)!n6?3DI7fSNpN_|Mgss5g52f-3>Hue!4CV~CIb+2 zxUyM9j^q_YRU>#KbQyb`>}A4UcxN@|d9t05dA2vYFqd0YYeZ67`;oP(`Z!4DN(ep4!i^Io?gee$4==aVIneK8SnK$`{(B1f!8`o9bujA zYamHB+uEjVZII3AOif5)8pewWWU$BWlmQRCx`5)K-X{4p8 z#8QQ?3x<-+7ulcgwOS~Sq9_V7Eg5m@e52)Y|WvnIuWN7mmGue^@-{t{N7FCR-6d&AHB#U(_gP?;bz&xi z8j$kmf@w$2RuDIUJCD?aEDfg&V^a!Y7%7KguX0jwE5)< z1uJscaLmssD^J#w(|m0=aR;a$g#X;~)muN_+}HDQ@^sH< zIQ#JkbH=bMAl7=sV~#ng`Ez=osV7kgXzH1o-XK2}VtC6$PRvPgM3p>o$|7#bHYsuh zW!b-BTxU_}?MbY9AmYNX4ll*E!C1!N5rBIpIftSbF&%eOkxI8iz1km(D|bK5`6Ogq z1Rx)Q$crSIk=jE7WfVJ6{$R}Y?JR}b_x3SxnEXKirhQ; zn&UU!Y2Mr{bR_CCdC2Jkt^}bZzUyY8d02~Z=IOd~=VxNYV(2BA#Wsje-){Dveb5f@zl{#HDGVZ*8ZM6atvKVy)u zQIFz#SoSUMZaq_V4&`~v`MpIMLwz}a+00(dQ+egk9b#o0D(LpIYI;sFS*K~o73*Za zEa2{G$zz{geenesxvkoYs?x{=Rv-G{If0doew|7N<L2JByE-_K3x8pR}0H=DB@8*yj&|&IF2h&${P^Z**AdE!Ky+qMp10Trc zM9{c@jI_~QyAEqnRSfr%hhBMg0iD_gvs2&?l9&xP0-U-vxlWIhy>$S`fiNuB_ScTUd2TI(fSuq+KCC_DNgz56n^=k!9Qo$sM9Gs^rfLH+dP zr&w->&+6bTdTrDiFkaAAfsW8RrFUlJ)B(wEIafm9QvRv1s|h14cg00M#J;g(n&~|_ zeM3S(x*Dfi1gh`fF~jBEF(T8#IvSDe z*9Oi^{L($Cnee9W+y%ML6AT;ha#$Oj#R1D$XW?iIj{ctujtCtNf#0P!dLIZ%5R3H& z0%R~p<-6~q1;`%PVxDs4LvtwG_=e*oXmgKTQ%yrPFn6W15SIqf-_mzYAE%(b9iIj` z#T|(exnU(3&D49nIuBSbrO5Xnb?d77sTWID`g^5b#x=``N1v2^?$ut=_Fi%!hl^pa z#v>EvINTskRTx>1DSA8G%Z@UAog6%8SdqZCEn2zP12QH%>QOF+8X~)H^qYb4j8#jw zk7OXjcr+;9f7?l-`I)+G9R&hn2sm~O z^3E`pAgX_uY(c*N&Lra)n*C%YD@vC1ZMtEIVLf94$6NxNXn^DA;B}uj27X_`F^9Q% zfRsPlb~oAFHp@E{l-6X%8@g|f{w$Cw5DD&mg>z#%n(qbhfm9K_rDi$sb8~a&SM&Ol{tx=Bocu4Q z?&3yXZ>z}~2MGFUlGRAIb56JrU@f!@Jn4mM&%d9)Z;R>jz zOot5SE{Hi9lGum-yik*d4sT$quZ;D@a$o{5;Hb#l#G@^MacSu)HnEsH%P8Grr7N3Kf@9VLYy&;GMJgyn_iPVsSC)=#kt zgD@lWFQ0x(mn-|Ocj#6?uUnTymhYXHoUfyIpnId8GiBIk<*6yCq_2SjxfoH_x_{Q+X+#YT~n z=o2QUaU3(co>siF^sUe99hTqe9=%jJ*@8GY8yDn0l_nt42?_{`fOM%5ktR|^=}iTsgd!jiAP}(7Art`x zDM}L&BE5qUASlvHB-A7*T@q?A<$u@z+}1vu_WDo>Wu}EW+VYHBfJ6rZhEr5twxKuL_VS!-+njVv;M8 z+Lnz4AM@k`XF?BY6DSFIOlo65jLEiTE-LgUSO*YdiLLv6f(3H*MS5M^AJUQy$_eiG zpP=VmPTBG5tzV5cBm}-lasS=bOy!|KttPJ(VlkVisy#k!gk{Vdg$q?C?HVsk=f3Yr z49pl+-4Fj450G9#<+0khA${+EDApzcFo?Dm=1}szP6wtARS2fO|gq%R5?3D zZw)Ez)wQmRJxr7S?wwP=(l!+7W!g#1#*B_XHr;wk)oQi;=2k_*A zjv;1>f=vZUai4>Vf|mS&gDwm&hgU2koRm|03ZkBSc%h;VFy91VlQkNz8a z)&B-*mA=b$qpTE&4(o?_Q(rcXYjdllC9+4$G-kY=^I}^W&B{99ThG;%7=O~32LS@y zKEDb}{x~v!v}r~zig{*{;9#|0C|>7$t4GQ{^K$5|8m51#P$`jEp?`5J=_xPt-!b=q zabbYvI!0STkDh}U12>U!TFGJqn?2VzcA>1M%`m2xP-&k*s{Si9xDDN?Hgss+0Q4(E zT&V$F5_*-LP4$75w{z7M>putO{D5J;pR#3odSkV?0_J#VM+qi&r*v~~t41l?WX|1H zyW%O@oe*-GM~)ChGtyku;;)IYk?voLT{_uy0qBig_~Y?A$ux@^%5%2-WG|H^fu(+G zi;(!QLgp>eCj? zLe-Y)ataxm6CwGigbSg-N#i)*p>`h)3cVfT{xCKSSri8^)ZB%>B4c8^PQW!LYf8z| z=q3L3X3JT*{TwUU#G%atDMMY;->f^F*;|QJF~%tJ^Ki+hg{}|$fxsF65_?}=U{pgt ztmPpgMgs|o#zgax6jD@W=K{d2lg{!pixZJ=$`lh91S;h+)qI)7f7OpXmDTD2*T%

Ur!5TCEo#NB4t~8RtZ@?etFK>li-&<^BymEQH6dv@S1(x%ITi$ z1lOWV%IKBgiE3EUq21)cTsQXunn>4_9d>ip>==Cm2^Ai`VSjeVN`2o7k`46+Bs$ow zU($zBpUZ!bKIlr);J3)fL?ChI_;j`8A6b8H9F@bL(388)Q%vzjiK@=hCNqAhYB}~V zgNriLl4s}QZ$LA-fXT&dH0PS8dap%Xo6##|();Npi&t)u`BlHdGGaglKV~J8&=j4> zfR8j7r9BY(H1|4pxeV+L-ypxnN=O;WVrvPgVysAoSz&>tP8O>DpM$hBeQX^Qub%k_ zl#{&{eTw3U?~dDsFM=muC3edA3k*r7UUb_27OJDJzIs#C<3Azk*#B3co9&lx|J95s z!#uP7zn$~B^Z-NC|5nEhI*dI^Wvy_s)Fr>K|DTYz(gHtiQT#WN4>t?No8?WIf9?MI zgE+fSBoy#1NjrSeGSUl*XYSTFBO_xQT)}JGWzZSZk9LA5yY6dUWLIKhG1eK40Mf~Z zNL$-%AMU<+IO}|8jTh;<7&*oozk#UNZmXvp-3dsXQH$m#m$&LxfAl7+oU$*;F$})& z+wA+90K7P@(+8E>?Op|}ne?2)qc7nS#HZyN*|Y@Z-7YQOu<_uQ836T_Fpl{G(A{+y z^r$F2l#>1Evv*tROq+FA&S82Ff#cT6#4^Vh7sZ@5v5yb-KQE;K6=3vfxJWChKOZL1 zAANCJTQ9=b*Uwkm`D01Pn-R7lSn*S>JkT%};TBlsv}oT?HphWEhCaFac$drd-4e&j z3pTUEsiCoPgU6NfkjGThWUjN`dvJr=rrPm_b~(kBFD=GTGW>`?!!$vo?JxFtQvy@+ zz5$=(fY`+|U!$3OtAB+3;3O(>kGd63uL~(`by78f z>N!KR{Jm#z6;5ipsVJD}Y~n8{sQ=K=e;1Q6CIm`0qQBObD}e{Lk%x2B(tpnTWNz%* z4F!tCIJG_wY?lOhQlpcd?(j==BwTUXRd}d!v+&Bewr#27`cbHwT38kHYhG=$mS2Ib zw{J2}{n3Gr&>*GJBRKlVyQ64Ua(Uu=ABQZjnTW>GWYr6Cj;}}m{0MYWsro7%EF%(v z3W`6}rWeVpRz9=q-`fae?<&;xt2`!7Wm8@LK&nAc|1NDoOQ6wbNb&{JeKKw{a4GgC zo1*oNToX)rjo!aeRGU{_YdAqlbfzP*Q9HF6dM^XrGIRF?4}{Q3*@4 zD52@q*G>C3?rhW55K0%Q+ABk?YU%nH_aF)2wyOomt;7nGvdtM>5wc+pxg8Zc>fmmF z=|MtoGpLX6f&AoQS_^}F*p;lXMW(7zTzjoH24r`1u1)+F)wB@auyks>ehe~EIRD(J zMz(+gFm`|_I5*OPw)LlVTt})@Ll|4B5z)^8rQHgG1aH4PT(M-mPe9HFm~@lnTM42P zm(?3~46eZ-;NpXVix=soK$1yl_R|6Pg%-p|#vlbjmY81`}FD55l1 zPDO_84i(83qZ{+Mwv_(7i}TeJX9=hK4KWD()oIuPguFM?Iy#Fv3?s?E$LoYEsI<4g z_pVvQ>91}y2Pxe~zH%P0vJm}tIYz5U$Y(|qxqXE+x0O4CWqHd0^`L|zaEL%UpVSWQAm1p|)$<;F_iIF0nUhC`5c$+~9*23VQk(SJB z04VD1iTUUc(R_O!g@3>DyoP`@t z>@%a*n{dv(%D4U`bJCP{Y`_D6i6o^T5;|%o7=9n9%aohwpD~J5;Py2o7+%7`e2+Vu;TV~ zytXgteL6=`i1GbGy{|peJr*xD)v^PkYT#GM6>)^t?&jJi{z8pbg!W)&lkJn@c^PB| z_O}2lt1y_8aXNZ<>0Ad_1uVVi6D;EUp-~b}&UGLnMd9*%)cgW%!N|e^vd>!Z%kg6-d7%eqS=5>`c3P`%(JU=%;(VV|u?Nzt>{K7Lpkqt863V>-XS7 zz)VCT&P9H#5!kB$@UyKvAD;w*Z8A^ee9oWY6wqlZ#5ZcAJAitXF~aMVeB)1{X}8uO zRog{t>TY2G{w~&^(wSL*oUYqvtUXn`eY--hW(h zHE^RBcoNM_Y9zvJFTT~C?WM(a>L4C2y||`GPplCkGM+3rLjGFc6y@JqT`mw_cI~Bd zof#$+Kptc+EEKNH4=~pbz=)F*^<6ihnomlI;8!NzQ2~+HqNS1yjXiBH!kfQ+)g`pJ z#zN{VVuhW_jO@!rQ6V1XKEo_^3qIJOI*tjhj)@!w_Y}5aZK-}Vra{hO(zUWY4G^aHOc?O29Mugq@S?Vmf2)4?qUZJ7MkZe#lB9Fu+UyG&Nem6XtL)pUhJdrBB_6emou z$*x+@D{azLjZ2kF3B@tq`(E_U+5B-MEo7lcPIFa&*r`Qy1!^(=WlwafQ9rIZj%FJE z=&=&n5ms;QEvyr_+3f==BO+)019)JVKFzKIvL@DSGNjr@=kcm(5n9B-Vg;WZrYGQKn|!ud z2|?lIqAF?2YUA9`KKYK2r@w77+#lKwO$j_aJ<7_O5feTDM9BbxGh1W_zc=BLccqt5 zRR3fT>tT1Qs*GT%lY1%_rV|nUnhEMaPlL-s`rc?;JRg)qG zqv79*5>2NRv+gZ1zJ+=dqVD(Qx%MRsJ3mq2wm_|CX{XoqPS&f88=p=8jv2ZkPV^L5 z)m}}D<^#^Ab7X5EDOhEP1%~bq!x^+W`*hFhUYR~?cl#J;pSQ*8*4Xvn+R~Llz9oCc zPrG2~g{v+W9CIQDUOX2Ja4qvGVxU2@9d8Sx$g%G`>W0OblF%tW{6=GVF?==uJLH0=TDpw&-gfOV_8SznBCL`dWQ`<2d}$ zCnu9ItrPIZ*=IM`r_y!Sn5#))TYF`I3MQ}UMNQYmxkb2cTTLeViQ#^SD*cqC5gn)f^X0~oTS zpj?1U2}{+5`vL)(+idz++|u1?&q>K_n)9c+?_@=*wV_bG`%~OjK9IUmG>QctNixhT zTW|aHb3-%qz3LBjUGXV-zPFN%XBc&%01Pknrq~`C+J{qF;-KjXLDe{Se7>KUFX4%P zTMc;**)`S{onuJZ(D!I3zBnGbQJ&q)qMrGl34?CNv67T*OV=HoYZA-nybrG@M{0S^ z$b7JRnsf^EJ4S9Chz|NMXm%!+iGr6kVf)87ztJ{VkO{7=aD7rV)wrF6?Hl(03Ty9& zau!Eppt6bum$QEcBSjW(4&0+c5Y)A>L2?Cm7NH`2N3!08M@#<@pct5%7^&yBwpvclZDh zyZiiWrFp!7WF*`Pfb+;hAIYHygA zu8fy4zPX-z2FUBJ$oW2M&40D?rrLh+*2i8N`1P$>nrV;)`%A+j_owX#1X>!ll|D?> zr%am%-JIOtVJN!T6a17Wdvqm%Ig+O}y`oFpar3fan(RINn^NyLBG+vlFO@Q<>0wlu z%9aCWO$qTY185wCs)A@8qrU5|^UhEJV(b59p!tz|+gZHcQ}-nKGdeeF{2*@K3Hrul z3S)Hg4W-_q-OFX&YUv^BVFNu!8ydo{q))v~St!XkndE3T z*(1>u9Do^{#B3E2Jsf%+~G5ug|C?oz~~ad zBk(U+#zhgacB1WC5~*5wxv0-fYydYhNo-E&yFmVYy8EZ51`hO98@HNbt59{hvjm24 z#QFn!eKUViWy9>^t~?!9<3RS9bhoQ=XTGN!G4B;~RfL^T&PYC{DJd2cE&M%L|_%?A1p=K}x(k~u7Q`wY7I*3HUOPnBn4g#TA4 z>Ho{w0}gsesdAw6Kk%)@YTXivP(85@K*^N~zkV`$93r5I-NLDZNy2SI^wKUC7dVvc ziB`Y4{lP1*r){cFJ-|;PyB;i2BKx9nO|QC}n=v}R>7q5GZBb4su_4hHD@7C+%JNg| z!XulamIG6_Cucg)#AdVtFAUrp;R{5}@9^m9ELL#5ZLyA>WirxWN`G+_nFJc8mq6Ty z-3D^=PU^B*m{W#xm*K=@nE;L7k zD1Se&HAX($zJ<>gPl9mj-^k9FyxL&ndxkg@b7>6X2Ii*N_KIDYx#kx=Ni>7>SATN8 zcJ$j=veqL@>tV(ZrrrDL@7tzRg%7pJ^mt6CV;}Ekph?MskFDlAp-*kqy%-6eFF9Wk zxe~u1(krrE6Wvdc0-H^0e+y9C97IIjVsWPUUytYMpOuu5{%7f@Pt{0oRS=&$LK=)x z1+p?B_4_+-j+T1>_Y@FqOn(i3B>fe|OJRL5rmg6WxcoftL9}@6+w!SZtJXr7j)Kxv z5N)6p3Z7LaRJ?#|5jqvn5r(-H4zR+-8GL{0a&wgKpNp4&N!f*G6satG#LSJ^0)u_D z3SJs*+1@=;!8wb}k;I_5cu-CZO`Z+F1r&QT9l8n*NcSW&+sH%q2p zKwA*WyRxHjZ@e&qNx8q8G3}z%lp!xs@8t&wgc9%m5cuSqH2vnC#NqZZD5}O?fmfLe zuYvgp1;X>2Vm%X!`U;&4D9Gtvl^+D=^gS5ET6Q18Yd>fJ#% z7Yv2Q9$f%bG7UM^o*~};0n%xHyhc{(&rj{@4ozlE)M~SZSHaDvR=<#zwv`EN)Q`kH zhf}1cw@iwwx%yI>JAx9~gDVlhX7)qY(*wS}`NebO1~G+rw9#Q4`O?OoW8+jP5glQ2 zO697+AF7yU+tH5Y93{9P7oQpczv4%|4Mo=c)DvA;h#?(jXD8j=_FHnt+|Xve2{v%| ztY(TGl|V)uqX`PJT~}c0J(^ve0pv-Sj+_BzCA9pDQkJZfPXm2U(`4tgSt}QyVjSbB znlk%8{=S4flegBU^)iy_#Y~j5pgmOF3IctX=CN8{RE${T&*s_=CY9JzMoFIcNnHsN z>dnCtU?sDnOMgZYV{t)dBu9N zR1+#xRn$DPr0zz=-HU~WY(F~rMLT6zJ53KcDY-y$D)L2j_0DHcKed^S8KU{yl1!OA zeJ0ym%S5sJC%%UT0k{mn$|wlIh@S^HsHZ|YUwxTuIRvz$PC)o1XqfbPK#=x`Y6jae zY0Q_B7UF2^gCci;&Xm<Aitme7Y$G{2n4`FowyHa370TFs{}7j2k#CR2 zj#Fdzo{8A9kc|%SQfg~97Oy=YqJr-=ldnv;{H6xo;@h_R<$78zwq@R(#VHWi$=rhg zb(oNujglXX1Co#(F|)_CQ!V4waz#2__Hx#>6q~K0y0BE-O|ETTqBf5rBepy(((MTB z09w9(C<{nG?ooQ=0A`TxB{M>DC&F|};GdB!*Z2OfyYdWZ1zo@ZFvh$6o# zoZIM$;a_ zTpcD4_}X`crpv;-tscymVXnkj$Mlrb4Cu)nM#N{7;Yzbd-oYqJ(&7Neg+KQ9oNo!H zeEO+%Q>$dM7V$W%1lKf{0uRGbuDWn54+7# z?cEmAyd&9Kq(46WAVS39ACNq(m53~ccyku)SRJNG3y`5tq7Ze z_oQ4xR9t~hFC2#Ls~xbDUDGt22pj_#PGpKDOLx2o1F&!ihW`V46A(Yj(26vnI>WEd z=&H~-vD(t_6Br9H{-M3n-6^7uql73lnR1`>0ca+3U+xDagt;iqr~on!*bC!2=R3dq z^aa{>)3>BfYzypx|HK|uRd-RCtMojylgZM3`I%~uI^Ro(hXGk;nG_;b0pUZDy*b{& zCQ8s2lW3SiMK67tcg{|dsc`=8FBx>*W34lIjEH2yLLLPqVxxsfrPt?w&Lcd9*H$OW zyz;~+Rah=t5(7?13y$Dh+yqts0BbB=0m=&kq{o68R$@iTAb^`Ta5{}ERPFbB9X^CMYcd`NmXg98?v z4OErZcJ)z_rm!4>UP1qh2ESEErIsPk^7Iw`TqWeDY-uwq`^r8eI!22JY01H!gg_tp|G}DwFcyAKJYzjbWI`LeeX+w&VrM($NX zlGf6{SBCgSVTU#9=Jc10%l31yQH%B|KUJ=6QO(^Mw%N-}HIjM8Z-op6Ld6Ydm(tnT zLsSoV;6fQCdCTwz*cq8G$SZmCpTr^nA^zrP;T;xz52Bm|TAF}N^q6Xd+W)C`kjehw z{_2B`oVeL11iWR%v*_Qk-8n{|*wsQmA23H$Jo@mc@ItahuQ8uTC(GSfat`ikxLEcy zrReY(xxBKN66QPxSHvUFQgYFG-#2XX%u-Shp)b$&WbEFldRKE={OPQY>}39O!$jYt zdVgxr4fU5Nhfbdj|2neNxxMYg=*FAz_eR7aJwCy`W zhLHnkSI+400i}qr!$Il3i=AQiu7v&#p}%_F+y%YHE%h_oc}OJdcmFg}--c#D6@ukq zoyh0gIJ3)5-(v`-a^`5g9LpT6O|9I-n^I5;)9(sFzA*}-k8zgln(+CVAB4!7R1>}Q z)NfmUam0AL^c`YI>P_$Y!U%wV2%UCaPDPtaDgX~c?%@l9lRsYai5wgwG(pLS5Q+&3 zevxF6u+^de$fI<@$6j4!V6`)2(M=r|j{PJ18_5d0g~2$m=M5B*9s8CZJ>M`@I+96O&wF_aq;vvWK#BiI3B#AS z;N+{xp8Z+S6AF!Ho)tfZbM27i=3KUu%p00iOIECg;6Qlsb&2O3@CEN>KftCM%8+QH zbfcWT)zhPD7VUmSmc5F3^zuq~M%pYNGSc&dH~6dsB|ePo)~6ONlyBkuz~a)?;a}HT zb?=$Y{}Ev!0wK`T8pY|X(tLPL+a9*+u)9rDa=J3GjB0;39<;oK)q|85&xzGOAbwsWfmSG+Xkb71%vvXhKDDJ1wVBXQMWqCqgzX! z#0C=7OIM`G)%$|NWo&P1AWyw}%p}Ht{EC(ZJGu-M@tx*FVse3p;LCLX_5!P31Lf~1k!%C&Sem8LO@=Ou&0Y}X-#gzvk$ z-IoV^eZc)NOd9I1_x_t!Pa5t0s}}nS_7s{IGCh#Ye$8D^ppf^q@E6aN6Rr2Z0U4!# zD;WG1F*m@Z0+?6UpoC4cIFkA&o1p?brIaa0!&fv zW$<8C*B-Y$?}sb7$KCKSBgMack?AI{wU+4d&L{R?x?|#6VA( zVPCmFNV{3*Z@i+07mQ7zPZ*tN+P9-jFDvARrFEz-1qyX`=@vy7>Z-sY;zbm5ni{Lc ze<;cKJo~v)5KJA4%YY7L7~g#s=5~+l`s(wqwye8tq;D@mzwt?4b&s_kunQ_pi`x9x zoh7Qv=?GVjibO}VkZMY5>_)vWl$9+~pj&a=O2&G6Dpxv#1<_Z;W3d@G!B)VfUL~C} z2F6#L=x|`mcM%$0bhO|}Nd}xhzs5pNS_o4@jl4uy%pB%3pGI&Tto}7h?Dk9zAn=Vo zms0_=JHg^`p3Rv|_%D}uW&ONn?z86n;Dp)e$aawVdyw&gUYaiyVrVL97o*BllAr4J ztX@=-Vb(gd$zmvW-MlSrswJMvqZgw1@+NB z6}t_(D5fy&qwLMkMg8k#1;WE)ZvtQzAxrMjifRBouXHyL9DCL*?gJknl4{I%zM+`dK)ZJ@94|QIQA9V$VVeYg681%_%E%;!9Md`)B}AO zlo&^_?PCat0R^-#^&ilXCg@mm3BTGG#lP&FH0n(#aC0JGXo55dnfd&du1}K88k(*1 zxLW;N$1739@xWLxj_H`dzUkZM*mSa?Vg2>1B9k{B#7qQs7iB^1r=ENk-c3@S3D(q-^a`De)wiIhL-Y4Bx}do9Gw zKvy>mzB{#N>>B~W-fj7_8AyMdorK`|DT`m3ftM75n`Zz11-1soTyLsrisUduia`ZT z-*B>#Lw2BzEAdy;q(Vbw_gE&zH#SJp4|#!GvEzbBhwSQzieubhDx#QZUpu>UH8~uFabuuR>*f}mw5N8r5v12J zH*F8bk7MR;T75C6@}bOFhkXewtY5!R(|M!_Dz%%c?c$@Z{>0$^WrFUc#9*gw4bv#x z)`Mzr16ma4t_T3DzK^+yr8`+_tCRcuA*9z7w?NTq#}`Ws`x)SH?hQy>l*e|c1`-fF zYhgm6shrrRKo9&K3~u@*zSxg^9vW9S9U((#$p{W&P?CA1KOEYS3g;~nK2Bf zQq3vqmSlz0XwIeeHrqMk7xDw;#qSAclE9bmwboC$r)kv0YAcgFPXkhS6xy9VHs5Cb zA5io^oXohU5)6~sxUm<-B7mg=lhltKH4UDPEnFQ@f${fS)v^f)_t4^*!yQZ{_4-<}M5YNu-*<9;TC*OuC^aR2R z(f#U$oN<5Ys4bNO6GG>1vcaLnVxkQ``@tQ~-|{9WSFlsb_|Y^St|aa2#m{7YSBh%f z%A4b&Z#?A%j%Q0P`rB`Gw{4&Zz6s2tpDbN~8e>F5`5+6K_9*YAn z4A(ioB!&j>HgP%Gnn2b2xcFeGdoAM~T#@(%3C20<8$aXbG@PUC3#qOl*uwSgul^>G z;OZ!KU`&M>*h9ne(JUYw@74~52i~zt^AZ!HEb{}OWY|M>Uq@Y?(Z6k=V==B5t`}&k z-etr1Rcwvw+-UsKiO6BY{UOPSm&hkSVhcuQj@<{Y-%tf^=sJbifPG||i|UMFEXv!# z;5V>%?9uHEI^xw%kXp*kSfHkz>5nv}coL&mX9-A-tNWmyiwl1cVLg8X?*Q?@1U)uF z5qst6B30HM;7VzN*1NP>0O7X*p>~pfCe6tFLt_`8A0lp1z?WTAlO3^iqNBavl~Y%l z(v8N&B}W0jQdny+#jI{&x;A57G*aQ^z7c6PUS(LWK$0rj@YF;3x%E@yVGz_;P{bC1 zlomImtJwL#WVIKl@>y9NbTnF>rZJ^^nIhFtpmfM4{Hw(@p}f`V-kms+WnS6?rbW>C z>jDEhvcUMzAHwS6qE3I;VOs8$7wqFu8hcxfT;trj!oFW!i|)Z*7(oQMrZRO zf8_zA$Z0GF5XSJJ*t3rseSzg=8;FeJhk*wY$&mz1A|S2#bM4u}Su~aFZbNsbuw&xf z@ZOiC4JP6HlY)c}2{eO)GW2mRERSWOJ8?^;s))zyNbO@==?LlT*do2sCNzDhp*dr^ zG{MQX)d<*0fZi2xq{lpTQ6MX4+U z^o0}Sz`Q2Fqh|9;fVXa0P?c2o+tZDE{+H6tjV-CBx|2BzBUcC7NqfZpu6)AkI8dEn z9CL4vU2J2uwDH^}wDK#KEIk=!!Dd`(P1kV5Ve4g07CwF&_ z?NC54aeFsjn6i9^x!*=QH~7bXb25^Y#l9!$!(y;Ca^C=@;;!2ke~$5m#P6`h~7(#iyig(Xq;0tJonF0 z@UrP@X^_?*8&*&87sFBRz#A{x4+3xVK&*Efxk_!*$D>m5X-nr}?wrN+x4Sys(_^e} z82!<#Q`)k`ofLkI{&a&MuT@9A-xbx!_&mczj#1k%PhVCSyDV2LA0X6@t$kqP_U&CI z#TPD?i-HuwTnyPF?t#)WVYWqgslD78cAw~XQ13Vd)K;ZdC+Y;Y=S91g+KV|Lv$l`u zg|yS3^v;ydp_m199kAs-%N$op+oOM6Q;4-SP@rpxeM0djVbKhsmR8gDRLv2s@XHD3 z(!Lk-0IoQ`>BYIIx)Cq+*L&y6mzf5PIzi$5TiFV40oRf|?xr-l$@jqt{!>z`5WMqI zABP&zp5%}6gq~P*9`zkMe=>&6ZHg!g9qix(sMI$}{4X1j9P42I16e<5(}uL~GvKWP z9a_uyO-nY%Oc-;eYLo7H+5@&1?OhI*iy1 z-IcVBg9dXBDCdGu1>bHEtE1|o`DoTlE$}B(oLZv%W~-ZwR3q9|M3Po4M6gjI7m(Gv zt7rl!_$Ri={7jE0@6>Yj#7Z(oNKTf1$!mo#8b#XSQ`vK!qLYsmSg zFA%{Ho}b6ARDQGXMHRD^6?jO$2n$$X=P(TXvn}8kvi@<5t~P0P3rkLOjjt;6aR^A5 zF2|}=%KQ0;teJRyNLq8!9L)LyYRFjqS7OQcp5Qubi?KayJG(&fw3_l&0g^>*&z1OW z?3NcOirL$GH$UZ$T+RFYEt;2Ry?f7*XkPZ4-T%>t^^P>)hTFCPpN+oq{y192$G{L| zGu|){rsV+DdY3R<1sLj3ba^Pc;ImytB@|Cf;}F@m{KhSHg(uCredd2)PZ&yQIEk5g zpn+@d7f;|%_21#`vt__@>*h8TeP)INo@EY}t8xqK>AjNV_+(@*yFn)96O#06qm?$a znN!x<0(9U012X(OiR>*(^8JAUk`)B5oHa}>KLDQ0svtP>U-Kb3%aoLZs(=OQ+&6*l zob_%xlH9yxlXJjLJFp42tNaF5ySc9#iSDlF@9T_kJ-Oa>c|2qduG!W<{ky^wl91t^ zCjIllan6x2xu>@(aNYF*_$45H*uxAIn1pMm@|&%M61RSqqk039yp*~H5BLJ8%-$6T zYO}>$x%-G1@OhPd(KC(Rr=en($MI8*;r`khZYYeW_?~;S+N7Y(Z=D`%DS<_c;lXuh zg~YD&G;@-48qMevOdYLRHr<`{OxV=8rnv1(Tl<7Z4CIg9;$Y8o$D-rvw-k45SJBI* z^M`7>Dn5pWk_9-m{MdEmen7PbgO7Iq@d|LS8b)w!`Kce%^I~-UCJ>&eL|x@+ZHbSt zQG>R)ox3DA1F5c}N&`1P&QB+q9`r-68ZJmJGlRi*mf?@6DsZQ%uJaCSZQU;pT)7u5 zmLoajhrZ3cPZE`9sGRV~RDAluYE>kCliF3HO)mr*S%%E{5Z9E5n8jHLS$eV!s1I}f z8xXypC>0$Ln!NLEk)ZCMe?uYrc`-V?Up4&(a+kMxzW?P04BVa~Rz0n*ZY-db=SBez zdqoMHM%xmkAO3@kAJew1%nS$nJu9wPuIFzRQ9ANs+@?~6%~t;bNmXiVkd*s!md>dl z`CwTDj-A9mDnsGR&jq*SE?V=bxbK}eM*MoSc~cC-R`uLgdvCPU#LPezyDQ3~8FNb!|^bCorGp!93gb+)?zNte?USZ>NM{uCIX_7F2ua~V&mL9#if=g9U$$u<_IP;cRbixa9uA!x2 z=iI*pwe!7rH&2gCH&37B6W@Qbv)Ix@RiSAqoq+2oz*nu>v`4LasW;C+NFKm#fbjy?8=;F~V}P=%CmTR%h!%4(Q^JAS zJmjn9Au13`oQk>%g|WA>YvGSI9Xev_l+K|;HI4hHhceALjJHEr7J#$ zm*0J+)Fxx8Cy>W@=1wfUB!+dk_ROEqH0V!l0}>lPEN)+`^A6Q86E`yfQL@!6_<53P zlI{ophPQa(;Q2~*o0VXj=qrzTrS15PWcujx`yj)7k)N64gFNmm1{oGEcAkx(P=qkT zeLL@N<_xDn$G>MrLJ z{1mJ;m--@g?%!)QW%H81o8DJDhbv9^WX%`!LsC#u#BVv}9i8L9z74Rw{;%(wLXkeS zB{jz|)Xa!b3(H(8F&Y2n`h8Y<`4n ztN>p*&`=#Inytd)&e@`OGJwr$V(Pya7bQr4&tRt*VvQ!WFXGL_pa@<{UO=s*Q>x*w z;l>uh%pkE_9pGzlH07@)Yc1pZOE3_P5eC`&PvpC=kSFblx}r_BB&6lrA6kAipY3!GuNM36byJeO#bB?BV5%_pbW{04q30}yn#xO z(pi5TmVff|l|ppzIh}~HQ;mFm;8X|~CtpVxK4TudosVG1=Q8+RfgB1kno`t1peDa= zN*ieVV~zBGyxO4*fHLy~81hJpGXe+{h#-wJIRAhCL*U}S*fa(f1ZayiDU-k`X^5ZXzDtBeflpDbjI z?sdpMFej<628E;g0Wnx8WsE!hr2+diakG9UhBWFDc6-oPk zjz*Mx^4s>3Yr~GDL1uUueMp^1zX}n_QZ*E!nuLS$9=s19bOZ5-DP~nR>|d^{?fL|EW;Nf{42)Zu%!* zzeWX4nA+klj%_F$ZsC)uAILM9RxY^vFATUA(iQ9?OT9O5;8zU0Y~pU04*M{j z41k}$6;-auFgLkAFXB4IN)wM36bGGp770AX>ujaTrs$%x(dQ|`)?_u*GLjAL`3M*! z95Xv+ZqMF4lL;Niq%??G9L^MdWo77Q(V&CTIzW(F#Wv`foGhRmXcFVAZ-wS>UtPL) zJ*qaQ_XPRN(^HNy=#Rx*g^%d(X&2o{d6SM<+6jTWI4cvt9gmIYQh;#@5Fe(o)Fne8aGU$^!Y$(kwp6y2vQ+#%$b;>riFR+>|g z{3g|4i&S17mCj2Lcq?d~l!H@CEe^gZR477!4=iA}ZEeU|OB89NNo}3tc?0N$3iX$7 zm^JP^sO{meTHDRDujcAFq( zpsdX3wNlDksw72%@M<)z5y=f3_aLivh>1e(IXk~k8o>UT&q&Db^9A8fd-wuvFDOhC znTqgCy%go3Rn3Mz{j5DX(zIIvT_r!e%A<0x(%3jS!F}WhQG_U=w6=JKUPLph-Vib@ z!0)gReVjE7yh+6%Y^s>7j-qy$MV}K?#b0N{RGNfKXIKs&s)QRA~t%LpL5T7?)*bTzURxAkul!!j<^1P2C;-&RWAv{Pm!TB#WuHHW9F3(fYUNI>RZls zzW8{nEB#xB#bE@gvJz@E9>GLa!Q10@y15@7wcXBoU0eJ#RNa7hCL}cGoCE?@XKpRD z`!oRH7zb&dS|#u{zOq-YaDHbsV&nyTDjF_vD^ym#0AvJVo@RCg5Q6rL$R)>GkO8rc z)WYbYAEsv=r(k7WC+c-hwD?BhX4Uq_7$ zieTXJ@2}VIITv25eDO|{m~u7f8|(m$=S=`3IdCR2tejo&qccv|%{lM9P|{0Ws@>J| zTfFmdHVw@w%o7pz3KAu;$h@2zEpHi(;mNJ}ZTIJ$l&xoLZtZ?-GbksyL-RxMvbnf> zk*1|t_7y*EV(_;!=d2;D62Y34V>4yiYRtSuctv=8W$qLjYB6Dn^Kq8Nx`-Sha>Z%X z_=TRe?q*?re=khRTEHwJXkcC3nwvzddw<+%aOq12gMPZ4q$0zp5eb3+5e7m7auE?M zsA;H+2|dKxhP)djMB}CUdKBrBR$FSbsuV+qF8A~6S9N`F-uIs2!=aWc9qWF{*bTmE zCkr3I2>>{~ZV=|0;mov0WJ+`a72S5V`?bRdLyEBc*i9!_*_leHYW`bb2^y-v!sx7vnlOlODKDc>WUfUhYnjqa3Ah&bqHd1SQ!da3q(-3D$F;fey zogMYAiow5jd~RVroG!7S^u=(oTdBxqho9<#YaP8wnLO0jq1*e~U`b{vw<_Yg*!3jw zwwt~&@6GL^B>__YAu2m1n#usO7vG)y(4pmlB7IiY#_C4hPecrr_BT5x9z0Q}aFE4- zDK0J~V`+&l9n_^_eQZ$iMjrA$`>w=RGsZ9HLgv!mQGt2Fl%Ceh2&Ay|;C@!Rq za4gIb%`1az_h+<(|D&lvcvz!kz=3b8p3W@5)~EB(XqE{xe}77dfP8G2#Q3tUZ{v?1^^29t8-T3w;-l%wH|IVbv} zE^n2#CrdfbNHwg_9tw5Kpr9kL&i zllf1Cz(r?+C8-@GRFgNFy@*2&c2EO5 ztoB%Is@R{XAM0tTb(or_ICxszyX-FGomb-1ZgI1q^WpFVh4fm=($glYUZ&qtX?f2OR2Q3!9Q1y~aJX|k)4w_#)i5&^I|fA?!q%PM4_rdmu> zH=o6A}&HU$`f8@wlRfU>&s9f9+>cule-skO+Zr0$-FeDjBtVQFurQKu{=Dl`ZA6~PRT z3{YZ?z4*v^X+=Z+e&}t8>NTn0WAlDW5Pu%(7-?RXNL=M${;IHB<~&5-0ob;#xI!in z#odZH2i&hinJy^u_D_XoSh-mX6c~{rq9O-KZP<8JiC&?iFHL3UysX9t`kh2>eaOd} z(djkmMo`a)2v+Gu8eJKxhvS_UT1VT_&Pd7`q~|9N8F?1AzQWT<3E038La^pYkP=M; zh`}Vsp?RfP5Pqp`P`Oby_(-(jLtW_hXU~H=9?qi4=MKk3nC=VRzarheIT@A(ac23M z(nJ@E{=#)D#VFWQi2K4IYALT7Yi|;1dn#K^CjWB|s2B0$8emvdN++Oy@+-js2l2F% zq5rOvN*jDl_91E$)Qx}aVa*Eq49K1k?5HKn5)h#{V2!c9wj;I2=@cLXVBuXl0GZPX zzlMKQnx0*+hG?#X-sM;tPfmb#pV_6My-FIBaS5I>dG01|uA8A;0vk%bz1kwys0Y}{ zI~dBoXP_JGqaLWjOX$y}I8nV@Q?fs$fF2e>3|-y&r7pxblBQsW!)!x7f!NaCMZk^t z@7`OZ|Fbt)bu4`&EkaN&T1y9TsMgQ(cTtm*xk$-&xsk<|$;0(-Hd9c}vGIkHVeRb* z3_!*BZYSW(qg(ey^?R*O$Zq$;9a(K74jTc{?IBQd$g3rYB3u}fw z#ii!H61&_P1F;9TIEePS>rju0TDFr+o#~W^RCl8@B-(q!Ikos95c zQ_t1{B(jQyjjOEB{(QCk&lmo78*HQu|9P|LMWEN7Jlt*+r$R|}I164%J}O7RS;j`* zVD+691RU#?6^nh0Zt?lULp)@Ed>o9A#_x+SD7v(2R9P$brMm2tPy+JEz95hW)FSyb zcf$5B2EnM&gjn{ddN`3iJ%-X^x%0Hv^?9_6U6s5&cWArj} z?m}AS1Cz+Di2Z}`^2>5QpF-lh!UlR+!AZ?Av={G|`=_WQ_Cy~`=WxMNmp!(su&^a( zyP9NJq`Ua3JME!6z8(2piC^pBp%W_g)I?GzE=#;2LBM5G+I;0i!Z&k0_LCYeb3#2V z_J7(m|KTQjGznl89n&9Wi8vl6-Kt=J4IS{Un6Gtt$&%va>gdc3ie*~e+G~#8e9Wrk z9rGV@h5wy1{J-;6x((}Sjpl$ad6faWZvPC>?fCC=QNfyMkan6R=U-)wrVkuyb8;n( z-kvtkMhJ`^Ir0^PI6n7+vTPk*NR7pfCZza2m=NvHStmGD#a4s#|Dq|N3bz7O;V-$+ z#Um#+UnsCY(eu7u3emoMGpsjry;u!Cg2sR5fI&+(C9l>3Z8bRxSqF$wEF^u9-?YC+ zA`IQ`5gUj|&UjQ?E9jM>%{W~~l=(cDv2HmzoZeieCGyR4fi9|@((RRRJvyGd^zdHt zpmbEnmDW43&y7haz=!%Jil>~lNnqbY{@XN^zo8reV3{=yoPa$rp|4 zOk}IHv7Anir=g;U?N&+D^!I5xbsIgtMVwu*{^(TI`uFc&UB*3c= zo`8}8yAzz$(L&)@^J@Ft_^QxqY;xQsw3qSi1q+=B?<50?UN*-Le1xe5hu?||P#;>8rSa$waAO;I5^W8)NGKIreDP(oy!Wmb#gr(J~-8F{Z~mJN9vRP)5VLg6!l zMCQb_)ju3A!PZK`;(jaG%Rx@uuGhE%_UW_mJvElim2!vd5~`>^jIHz}=+?!tSFiUc zFch0mZeEAmBO+_&J=NvmtDnDNs1MMQqClc`mMu>8@u#BCT2ocCdW zyD#QHe;-_kE)ul!67s~32?0^mzypvni_PYmjlm~&AR?JCi8R@UpM!hJrH3?c zs{3O&UXxTE6n>?`IcbsR$?(1Rjw*GIG+hkLH}>~gPZpKO6A@U0Nid>F;FtjOO+|?0 zm3gn9&Z;e32XSgwQevgNC9P3_HSKd1n5M<$t5%UTIk`w(aH+)?pP+_b&U9%+2h}HD zr`Ao`>|8+x?FQK62m6O`TfGg#-->7z-f08xQ?T#YCbvFiL*E2-i!6`%&eg1%Kp2A0 zNJqki8iid>1^D8_A0;I&7r10$gCeMlq$zm}4J6P$E$>!5QUzQi4CB3bRA_SW$ct0R zE!;i|Y)rWcjSGa48iIuGR?#FU1Wu{P-yf%E&NJ1#uJ#~z<9pn(q%5k97;OE>?~}X- zIHGO{&a~>LPE_lUv5+4@evlQ1Vu1ips#{`a2c1u6-fM3$YhheStPVM_V0_-MA)&-2 zai)AU@bi_Ji6^f_MNTr^{~bd`>OdPrhBv*4iZy{a2jk~Wt3at2X8dF82oN|wqw zrV0;xA{rO$24)oq(5H4cU@C(gQxB_)wx+`==(Rg?G&xixWQw|jgZRCCFeb41b^985 z2;Xdl154ZP_O-+XI@1`ejwsXL9S=OfEAtqzX5wCdfhKC4VT?=JEqfG%?HG-qE|W&~ zvl3Xte*$%QC^HDy-H;y@UlslP$1nVXe6H`LTvG-5kwqP43nX{GqA1Xn7>Ud8!-ye7 zsQ2E0?$P2B7jyCgR%s4h24H&`9VQtAcpL)(uYkpPTb_2};n9j(`490((MI5P#7Kw3 zg@c4bIuh&8TzL!`bglu-D!&DIP~FX$$y?zc7tqW9*fuaAR0kQz;Kw&hLQs#!z@AF% zgC(H3bRYqNc((!DMbq#4u2^m1F5Z^J1S}Ujn4Tv)IHu6^YF(B4H+MGc@K_=N^ zgT-uS;ZN0dR2fFBdTsrMy^WAP>smJFs8rIYS=*2`$~jiW?f>Nm?|eRTX} zx6IF>@{=tgv;qa-ORmX**5ILi^a~Xy|3L~_h&?<9KsHTWJSaX3aT{6{?`~(E09^+D zp!Emi1FAfXA;`$3Po%PDzx1U|65$82fm-HRBgIi$*_F%E$+y!pHpnE`CJ01> z9bbrS0y zivO3ZiGTi}bm{A0)hg<_DG@j!f;0u0iRbSmHvF*JSjTg?$S)a!5;nB>ZFS`C(RwRgvjx$qZR5W?W!Ev zSiIQ;-ihtrn|EN!MibJPR`U(zJ zO$yUljlGE1FjRKq-n%49l|VThjIi?{vz=8o(*WGs1ZIJXg4Jccg(=^YY**9(Ei!dm6BEf%UWj$cfeGVpP=yQRv* z{doMKLR{Q7A|xP?WY%hZ7$CL2L*BsoS?3dq)R)sJu;EiPNB9&JA6?XU=|3KKmKQfa zS;`;&hJ0DynwrS>4lk_8B9A0!~?$o<{?}dVL@4>_u8ITnswQWcF)0>6uq`vYKk=II$FSJ&L z4=as3m(v%5y3_A9xW}+_tVyR+3&`xvL9Eoa*Ho7wJUV=(9xixZqz)w!&+TtgF0HsP zAUpWtb$hWm4nnEzZsG>hYot~${n&8D&=bYh{*7qkFQVs_#kiKvhM`Y-u~Y^)gM=EC zz}%5gA?(!NvfdhWylzLgVtY}BZFHagnfz42_mw?M=Wb{VuSNw}lEiQm61Akw!I11k zo-q^QlKx*1ynw`omEv1Z_bVI^S}t8oJ#r_h+P=G9hP*oU$olYy0SztEOlr+@pJhl(HC6gq6Q19wV z*jb0KZb@aK@*W)zQ6-hp{`i;hi)GYAJ4eo%+V$xeq)n>EY<#d88>swBvyV`vOkHL5 zfF}eAW7-1+n|cCH_B8^IY5t=X#RYCTW9`XNUvzR#y8e8qdc1xTpWjwzY}S&skBo^0 z;7lwqR%9hbQ%h>2K}us$-&3~Hz0&7#{z}+KjC(!R3SWSMAq86viRx!G6mqN_3WTcM z6t0|5{slSPePbtauzs!yUdDpXcA#^SCK||EfCLj2zLL{W(wCF=UE|ZWOHzQeOl%(r znfpPuwct-g7@xT!7?G}yM+7&b7{sbbZX3n?l!tvqp3XN2#zimR@F_bIEMIZ(^%NR} zb)`US=7QsaCh;ED2>PJ+(;tm2Ju-O_Qm--*RndL6W_k!&>;0k$-zM^# zyCLCCB>f1g2C6lWE9>VaJoaHn42+rTocC1!AT?t6xxg~hmWNq>;t`~;@6ieLmb=k+ zNs~MWCc<|Ug6*~)wl$F({R9nl)i^R0=sjmxXI@^;A1`#h)HlcHvs+ajJT}A{=R?Gf zY#ETfGw}tx(2JFWUMJ$0uM=@6?mzpO`_y+rKaGol_*l~^4!fIq|C_9af37k4%GdrD zk+XyOgL0nK6P4@Y2S0Yt@Y#w>eIE{6OL&M$fZOi!x66pb2)6wwM__n3X zGNva|O?iQ{d2sW-$>(#6+FYdcWge3BO;USZu@ik?|HgjLWou^zAKGzO`AgTHxqo6} z*a~`-l%No^q@hE$p}6(9Z0tPf3()j;duxI7amYZ0kIr1a9@oA^Zt4`c_iFkIuWE6ER*TZ-Tl|3#>mdnP9v(@2dDzZhQuIaO)??YZ}DyG9qisL=#~1&(L4}+5PG?)k7}skns+t)oCtoqNJ!uEnRgN-I3@LaDp!uzfiBwRPW44^_W@L zHxF2q?3`@=>0=+(!Ao!k=yGyxr~?}^9?j?j<$`FQAGMk0xIF85o>o4k>sHOSS8oMf zHBc3d@QYcILD`|09ngZZ8g7onYGQfKH}S!vO%olWmiedMRcwiKE}M~f`0!YZpLbEN zJ^>zOSd2vJ$835QX$fDoFx;0?uRHwdz=dI+len`&Stpr#@Z_zgOq2b{8&=C~>`F`5lFYEJ>Sga#&$&}ub68zV5QkpqpOrxAV+>$CP;q`kReA92}+5v z0Xq2ZCt45$ll}H{Ip6)7aQgNF~2iC#V{}3LlgGE%k4wn&?nKK7Y^g{9S6yymN{0hv@B%5t#&Y0 z%Y|(X0xM3qQMS|3hxrRvt@Vi*EsmvDC)L=FUR{S&iS{ZTuOW z^1uE4pI|GMmX!#T&6hZo$+xB^s*Z2=$Sa(hwK8{iJ}{DG=gGP12DPOb>;!1S@&M6JT6sx~1W?Kzx*) z`AvDP5|_d^49(2zW<$VjN(N?Vco^Ol_q)ISLq=?BH6+ux%4Vt?dXQY;>MYCR?)KHt z0_2jyHK*jZ4+fkA_USV?H3sqyc;Mam?%l(%J?DSu@6JDZ`=k~hC@1`e0Xp9loRlU= zcKQ=EVCc+)(vJiCb%GHXzLGdJRVoaa$k}XYQvF`xbnkgm6`iXHwa0<%O9S8X8jOl2 zYyk{TFIW2EtzhiDA&7Od-TlK_{-2JfaFvJVO7)cudn+EKNg60scx zB>)t;_IbTS>&SqS2~bw)=^UuUSVL50qrj!WvGorbY(iuG8Bjeb_-@+aW+HLC7zA6B>^Y zcvN1bJZ4mWBQJ^b#qkr8{O6h=dpbu7Lw z(AU4~zI9K#MI>KnNTDb|iYhZz$Ej>`FhGnf60W(LIWu+#Il6KilISukVzq9+%Eh0t z%|ywi%J`G(3`lyB7IBkg>C?hG= zgk9=w9GT6fypm}Rd9zlTB)+Bqt44mx=D@N9FzjXo+{44!7G-Qb!w8lFUV@tN>*Tyw zyg2bF0Z7CWANE4J%BJA9=vh+rH%De&mUZ z_AkiYAxXC#wg7$pET~lBhzVz9*uA_v9m*}IPgKQ83k-99F7$hJ?x&tp85y&bLzZhz z&pJ!CwHCKT@k}72z0`%3Y=XyrUOkdFoObGtv*GyT@s&B%Y_4hgXIR<82_yFAgWuUJ zE0EoB72Fd(=b|v9YXZ(1{zolgBPtZPfuOH4GNx;{@lMZj$^q)&v1G;exvN$7?(v;z zLY$phuj{Eno!CRrwrDTbias>1h#0M5+BM50E%uWd^>T#RHSM_&V;>BEU=o9XPPS(h zzsPW<3`Hw0CYH1{T=u(Ibo@*Nq=Q|MafB8ABc(4`m=udgfDSEp#6fmA`;YCLM~@^J zJ{SnN_FmkFZ_RaWg(rUK)CF6haJY*SMS{9PJ2$)Z->x1{A;ejLDY8f&GabOyl*?kUwpzgmo z#P{j1SP=@CCw&63g>fLKDowh=ZX9w$3OhK{PQnyNQVZiNdq*!Z~cvS-#LRz}2 zL(nuGHI!}n=$#_-nSowZqv1c~MT(@{B%`0u)l3NL!{v)msMw^!w65EU-Zb-({XX9% zbsw#0wyS>&G@)35_Bj&Ge7;gy0Wn6?OKE#N^8D(>!9v+HHK!r>W-&(&Gq~dIn@oZc zhboMH^tJX4mCGG+NQ8}TSn0IZzV71N-4QmodgP@pm@4kJk-M7%;sUU6IFx<>nbR61 z(o-SLY5jS?$oX-A&bv<~RSYi^AK%=Z*Y)dYMu%rf^f#VD_7mW7HYKG4n;)GY6_xL> zJm9fxo^@V7aGD+8AxbQ=-YtRBY*a}z*ljLG^WlNIU#CX(YEY26Pbe=jUz5kH-* zBEz&`R1|(Wj*lUxxTT;;W6^(+9*}0Op{e!3^VK%oG$lV%2U}nU1LB${camsHqFx zUmU-edRAqk^K6MtUaQrFFBjR+2M}wLR3~~nyX!8$lK-jg?FXP^es8(TNc|lMVJ(Sa zCqJ3ZuC!E^v`6^FI|HKTmt#G!fGz07l6B2On=S1Tm6@c1=bVf6#br^Fl0=2NkuhzPoYuPX4z;ov zN`tOVUGjtuU(1;y!2+g~;n`pf);1KE77LQqq_mo>--6+G7*gT$@e8#uCaQmW@dnCP z@>9-S==sn#1*6-8ec(D$g(&ZtRyMKmEwt$Ha?H0zc3(3}F3t}5@O?!xsplrV+z2qA?0p;!HE+RiOZl4*6HS5NILR8A8c&CjHmlfV3e2n3ub9&^pl6gIWo z@#&e7p(gqD5+9kg(d!8=pan3SFhq&|59y zC#qiyRj*K`S@4uR`2=f+W^_{7evkub-CG|`XE3MiI9Vh}$3_jaM5ri)!&jNAK+Uel z4mV9N5Z;ugEOxm(#kl8@VqNS{jk+YEr+U1ZwmXziKi|8DCbNs{I)FB^Z^cBxxdR;E zFJ^G&6*+nLTg=N)s&gXRSpuRpa-Tl9z^nCO-{vOBghyhz8kwkLcSw}X0)Qo|5>_0b z>q_~~y9qt~RRUBR<~CD^flQn)3_;H#B;yL=SycyRNZ#ZH)K zSN_2u`a6vKpJCnq-@LC!P<{iEjFt}&TkyY={V&LyEv02%{A7h}k4;Wa(1ea+0vD2RWGw#a1S+?8Suka}_|2Zj!gggFmFD0RS;3L_Koc_y?w zFt%TisWo6nCtPLq)qRX0HEJD20joHl4wXSsXJCJN5Ai8C0~Rbh5uXoCa5mK6K6>q6 zu7HP4)T1fye?gL&h|ui~*!I!EDe5X|$cOfu99sf>{+tu2lb7zqI%47`K_ei*$}KMg zrBlVlb`_&fn+wO(YsTv#unfpHlfFRT>1HC293s~mqtvH$j&{yUeqTDsu%wyD=txq& zRof985izw|8UYF&Fz))3`Zl{Ydk;U!)bP4mj*5VB!soN8H$b6S8kXjs_~#43>Z8)3 zz|SC)`sp#ya5%~L_YeQ;6{d!Nhs7^;2Sbxfj6iQ(4UhunX(xhy?)JoSkj$HPX1$sK zgCVUAEm+y!6#>P2#J-WsT}eVCgjwbFB_kt!k_w+o{LQvK~w zL=5Nf_~^Xp)h>?hhEm1T$FAO-*(RY*ZS;~S@oxp-+#09ytJP*OfQa?KFzo;4S-=RB z`InYm3z7Y|$uj8Z&6jMeH+Z7c+Aofdsn|r^*dYjxjA;${JXeKaBtE#)`!E05!SYtf+`}&RGEoB7VW>XAJokk2Lw^y zO`#8uASF6LU@N@93Vq1pLn!WMsPEYs{UOAT& z9RqiSMs3?x$%;i>du?efRDAvzlm7kBmXIlXN!GqP6Rw~y7DKU~PMQ`tN*MLYVEWT& zF%>>O?sKM)xHoAronxU4yaPcaTKfkzT=6Chd6D_Tmu5TLDt*!!t{!|^sKWLou(Z=! zn2;EO(Tf!IBVqEFp8oBZj2UT0*>|#0mGg`j^=(4P>CK0B}x)L&9exap<;lbNo zK5hqdKXH@#wC8>BmJ$!7hXCAN7Iw!E7xgja@ zVjUPo)!if(b4*37-fo`8!*sRFQkpa^>*uwj%3u44OZE1SwD+(`EaQrn4Aoo49|tdw zOjNQ`8p&C|-ft4?6lZs-;`LMgYRo}$M+-WNFX${8H;lA2LtBy~VnIdIc6stgQj7A( zA-UrP&R_A|KO^+6oK3MDUB#Ki0v>W8X!T0@^D?~k8L4Sy_cat0+77z8QGUC=TAyq! zE3eOZjS?9@$H4C?knh0=~y5nuo|8tEx>$*#;Hzv2Vx z?AP1Kgn>$}8{Jn@aX&I(?I`ZlN~Y%!%0OHFSPIY#oh zEm5^|i5hF1u}Q0QDE8bvsGQosEvS*QQ7m?Y+*O%EkX~k6rDT$ym<{r?^evC!{M?)O zWhYe{0@H+6agMdXBW&RgOD@T%&02I9O+RAtj(YzGg5NPnD#p~XI4{efh~v78YnI+4 zTgi!Y`PA4JYbi@?;)FnKlSKl?m&kdiG1Y6Py@YvPLd)kF^%}1D94k0l)L>z7ZgE{C zU6WdQ(QZ7~vq&IfLv%NhH{8n(6fUC<(Kzh_$?A8=5732HhRki1x%cv0vpMq%mFN8_ zN=qmX4Rs$pED|tJxX!7lRPvn}GnQ5+th{9q-}=NmHz@$NM*&S5;B@|m{p7$fS;0?> zrUMhQBoxGGbi1rSH#R=U9Nm43oi-s2?Z)vI* zs~hLnWIPiT2jdRNS0Vh}vz`$}^2!?315OSF@Zz1-h=$a3g1=E_*L7(_S^lM^kA=mC z46nuDa=CtHEugbc)in;WxtxQVSMdxQK(9$4QFI&y&??JXK!}-?3uGgAxC2xqVoJzz zp`o#|Vg>}JG>+xbq=t$%PzQth&x`T6@8PmSz8)i4d(T4o~l=ri$cyPD9LF+$(yM*%imfFN1j%vhmS z?Q6w*YUxT#U+<>j^^=N}WWC$H*KZvI*l=?2GaY^enmP$hz{beX08nAP##PVnQeM>Q zIE2Xop68F~tw#;MTVHa33kt`P4y>p(r`Rv2Y-G2RI)g77pR20Sg zo5uaoj0J4Deyd=5|H{PYc|rC4m6zT`FnMK<%R|ME*R!@x?5B3Wza60QJ=dwW5z88} z(dm1vx*_Ac%&Nw#xyE}*yqVJLM`F1$-O|2RwZg)&NAAX&sp*CI#ABO@LgZ1ReL@6dU|9HxiA#7-hk>b z%@C(}uLbo_$ko-<8;S^QbaOdYxmK`6evCD_UuX38T)Vu2wbB%ZBfto-wZnxBJ*F(X zTr9);?*riO>e@Q3$3}_DdJ(>svxwh>-ycq!5^{S*s%uKevT2<~dbBy=5!_Ba#<@Sp z4^uQ_Px_BVI}4p^y}HljyWz*Hd!>IyRI{ca337Y5Yr#Ca+&+5KSk~>?%H6(=02PyM z58~UYK}5V_Vib(60=;ki6B&UZpUBF^=;VLDjaV49eK`L~?6FOy9?YYp2tC5ylrb67 zDD(p{md2`E^KH}rrRn4)d(#~u1?A~jwkth3asH<0Wzn;eIQWiW5q#tF2E$UX#FuT6 zhnKEwl>fJ<75>htWfn;v$OtShup^E3Z4U~L8P+>KD775d6OZp0SwY%~hH6!;@cudD z;DaE&t!D=@aYSS-k$(OvihOvLdea&>Jg=m2Sn8?0Xniqe53l7Ds^t|)a`%9>Fo^Tt zgwb?iq_+VFz$eWjQKVa}KxtVyAO26?1zL{4!z57Cmq@F0wrp_FN_WB?SHl}Q`svKb z(%GRFHO_`s@4963a?q2zVtt;yEs$ZNKJ#~nhT#u~riX=|NJ?qyxKzHEw^Rml@Thl>h`u#x6r6t=xzP_!#ZKhKBQ{DewHWOEtOd7&Zj`G0)(UKx(gl*#tN zdQj{Vx)+FFbohUIm$XVN>VO8PNXT1xfH^czU_F*%6k?#dbYTefuhm6WOI;*fb1imh zl{5jGb1Znjf9sB1%FVc4{?Yv7EU)+rjHJ>+Cn>h+4PyX5o`727-J9k+*d>sKk@!Zc zqqo(;cDYl3L~j8`FZ7?610ZU_7*Rc`_(>Wsa64PgEcbZ7{&(Mn>~6!1j2V!v6Z7Q4 z6#*o##kYu8!W$~R3%$pfZ?$XP`~`8^c*`12S3WC>#Nu9Y82|_h_n^ob%tNnn{p>mN z8=f^aw{DSg1|lmsOa%o(1FZ1%iQ8@|pbO#+=oTCFqgH`}Dke#whOCDYJ@h~x4f&Lm z*q)t@YO%!Eb3HG8`U`T&ooYt3NE2(D5ZniBt@C@I#(>VI91##VyG4^Bmul-E>u|QP zzdbk)eSr2*G>p*Ac^6dkcf_G-#{Lg9y9Blr83+Y<*Z7!f5n0kKeDSjhT_Qtp{IMhU6Ay?>~UF8B-5bOcV#a3o>cTk24F@L2^kbuEP^JxX42=m5A# ze1Lyp)C0|rbOoU@5NIGcvW7P*GbI6B{;)XI-v(g%#{j}wu!4*sppeohg2ckQeHaW* ziiB-%Kc^*2nm{eKgE2J}h|I?MXF$j(s$Qe=sk2&gq^VVOi5C3U`!v)68mf@Gj#HbA z)iBOOj5(|+F1Xq}`c#vk@O5(0dfH5EXwk6zovMaN$A@g_e`Fw$F{82ci@;?<4L5@- z#n-bKJL?>BHdJtr6;G0r97}H~cim-Kc}pK6Bf3eG28l*lg3jkF#@slD*esM>Wv$J* z3<|L9)w{16&!UDZLB(74_r9P3oEAF?Slw@TvGmxqV3=ftmXcizfZCkmn+lAshHZ7} zP4H1ilHp+fMnov`D6-O0QzhYwGQFIftOht%tAG@p5e4FK@sDN91qpK-qU$c_#NStd z^1?sk?1}?Z8-EM-=)g3x3g^4I!|@zc`#GWjO!BZcYg^+{)rHI>P3&N6#d-7`l9{Yg^mT^+(Pir2JH;H!{18I7dI)U!t zJpploU!z_lOSaWcM$C~-qRX9Ls^|_72WXk%QKvsOXFw<@a{die z`%7)+!`FWQci_+3eW-8?BeDA)I~|O~(HmIl5#v(+8q;c#!amNmm#)560Z_! z&TGO#McTPTDR=hGP0r+FT1=SKB1AYyKUrVAl;r_H2tCXQDgw>{s*7JEO+eVo8&s)- zI9|{ZknX-nLesgHK{|)i1{cr1Clb7lg*A z1C)Ocv&mnBD)?)r{(mV`$EaWz!Pc&60391v2U;46|Gd?h@cbdo-Lzx>+)vpaMfXLv(H_EIU+)b!NZJT&l_y4IqzK6B!7bIRSlMbMs{@&YnWpjG6!i@G5Du5aShJMdrgY65m z|g z^uqD+Vz_I@A}Kk;3sR!MU%y{vaPiq!g>nv}B&NvMXW8%<^MoC*%yqUQ@dL z-{_L6J=a__y=1#T^1SgpXxhsc0DB6-R_@>kp~9`% z@1DhTvWB65vH%;kwQnro3@PVWJ!|6C1;knWJEH^5_bs- z5_Umx1%%^s>34N?;d@tiRrkkr&0AA7)6>(>^t|2uKJRn$^=1n|`%p(;2Y`25MDauc zfSXl-7JvXB|DWTw5Z)d{q(nr7ghb>dB*dhY

YHjJqFbER-Ix0FQHZDFPF(dO`R(4KqUjB!&@`}o; z>Y9&D%`L5M?H!$6gNUKwk8Z3>7|VW zWI!2H43pE#S#oB6S(E_wA87v`*}n!X@_!52e+Kq%xR3x!0=(P7BcKDQ0scPzka!R9 z|F97-jHpV_frv_`K6wR6__}iNKh^RT7@F&re3E+4$vnftNu4zDvyr;j7@X$PbpJ7q z!Wb)&Y$a+UcclBUwS7kR@<>xRb)`VmF_l4eSNmC}RDHGJF=JWT|F>+faYPzff%ADWkIYs5Mg)0m#l9=u==;}&_3QQy?$dSap7vZ=rcU^>_(_J% zkv!^INHD+GtJBiVNpZ=0>Z!4|+nKxAj?X6CIAvEDlvc5DxQjnj|WZR?=Uq_X0RLlE5MfrSfNrdM?>!$>sRE z6D99T1I@|F%two8qBiNCvzRT(_JAKYEWxeNmcP;%_S=xjn8CIrXRZ&c$PH2Mr>>`W z-j46;%+VfDYP_-M`;8K>!W0Y^Q|>OnwNdqCp1s_OllnPBRYN&}O_TVxO74#gxF@l~ zT^|SJ$;U+`0~NFc%3%*nwqaDcA?N&S(YG=?_-E<}PYhQ^M?jY)Qm! zQo{8`m&3TRx(Tg&?KDJFg_~&swL9@$Ozy{GZruSSUZE?GfxO#_vUo*;9wrcj z877F{v>J zdsXW|Yv*pSGAlutVY`o>t*}`wu*ph)QqD)lkDQfyHM-^)wa>$$D*a=F89O?71E7F_ z_Qli^Ti>oh@)Fty=-c>ML7K*fG5xOH5;8ubpDVe4q~SJX&4|h>KKPOnB&Zq zqszre=_d%nbg_Q7G2_4srM%7&@~S<{DtxY7IE~MbUFdnE-y5$>1*keEHV;#W(CePL zGTmUnN-g@dQu#kAnhR=(o!c86K}u%N`?|Jum<(x}v{=Hpk$+=i9&(sMD>!-vnE;kLPFI) zR%Q>I-#<-wvc~y~=&38P4=Aomij7NPZI8clzX+`nycXzXYG+P-lKeblPmBMPt{_y0 zVLnv}uzzK;?Ms8ZyQGp5Zrw18&KmOLSdB@Z_!bdQHYs(V(ItO3ZRoGt5IBtlC-Hb8 z{oT8TfWzg{J@X?xIbsr)?f1w=PJhT}bcd+U6u*qZg@R%d>ug^#1_5CFBfUi%|#_ua~egh9W zkX;FG74)@xSc?M9-A&2ll9oeyG+k_uti&rNWOLU>_xvZNj=gSMB;UPqz)T`kl^wjm zhyHDZ4h>%fZ^MFEfQ@3^VVxtqH7`gPL{Fm2T^dIiDm?t+b$qJIIIe4+Jki!58vdwDKt?-&@eRtXbNN2th#Syv;eYyXmwFE!$-v1#J zAsFVqkNFlE)3F@T%_R=bUh$0H^SE$nh{zB!E>>^cPI;$L*FX?}xASnd%p|RwFrB)$_4_+xlK1tgAZL_= zB&2?j#JD*bTMN-gVi?KEg2h-xzX$o?@tu7ED19R+$K(vDQ9-`jrjS^-EL65U%`tBr zPfD^7=5U#L4>E{-+`7Oixt;&LwgBsfsHehh4c~1pNB9Q;_%<%2XVzE0)g+>&n;wMD zzA2&3NIXm5+T_3)>V#86TD+EQnq-TaNB0J8LgRm$tra z5pa73M=%uqeP+_r(assr#U(@7)}T&S~i^lsZ>Mqzfe8AU27IU z9j-ffWHWqY*4BZHGl=?3pwb=WiZ+`nYl&M?JM&lJck@u*1S9^CF9?Guy_DlQtEI!W zRk_KriCLA6u_u2t(yf+7AA*8S!$vIF>tOWV-bR3D@{k5a{7;;n98&yFJUgJO>ZPU5a5o0Ci;C%~8AVPfSibI613L(Hc+ zF$BroNAwMB$?g+#gp@LUe%N`<#s#<)*LqQ@M;XpJ{Jf}#H+n_W`AyY3d4B1V2PWB& zMa!;eu`}mssOzN!Bxy8!rEis6wYe9pLZvF(-Z5jf)z;I}#gJ6%emzI1sm`oGwWqpZ z&{W3}a1zhc)Y><6!tLP2eq8U8Z&+Gs?~!wUVV@x;M}eyo+ld z%3^{~b!y_p_+I)$9EN*Iu|>68g?uMNucu?Dit{Q~57?hyyI7e1dGVzQ5r{cjDi^l8yv5J#> zxQ(JokvoZb-5w3n-kwr>(wV{PI3EBGrz!BKdG~!^;B&Z#@BQC8-SD;;y)R7qgdPrI zpEt>&8bRU}Xo=V`GAwcTs}1k-nh;d2LjHmC?{cTv41Lw|V$;_%#PYDqCpc%lWrrEIpl_$R5Xg>Gj$u)%peYJyP^`hfcMW z>FY0+wVVh$0)~n&?cK|_;>(II@{BR#o!kx97&DRypR^Ca(wslV`X+M>n_oDjLe)w= ztb1V}4&<}LF^OP_ug>%KN_V1}`jQo&MRLCVh#!Zivt^;YYSD~2Nr9SGRwcT^ac1@Q zYi+QgzmYD@4GVWUe8iSbZ6bgvYf9cTdX3%EY_o}C0IRthz*b2y`7d8e$f#X=rb$;T zW-8LNdAKSx$0Q#;RerkU0@mL>jrHsF0aYbSidQSuecRfo-x>$mpk23~Nuw>*|;^L@s|oX+)=M9>JmP;#wsdgAFx@(q9*>b+I}brVez?E}~H$FfVI zI$P}Um$fkqQ#FscKpjK_vHI}e6pfD(IE7L^Pp*fOAh6a~iXA<;QuO4y+faUA0!;MP zSb;Vsu;QD|%8+3GhLR|s)iED*S}1FWTp`P}v9Ly+Yjl_01y_TM*)}4B9Yj%fMRyl`s8z{bgn5mu?CmS9y3|Dtygyfrk*oXW@)5u~ya}** z)j>PC$8Ykt>M&yWt&gzno3AeHYqMc=KZv_x%m|#MQ+@d$P%*rNE%r;+rRILu^p!y1c`plAwyQ7h@UWHUFrYc1?&RqB zcajIMiI6eZhb+CUGM9VcXj`e%H2SdN*XQsJAe@Kx)ydI%(BQ>rw69#!G_}5;-~Ftg znDJioOV8|V{)E{V=DaQwLlI2gE8))^xYoS5#TQo5VTGK2!SyXl+yc#=jw%e%Uw-~HAESM@ zj0%n+PW9lk`@z?cPFW0uR#+a}_aQc0guTw&j-f>8LS-!c!3JmN{PCuN%!=OIKc}{z zf$#v@Pr<%f`8up39K@z;_kSN2*K2I~;&f$cSidXtdu*#1u@36S6rxh~1Y)-|cEt`{ ztiH6epEx1if-{`VA{tKQ+r2J zwROKV{p?cHuucdE+#49g6aij1cF^rio%sDE#nDU8$9l~+K9>x%sQOqZsKt>i-ORF0 z9eX*wLh&R`9s4&sWt)mevkU9>H7}(&7TPW670j;NnX#l&ZUHaMB@=wi-ZT<5IdOd7 zEm4&+DLnDQVK~&tEW!YV6UYxgl%UoN0FU*4c9M^^wA(3K_Lm)88|E)^H>f{7;^j`m z3XWd54ff%AZAdI-92)?&TQbfMEmvEI2Km{Zk;2~+>w^Gz{1If_HXp;5H#ld@mdkrE zRf$KLT1_oW5=a|x0If$5N1H>28*4o44i(P@cDL~~o~;b6kn*Y?NpTx@B!sblmxfd! zUgspXtfugLc6~!kd5d|Yv*oSw^4-0+&867zbF$Q5!qwJ%z$0o+YAJA6ukG%Tv;<{F zI$Zm}IX7LW6z-wZ)6~t+pT`Tevi<%1Pm5SyLEA>o0QY4^`&!cCRC&CtvtSzqwFm6> z3H)@BIQ#kSSg;u3XQr}C`+aj`dA$s&R3$?9flbf%%e9fDgq%_K6m?;rkyY_>Mhu~~ z!)*>A zytBTPaQFM>C+I#zC~(lvwkoC`ZsU)dvM|s8!X{R~n>cs06T9J{*d;5Cdms&&Td$R4%6~BbTeQS4!r2K2TWg1Lj#1#3Wtu$R(=h_~>(!G*41$d5|K@MF)*G<_=(t=UApBB0p-aW z^wrF#010N@Ah&93_iNV8zg6{mcjS$8w>);K5-6+b7+s6x%*9J7pkL26*}^6__^_Mj zzUQN9pH4EqAdFJPj%Ar4V)fqQ(dYxDTFV>Sw?rw3;IvkT=e4oxA!w3Am@igkGzU4- zUAuBOv)Usk-}P^API;1n=Cw#tFz>0j1hd1&>PS;?0*7{wtG2IAOf}doHk%a&i)rm9YamIe;z+1Q-MT_S z=tp~;=hR+T?%#dZ7MBd88o`C47Q8Q>n{7r2I~Fu7Ecw&1g4vGM`laOZ-J(eju9d-ZpxtQ(~%+-ZP-q5};Q?Ium17AOk zlQz~oQ6okr(2cJ+?wSfRIry3;{z{?Zc5d{gTrb#{EeQFGSJ~Czl^rBCDZS1&O%AFv zGgmCeV;oagiI9Y;J%kcIt*Q2jX#CF9r0jDv~I7wjx?dtcUBQ5 z^v~%PwUO7lF`_LT;qey|D@S2G^%3U!AQ2&d`jijfuGRWC8}QmIgTE-&P1^r0h)Z79 zO&iKzuPgNg$w|Zo{7?y%nTWIG@FUFiupMe-6KB2aAa+kBb~Bft09T8y^^N7`#1h;g)_1y9>9eEyy-XnaR2arCMqSiuL>tU3<7^V zVDGKrm66TwX)R}ID1%N?qGt*M)A5kg%yjW%+nFdeM%f;%hd7gpE7>Nj+|-vU$NR98 z_$wQpn2N=xv95*U&0=r`6S$aczbfP8?r`@D_1ST|^Q22ti1-b_D5W%<5fVR~E3gPs z+Y)=ZH;8_sVz-qcVr5b$N@m)mI3hW<5Mkc)_Y+*GQX=K}qy^^xXa>p^c3}>yJ4n}X z_Tc(T%ZheTb$R=z&m+mD0MtZ{KB%y&!970j$9zk>A`3wqkwKh?>_tOWuf0_-!85By z-Pw!V(S~1^$pXFED4&;08?GijXL~UwlD1N1f~79Ns)~6H&lr&;xBf6<^vJMuZ?al* z{~b8_TxD=;TVtxMP41bnK0E;CxuQYNiYb)FRe40e4F4blX!$>-~a{mpVvU9M@ z_}&-nodA7;Tm*AJFaGe8vkiP)r#H$sd6QPOVn#0Mh-J7)d>*+xl&$tGV-RW8LM7)E ziFz~$+3{`uhEHE&Kqg9nE?)&ALQ+f1zKbuEQ4o23IUvL^W)DNf=wS~e5sCAahC!` zGU`%-sSavtwjEYR!a1*iw*+t0@vju+kZzIipD-iK*`;eM3D#QuPzsU3nYEKMI~PrW zhqOrqg*tP90}`l?IY|l=(0B;~%NEf$&-Tt%PPr2Gv}9~df?kBC>Vuk&fH5f>R)oSP zl9LGrudCt$Dwls&pYRy=%(*;s2{F)MdX|!v`2OgbskEZ2(t{FtcJGXwW;OI^&!=Ug7u+p4qfUrag49J!#1HFiRxcE%Fx^#kn)4vT&>L z5hTeXkFdS5Jr>GTyS{(EFZ$&HErolXIq5v1sF;X!-Q4YpPFz1!j8xOX`EFamg#=^a z2K8RF-x+Wj8s%R{cajvJB`WDcV|yBVk@bV#tG7o@EwL4%{$xr5HyXvKL*dAD^jE*=`}>Q`xm5>cZ} zJ4_)uJTA>%(h_A!5LurnjgAW(jOO|%GcZO{4OPN*yJAUh6Dw9f?Q8~%?#|J(oydv> zJY|tW$ln0&KAi!J8m2nG#jkr|5(Ur^f!C|x{4fa9TbfeNml;xJ-Gt>y4p8B+lMdA~ zoOdv4XKp)^8A>8BlA`KGn?KtecZ?{(vrqURbJ5RmaYL`&qJJi(JhtqOGn(H5jDwCM zq+bAz_4xs}9tl5vAMY#FJ9lTStIF(>YMn+D%ym*NUF_L~oS(8QF=EF0B|)?zo*m)LSBfF)c5r=E z5*D?|98J2cDI?H&fj4CFA`-O7^`4F|oC08FNzn13BaP@vUwNdYhzH9RiE|tApeYo8 zHy_++d#^v(`>t>=R6RYj)$V2YECnFsHQ?Td#DB>|QnB*gH9uHRaY2KppA>$yc(OO& zgZvzFEMmm`rYvXD8jR$^2{#$k{b=v%t&)g?tKCaH1%e#}|qsyh~nq2CBeUIQvTnfl!D_M7&isRD4&|VF72eU@6SK{~iJlMnOV&s`Io~W^f zM+qbjj5W_9t}64C@2V?Q{2XNNFWT5Q`!3yDZrE#+yroCitiXCsTpTWf7Si*OGhoY> z?*Q^(u?z%^R{$A48NA;Qf0a-#C7zXT8!vwPkN( z-a7!8kqPO}eP`~j2<#`_^HFUgcj`S1ebx-Q0X4?|E;jr;kKD6|UX_sE`AOFcuLlefY>VvA6kq7pF$b zmrr^!r@DJ`E>FjT6*-AmpRnFWJb1IS|He-{;`#<|xvN)=&b2md<_h!!AXC}Ls}EHV z8z#zSePj?qB=t^SDRCpp(}OF{jo8oMOmCMK3g2yk6cgt|=D&n?2TuP;iZbve>8)Om11Mj^^t z+q{hc*RszVQT*$8M+fqC_G#SF)t&A8z)@@E18ccuBrmm7wt`NgSFr9zqGc{gs`m7~ zExI*h;`RU8SiR^Kz>1fl?>`GC$C-yWuOr^ndU=-4gLMG$Gqh&MR(itGOxk?9gpB$| z^tc?8+pt0{1}dVqa*XOZ1En3c`N&X=n7)j3GqY!%~R|V14i2~1U zUEVKOQvAn@z@XGauu3!i=R>dzy*~d8VLo+~D+(sgr8)>?f(I)FiJwX-xdk~{ttW_n z9?JN~i!}cW5l0=zP#>8r%)zw4YEJwF3PdYW|6XiSA~aCJdvhM2D{DbOz|*6{8#>qH z)p?s9LtHZyvs|hD0eO_(0DSg^ZU8cZF|hJX_v>H7sn(X)4S8{+3lWf51iOew&-2!)OjjdpUDvkR^Z@qkXxvd>ecj$Dhx4E=yn1AQh z<%8$!B5ziIR}ay2Jvme7T4&mu!S#)(5^EMo&Cc7+8*g9J(@+cm8*D@O5A{7B&r7zf z9B5J(_Qk=$<+yfmn(1tSh@JVMrkRhJfE5GpR-MLH)Bwp_h%8>ke~a0-_piF1;ig*j z4x9B7@8s9Ay8%Q$|Aw&6Xxe;9E?w}#43AZYZkJ%-h1YEDRLf>;S5W~r{K+!?-U7t* zY;ut(*X>e$5t`|F>df&#XWe;=^EO%D38+#y(#Q198HD29Xy;{1&*b2(KRNAZJeWa^4kxx=k0=n?NlsheR(?h6won;W%A!wo;0=)0M7vu$s#RBe+af5RHq1XV-)&6ZpH2!Cu)1obS}1KZ4c zJK81JM#+)Vn)LT}*6C}U1_%sz|76aC+%U^%iTKu&$k&Bg?YA38OmYs3bz{zxj<@_x z`|~S!KB^O--N!FnCUX0pKE^YS>FcN5GeT0u*=)2F*LVP8#m#-c{xzqd8QxauqTa% zQsxv?(zUjbHgv6(1^bZ>()NqIJZi;iormFKu)6)lOcFjHFeAm=)9g5(<-ysnS|8VX z^W1zX)}(URI8696q`K1E{_p~-ySq98=e5(x*R&1T1y#C^g}o%JY!jbP&&5?ozvX_8 zTwDJWrvAQUb0-fp)uHl2+r{Gs&`L7^v%W@-jG{N+_)7S=T0U)S$BMnn00U{6m>zUK zbT6n4i_``HI!1yQ;~H1s$lEzEfu%yM;q*}VM+`iaeD z65HL*4!cQN8Epi z0$DAME$P$#{3cB{Lnh$hj4WHa%rnZ<`db~DQS{MI2kwLX#ZNh5ymNCpSmw;KjnJYH zI=<+Rj;~FmPt61HZDPs0zi<-ErDIl6aYHA>S2}Pk*IpJ%$a}uu+94L^80F9s?4;OgDbwIQL(h=Gg6x*Ydc9aTNI`M5*avGb5# ztiFJ63(@Je=1WqJuJ=Z4SIpR)#DG5560T`9kmIv6 zdU|GaNV4mjd$?ggd)2==P{-{P`YYXq04lWsWK3!qdP-qfSw8RM+EkDSRO~shA;eCT zxeb}bulI!wx}G6j2-}V9=N<|7=!;&u5HI}b$wLQHDnT9)o3$H+n4~=_%on2c2Wq`^ zPUlu2;$qVh!Dl5f-4AbZK%~+BU}r8Ug?yYJn)?wXV`XKFd#xm=q6IQZa7hFg1V9`E zQnDt-4g%l4HaCpBRQ=9k&pa=B(xQe_51Z`Cd4Tgr+ky4wQQ{imxHB*9yd?afmWRP3 z%9(hryXgByx)<=EWAHCIcNwK|0$&^^*_;EL+ z=nUtA>d%C64404BgG0zY+p!+mmD7(pd)EDghTJzE`0mDnh@s+;sQ{+&D>KaFD@_b> z{Ra(Eb7XXN4twarey3QyV?h3rlVsS=?8prO!wx`TS&k^S(#W+ws#XNm>bzS0BfEl% zLtI3k=4H^y{P7zlkZt_*Kq*^tHbzNID{R(*hPu|Z$_A1U0G{lo@HSz1*xb=e=K4Z6 zGeAU(Bfj*hR&W!Oai7$k;JT2Ja4KkM9Zp4a_Ao$&!V$V`gw8$sC6aVE{g^J*yAGI8 zA;g)iZnD$N>#%Wmjgu!*jVz4sO1c~KN;xGb=J>fRP29OEvj;4oAX9WXdqVX^$}>Ph z{K(O8#5a$9buNSDBQ?x#L=njh6kLm|6FHKxiaa>~as$wxlMqM+>+#U9$@+b&=cJ2G z1|2_eewpz^I}81UxkS71+zd-X$bUM_^ndedOZXWJqhl?QXvUs`bqP(Q9GIUZQM zr3bzS!L2Y9Blf}#SdzHA*ZmGukm(1Fa{-rW?MCM?kOqUU;L78%RlhwES~etC^f3~L zR9D_4g+6GaK4N6qrqV5BjHs$42@15Vvwh~GV+==a@7O_ zD@J%M1wZo!qQVp8xP*tA2_N&PxSdO=Y62bd&=bk`_$l8~MsGuM;yG@3JJ& zhK-B=#c`sl^xUmE-4q?znIT=P7@#gsUku^m&d#e^nO8813TvHZcl{RxyG7Nr&j$Fzua#$HMfWn z_4zqXvCkZ|Pj0`8)TW&DzLOz&5W)4yOrMRDzU;e*c?9{rTgBN~q1t%_#;4ZnJjp6x zoR9tF3h1WFzL1rD`PSs!YGgI(KyKPSZi*=T6npQ=E4hWAn@Jay9Xax4gE>X^)uISB zBysIdfkh@Ol285z4`8QPpKFXTu=rNln^b!gwg}g2Gbmj#sIfPwURkqN_jb&j%!fS7 zmIKGnJpzJ6QI^&G^mt`%mwLBiBKtcS^WqBJ2NfZZw(OCc$4B>^hRKhsqb|Qi&!>5l zg@xbwE77naXDRji>kGeLQRC`VfoqUWbNEa^kL#5f3=-sWv5V9I+S;xfc#*coJ2|26OT7SMg>H@h)xvszOf}@O=})Tfe;9#J|3SL!h3Y+uvD+N|fJi5R>}>o+PzjSDLv_wSPEXE z=3&e0i5mbt)U5RCQ5&|dr=rkel$*E}v%6HoUE@~`51JVd?sDX?QBR_PO(^8hCf}jN zZx>%@N$n-R(#9?&Y^Q{U_)=Iyeh=jbW|fKOao4{@y0*3!F0>PC`JHP3$BtC6I}s)K z#s{7O&PDz&Y+!9kV#3`-dKk9N+tDy^{|$gfZY&_w@V<`(z5N3RyV-A2w@PS1`OZ9o zJ5rN-gJV3$TqWGM*@VA^aFNQ*RePdK zn+NL0uyS@WVcjX17{-skp)1rPJOoUZ#7lTqWE;~jHWD_yNz%&)5kadqqc^z@*aK_A zKjC~0<|XRHekGi^daYU=uk4tGSOQapn0GDtJrk4JG!>*JNoHRCcl34tJ>A{^zy5E0 M&%gRD!f#go9Z)Ykwg3PC literal 0 HcmV?d00001 diff --git a/docs/source/images/timeLine.jpg b/docs/source/images/timeLine.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5fa81e42340adc7be959acee12b27f76311e728 GIT binary patch literal 13754 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 literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index dded7a9b..860cd577 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,36 +9,38 @@ Welcome to cdms2's documentation! Contents: .. toctree:: - MV2 - tvariable - AbstractVariable - avariable - cdmsobj - axis - coord - grid - hgrid - sliceut - error - variable - fvariable - tvariable - dataset - database - cache - selectors - MV2 - convention - bindex - auxcoord - gengrid - gsHost - gsStaticVariable - gsTimeVariable - mvBaseWriter - mvSphereMesh - mvVsWriter - mvCdmsRegrid + manual/cdms_1 + manual/cdms_2 + manual/cdms_3 + manual/cdms_4 + manual/cdms_5 + manual/cdms_6 + manual/cdms_7 + manual/cdms_appendix + +# AbstractAxis +# AbstractVariable +# avariable +# axis +# bindex +# cache +# cdmsfile +# cdmsobj +# database +# dataset +# fvariable +# gengrid +# grid +# gsHost +# gsStaticVariable +# gsTimeVariable +# hgrid +# MV2 +# mvSphereMesh +# mvCdmsRegrid +# selectors +# sliceut +# tvariable Indices and tables diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst new file mode 100644 index 00000000..4b73df67 --- /dev/null +++ b/docs/source/manual/cdms_1.rst @@ -0,0 +1,845 @@ +CHAPTER 1 +--------- + +CHAPTER 1 Introduction + +1.1 Overview +^^^^^^^^^^^^ + +The Climate Data Management System is an object-oriented data management +system, specialized for organizing multidimensional, gridded data used +in climate analysis and simulation. + +CDMS is implemented as part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT), which uses the Python language. The examples in +this chapter assume some familiarity with the language and the Python +Numeric module (http://www.numpy.org). A number of excellent tutorials +on Python are available in books or on the Internet. For example, see +the `Python Foundation's homepage `__. + +1.2 Variables +^^^^^^^^^^^^^ + +The basic unit of computation in CDMS is the variable. A variable is +essentially a multidimensional data array, augmented with a domain, a +set of attributes, and optionally a spatial and/or temporal coordinate +system (see `Coordinate Axes <#1.4>`__). As a data array, a variable can +be sliced to obtain a portion of the data, and can be used in arithmetic +computations. For example, if ``u`` and ``v`` are variables representing +the eastward and northward components of wind speed, respectively, and +both variables are functions of time, latitude, and longitude, then the +velocity for time 0 (first index) can be calculated as + +.. doctest:: + + >>> from cdms2 import MV + >>> vel = MV.sqrt(u[0]**2 + v[0]**2) + +This illustrates several points: + +- Square brackets represent the slice operator. Indexing starts at 0, + so ``u[0]`` selects from variable ``u`` for the first timepoint. The + result of this slice operation is another variable. The slice + operator can be multidimensional, and follows the syntax of Numeric + Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data + for the first ten timepoints, at all latitudes, for the second + longitude. +- Variables can be used in computation. ``**`` is the Python + exponentiation operator. +- Arithmetic functions are defined in the ``cdms.MV`` module. +- Operations on variables carry along the corresponding metadata where + applicable. In the above example, ``vel`` has the same latitude and + longitude coordinates as ``u`` and ``v``, and the time coordinate is + the first time of ``u`` and ``v``. + +1.3 File I/O +^^^^^^^^^^^^ + +A variable can be obtained from a file or collection of files, or can be +generated as the result of a computation. Files can be in any of the +self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS +control file), or PCMDI DRS. (HDF and DRS support is optional, and is +configured at the time UV-CDAT is installed.) For instance, to read data +from file sample.nc into variable u: + +.. testsetup:: * + + import MV2 + import cdms2 + import cdat_info + import requests + f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') + f2 = cdms2.open(cdat_info.get_sampledata_path()+'/geos5-sample.nc') + u = f('u') + v = f('v') + smallvar=MV2.reshape(MV2.arange(20),(4,5),id='small variable').astype(MV2.float32) + largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') + +Data can be read by index or by world coordinate values. The following +reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k +such that i <= k < j): + +.. doctest:: + + >>> n = 0 + >>> u0 = f('u',time=slice(n,n+1)) + +To read ``u`` at time 1.: + +.. doctest:: + + >>> u1 = f('u',time=1.) + +A variable can be written to a file with the write function: + +.. doctest:: + + >>> g = cdms2.open('sample2.nc','w') + >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >> g.close() + +1.4 Coordinate Axes +^^^^^^^^^^^^^^^^^^^ + +A coordinate axis is a variable that represents coordinate information. +Typically an axis is associated with one or more variables in a file or +dataset, to represent the indexing and/or spatiotemporal coordinate +system(s) of the variable(s). + +Often in climate applications an axis is a one-dimensional variable +whose values are floating-point and strictly monotonic. In some cases an +axis can be multidimensional (see `Grids <#1.9>`__). If an axis is +associated with one of the canonical types latitude, longitude, level, +or time, then the axis is called tep emporal . + +The shape and physical ordering of a variable is represented by the +variables domain , an ordered tuple of one-dimensional axes. In the +previous example, the domain of the variable u is the tuple (time, +latitude, longitude). This indicates the order of the dimensions, with +the slowest- varying dimension listed first (time). The domain may be +accessed with the ``getAxisList()`` method: + +.. doctest:: + + >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + [ id: time1 + Designated a time axis. + units: months since 1978-12 + Length: 1 + First: 1.0 + Last: 1.0 + Other axis attributes: + calendar: gregorian + axis: T + Python id: ... + , id: plev + Designated a level axis. + units: hPa + Length: 2 + First: 200.0 + Last: 850.0 + Other axis attributes: + axis: Z + realtopology: linear + Python id: ... + , id: latitude1 + Designated a latitude axis. + units: degrees_north + Length: 80 + First: -88.2884 + Last: 88.2884 + Other axis attributes: + axis: Y + realtopology: linear + Python id: ... + , id: longitude1 + Designated a longitude axis. + units: degrees_east + Length: 97 + First: -180.0 + Last: 180.0 + Other axis attributes: + axis: X + topology: circular + modulo: 360.0 + realtopology: linear + Python id: ... + ] + + +In the above example, the domain elements are axes that are also +spatiotemporal. In general it is not always the case that an element of +a domain is spatiotemporal: + +- An axis in the domain of a variable need not be spatiotemporal. For + example, it may represent a range of indices, an index coordinate + system. +- The latitude and/or longitude coordinate axes associated with a + variable need not be elements of the domain. In particular this will + be true if the variable is defined on a non-rectangular grid (see `Grids <#1.9>`__). + +As previously noted, a spatial and/or temporal coordinate system may be +associated with a variable. The methods getLatitude, getLongitude, +getLevel, and getTime return the associated coordinate axes. For +example: + +.. doctest:: + + >>> t = u.getTime() + >>> print t[:] + [ 1.] + >>> print t.units + months since 1978-12 + +1.5 Attributes +^^^^^^^^^^^^^^ + +As mentioned above, variables can have associated attributes , +name-value pairs. In fact, nearly all CDMS objects can have associated +attributes, which are accessed using the Python dot notation: + +.. doctest:: + + >>> u.units='m/s' + >>> print u.units + m/s + +Attribute values can be strings, scalars, or 1-D Numeric arrays. + +When a variable is written to a file, not all the attributes are +written. Some attributes, called internal attributes, are used for +bookkeeping, and are not intended to be part of the external file +representation of the variable. In contrast, external attributes are +written to an output file along with the variable. By default, when an +attribute is set, it is treated as external. Every variable has a field +attributes, a Python dictionary that defines the external attributes: + +.. doctest:: + + >>> print u.attributes.keys() + ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] + +The Python dir command lists the internal attribute names: + +.. doctest:: + + >>> dir(u) + ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] + +In general internal attributes should not be modified directly. One +exception is the id attribute, the name of the variable. It is used in +plotting and I/O, and can be set directly. + +1.6 Masked values +^^^^^^^^^^^^^^^^^ + +Optionally, variables have a mask that represents where data are +missing. If present, the mask is an array of ones and zeros having the +shape of the data array. A mask value of one indicates that the +corresponding data array element is missing or invalid. + +Arithmetic operations in CDMS take missing data into account. The same +is true of the functions defined in the cdms.MV module. For example: + +.. doctest:: + + >>> a = MV2.array([1,2,3]) # Create array a, with no mask + >>> b = MV2.array([4,5,6]) # Same for b + >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + variable_... + masked_array(data = [5 7 9], + mask = False, + fill_value = 999999) + + + >>> a[1]=MV2.masked # Mask the second value of a a.mask() + >>> a.mask + array([False, True, False], dtype=bool) + >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + variable_... + masked_array(data = [5 -- 9], + mask = [False True False], + fill_value = 999999) + + + +When data is read from a file, the result variable is masked if the file +variable has a missing_value attribute. The mask is set to one for +those elements equal to the missing value, zero elsewhere. If no such +attribute is present in the file, the result variable is not masked. + +When a variable with masked values is written to a file, data values +with a corresponding mask value of one are set to the value of the +variables ``missing_value`` attribute. The data and ``missing_value`` +attribute are then written to the file. + +Masking is covered in `Section 2.9 `__. See also the +documentation of the Python Numeric and MA modules, on which ``cdms.MV`` +is based, at + +`http://www.numpy.org/ `__. + +1.7 File Variables +^^^^^^^^^^^^^^^^^^ + +A variable can be obtained either from a file, a collection of files, or +as the result of computation. Correspondingly there are three types of +variables in CDMS: + +- *file variable* is a variable associated with a single data file. + Setting or referencing a file variable generates I/O operations. +- A *dataset variable* is a variable associated with a collection of + files. Reference to a dataset variable reads data, possibly from + multiple files. Dataset variables are read-only. +- *transient variable* is an in-memory object not associated with a + file or dataset. Transient variables result from a computation or I/O + operation. + +Typical use of a file variables is to inquire information about the +variable in a file without actually reading the data for the variables. +A file variable is obtained by applying the slice operator [] to a file, +passing the name of the variable, or by calling the getVariable +function. Note that obtaining a file variable does not actually read the +data array: + +.. doctest:: + + >>> u = f.getVariable('u') # or u=f['u'] + >>> u.shape + (1, 2, 80, 97) + +File variables are also useful for fine-grained I/O. They behave like +transient variables, but operations on them also affect the associated +file. Specifically: + +- slicing a file variable reads data, +- setting a slice writes data, +- referencing an attribute reads the attribute, +- setting an attribute writes the attribute, +- and calling a file variable like a function reads data associated + with the variable: + +.. doctest:: + + >>> import os + >>> os.system("cp clt.nc /tmp") + 0 + >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write + >>> uvar = f['u'] # Note square brackets + >>> uvar.shape + (1, 2, 80, 97) + >>> u0 = uvar[0] # Reads data from sample.nc + >>> u0.shape + (2, 80, 97) + >>> uvar[1]=u0 # Writes data to sample.nc + >>> uvar.units # Reads the attribute 'm/s' + 'm/s' + >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data + >>> f.close() # Save changes to clt.nc (I/O may be buffered) + + +For transient variables, the data is printed only if the size of the array is less +than the print limit . This value can be set with the function +MV.set_print_limit to force the data to be printed: + +.. doctest:: + + >>> MV2.get_print_limit() # Current limit 1000 + 1000 + >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + small variable + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.] + [ 10. 11. 12. 13. 14.] + [ 15. 16. 17. 18. 19.]], + mask = + False, + fill_value = 999999.0) + >>> MV2.set_print_limit(100) + >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + large variable + masked_array(data = + [[ 0. 1. 2. ..., 17. 18. 19.] + [ 20. 21. 22. ..., 37. 38. 39.] + [ 40. 41. 42. ..., 57. 58. 59.] + ..., + [ 340. 341. 342. ..., 357. 358. 359.] + [ 360. 361. 362. ..., 377. 378. 379.] + [ 380. 381. 382. ..., 397. 398. 399.]], + mask = False, + fill_value = 999999.0) + +The datatype of the variable is determined with the typecode function: + +.. doctest:: + + >>> u.typecode() + 'f' + +1.8 Dataset Variables +^^^^^^^^^^^^^^^^^^^^^ + +The third type of variable, a *dataset variable*, is associated with a +*dataset*, a collection of files that is treated as a single file. A +dataset is created with the ``cdscan`` utility. This generates an XML +metafile that describes how the files are organized and what metadata +are contained in the files. In a climate simulation application, a +dataset typically represents the data generated by one run of a general +circulation or coupled ocean-atmosphere model. + +For example, suppose data for variables u and v are stored in six files: + +1. u_2000.nc, +2. u_2001.nc, +3. u_2002.nc, +4. v_2000.nc, +5. v_2001.nc, +6. v_2002.nc. + +A metafile can be generated with the command: + +**$ cdscan -x cdsample.xml [uv]*.nc** + +The metafile **cdsample.xml** is then used like an ordinary data file: + +.. doctest:: + + >>> import os + >>> os.system("cdscan -x cdsample.xml [uv]*.nc") + 0 + >>> f = cdms2.open('cdsample.xml') + >>> u = f('u') + >>> u.shape + (3, 16, 32) + +1.9 Grids +^^^^^^^^^ + +A latitude-longitude grid represents the coordinate information +associated with a variable. A grid encapsulates: + +- latitude, longitude coordinates +- grid cell boundaries +- area weights + +CDMS defines a rich set of grid types to represent the variety of +coordinate systems used in climate model applications. Grids can be +categorized as rectangular or nonrectangular. + +A rectangular grid has latitude and longitude axes that are +one-dimensional, with strictly monotonic values. The grid is essentially +the Cartesian product of the axes. If either criterion is not met, the +grid is nonrectangular . + +CDMS supports two types of nonrectangular grid: + +- A curvilinear grid consists of a latitude and longitude axis, each of + which is a two-dimensional coordinate axis. Curvilinear grids are + often used in ocean model applications. +- A generic grid consists of a latitude and longitude axis, each of + which is an auxiliary one-dimensional coordinate axis. An auxiliary + axis has values that are not necessarily monotonic. As the name + suggests, generic grids can represent virtually any type of grid. + However, it is more difficult to determine adjacency relationships + between grid points. + +1.9.1 Example: a curvilinear grid +''''''''''''''''''''''''''''''''' + +In this example, variable sample is defined on a 128x192 curvilinear +grid. Note that: + +- The domain of variable sample is ( y , x ) where y and x are index + coordinate axes. +- The curvilinear grid associated with sample consists of axes ( lat , + lon ), each a two-dimensional coordinate axis. +- lat and lon each have domain ( y , x ) + +.. doctest:: + + >>> f = cdms2.open('sampleCurveGrid4.nc') + + + >>> # lat and lon are coordinate axes, but are grouped with data variables + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + + >>> # y and x are index coordinate axes + >>> f.axes.keys() + ['nvert', 'x', 'y'] + + >>> # Read data for variable sample + >>> sample = f('sample') + + >>> # The associated grid g is curvilinear + >>> g = sample.getGrid() + + >>> # The domain of the variable consfigists of index axes + >>> sample.getAxisIds() + ['y', 'x'] + + >>> # Get the coordinate axes associated with the grid + >>> lat = g.getLatitude() # or sample.getLatitude() + >>> lon = g.getLongitude() # or sample.getLongitude() + + >>> # lat and lon have the same domain, a subset of the domain of 'sample' + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are variables ... + >>> lat.shape + (32, 48) + + >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + lat + masked_array(data = + [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 + -76.08465554] + [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 + -73.92641847] + [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 + -71.44420823] + ..., + [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 + 42.32854943] + [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 + 42.70106429] + [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 + 43.0307341 ]], + mask = + False, + fill_value = 1e+20) + + >>> lat_in_radians = lat*MV2.pi/180.0 + +.. figure:: images/curvilinear_grid.jpg + :alt: curvilinear grid + + Figure1: Curvilinear Grid + +1.9.2 Example: a generic grid +''''''''''''''''''''''''''''' + +In this example variable zs is defined on a generic grid. Figure 2 +illustrates the grid, in this case a geodesic grid. + +.. doctest:: + + >>> f.variables.keys() + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + >>> f.axes.keys() + ['nvert', 'x', 'y'] + >>> zs = f('sample') + >>> g = zs.getGrid() + >>> g + + >>> lat = g.getLatitude() + >>> lon = g.getLongitude() + >>> lat.shape + (32, 48) + >>> lon.shape # variable zs is defined in terms of a single index coordinate + (32, 48) + >>> # axis, 'cell' + >>> zs.shape + (32, 48) + >>> zs.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are also defined in terms of the cell axis + >>> lat.getAxisIds() + ['y', 'x'] + + >>> # lat and lon are one-dimensional, 'auxiliary' coordinate + >>> # axes: values are not monotonic + >>> lat.__class__ + + + +.. figure:: images/generic_grid.jpg + :alt: generic grid + + Figure 2: Generic Grid + +Generic grids can be used to represent any of the grid types. The method +toGenericGrid can be applied to any grid to convert it to a generic +representation. Similarly, a rectangular grid can be represented as +curvilinear. The method toCurveGrid is used to convert a non-generic +grid to curvilinear representation: + +.. doctest:: * + + >>> f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') + >>> clt = f('clt') + >>> rectgrid = clt.getGrid() + >>> rectgrid.shape + (46, 72) + >>> curvegrid = rectgrid.toCurveGrid() + >>> curvegrid + + >>> genericgrid = curvegrid.toGenericGrid() + >>> genericgrid + + +1.10 Regridding +^^^^^^^^^^^^^^^ + +Regridding is the process of mapping variables from one grid to another. +CDMS supports two forms of regridding. Which one you use depends on the +class of grids being transformed: + +- To interpolate from one rectangular grid to another, use the built-in + CDMS regridder. CDMS also has built-in regridders to interpolate from + one set of pressure levels to another, or from one vertical + cross-section to another. +- To interpolate from any lat-lon grid, rectangular or non-rectangular, + use the SCRIP regridder. + +1.10.1 CDMS Regridder +''''''''''''''''''''' + +The built-in CDMS regridder is used to transform data from one +rectangular grid to another. For example, to regrid variable ``u`` (from +a rectangular grid) to a 96x192 rectangular Gaussian grid: + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> u = f('u') + >>> u.shape + (1, 2, 80, 97) + >>> t63_grid = cdms2.createGaussianGrid(96) + >>> u63 = u.regrid(t63_grid) + >>> u63.shape + (1, 2, 96, 192) + +To regrid a variable ``uold`` to the same grid as variable ``vnew``: + +.. doctest:: + + >>> f = cdms2.open('clt.nc') + >>> uold = f('u') + >>> unew = f2('uwnd') + >>> uold.shape + (1, 2, 80, 97) + >>> unew.shape + (1, 14, 181, 360) + >>> t63_grid = unew.getGrid() # Obtain the grid for vnew + >>> u63 = u.regrid(t63_grid) + >>> u63.shape + (1, 2, 181, 360) + +1.10.2 SCRIP Regridder +'''''''''''''''''''''' + +To interpolate between any lat-lon grid types, the SCRIP regridder may +be used. The SCRIP package was developed at [Los Alamos National +Laboratory](http://oceans11.lanl.gov/drupal/Models/OtherSoftware). +SCRIP is written in Fortran 90, and must be built and installed +separately from the UV-CDAT/CDMS installation. + +The steps to regrid a variable are: + +(external to CDMS) + +1. Obtain or generate the grids, in SCRIP netCDF format. +2. Run SCRIP to generate a *remapping* file. + +(in CDMS) + +1. Read the regridder from the SCRIP remapping file. +2. Call the regridder with the source data, returning data on the target + grid. + +Steps 1 and 2 need only be done once. The regridder can be used as often +as necessary. + +#For example, suppose the source data on a T42 grid is to be mapped to a +#POP curvilinear grid. Assume that SCRIP generated a remapping file named +#rmp_T42_to_POP43_conserv.nc: +# +#.. doctest:: +# +# >>> # Import regrid package for regridder functions +# >>> import regrid2, cdms2 +# +# >>> # Get the source variable +# >>> f = cdms2.open('sampleT42Grid.nc') +# >>> dat = f('src_array') +# >>> f.close() +# +# >>> # Read the regridder from the remapper file +# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') +# >>> regridf = regrid2.readRegridder(remapf) +# >>> remapf.close() +# +# >>> # Regrid the source variable +# >>> popdat = regridf(dat) + +Regridding is discussed in `Chapter 4 `__. + +1.11 Time types +^^^^^^^^^^^^^^^ + +CDMS provides extensive support for time values in the cdtime module. +cdtime also defines a set of calendars , specifying the number of days +in a given month. + +Two time types are available: relative time and component time . +Relative time is time relative to a fixed base time. It consists of: + +- a ``units`` string, of the form ``"units since basetime"`` , and +- a floating-point ``value`` + +For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and +units=" days since 1996-1-1". To create a relative time type: + +.. doctest:: + + >>> import cdtime + >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") + >>> rt + 28.000000 days since 1996-1-1 + >>> rt.value + 28.0 + >>> rt.units + 'days since 1996-1-1' + +A component time consists of the integer fields year, month, day, hour, +minute , and the floating-point field second . For example: + + +.. doctest:: + + >>> ct = cdtime.comptime(1996,2,28,12,10,30) + >>> ct + 1996-2-28 12:10:30.0 + >>> ct.year + 1996 + >>> ct.month + 2 + +The conversion functions tocomp and torel convert between the two +representations. For instance, suppose that the time axis of a variable +is represented in units " days since 1979" . To find the coordinate +value corresponding to January 1, 1990: + +.. doctest:: + + >>> ct = cdtime.comptime(1990,1) + >>> rt = ct.torel("days since 1979") + >>> rt.value + 4018.0 + +Time values can be used to specify intervals of time to read. The syntax +time=(c1,c2) specifies that data should be read for times t such that +c1<=t<=c2: + +.. doctest:: + + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> c1 = cdtime.comptime(1980,1) + >>> c2 = cdtime.comptime(1980,2) + >>> tas = fh['tas'] + >>> tas.shape + (484, 45, 72) + >>> x = tas.subRegion(time=(c1,c2)) + >>> x.shape + (125, 45, 72) + +or string representations can be used: + + +.. doctest:: + + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") + >>> tas = fh['tas'] + >>> x = tas.subRegion(time=('1980-1','1980-2')) + +Time types are described in Chapter 3. + +1.12 Plotting data +^^^^^^^^^^^^^^^^^^ + +Data read via the CDMS Python interface can be plotted using the vcs +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the VCS reference manual. The +vcs module provides access to the functionality of the VCS visualization +program. + +To generate a plot: + +- Initialize a canvas with the ``vcs init`` routine. +- Plot the data using the canvas ``plot`` routine. + +For example: + +.. doctest:: + + >>> import cdms2, vcs, cdat_info + >>> fh=cdms2.open(cdat_info.get_sampledata_path() + "/tas_cru_1979.nc") + >>> fh['time'][:] # Print the time coordinates + array([ 1476., 1477., 1478., 1479., 1480., 1481., 1482., 1483., + 1484., 1485., 1486., 1487.]) + + >>> tas = fh('tas', time=1479) + >>> tas.shape + (1, 36, 72) + >>> w = vcs.init() # Initialize a canvas + >>> w.plot(tas) # Generate a plot + `__ +for details. + +1.13 Databases +^^^^^^^^^^^^^^ + +Datasets can be aggregated together into hierarchical collections, +called databases . In typical usage, a program: + +- connects to a database +- searches for data opens a dataset +- accesses data + +Databases add the ability to search for data and metadata in a +distributed computing environment. At present CDMS supports one +particular type of database, based on the Lightweight Directory Access +Protocol (LDAP). + +.. Here is an example of accessing data via a database: + +.. .. doctest:: + +.. >>> db = cdms.connect() # Connect to the default database. +.. >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. +.. >>> f.variables.keys() # List the variables in the dataset. +.. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] + +Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst new file mode 100644 index 00000000..b42df836 --- /dev/null +++ b/docs/source/manual/cdms_2.rst @@ -0,0 +1,3820 @@ +CHAPTER 2 CDMS Python Application Programming Interface +------------------------------------------------------- + +2.1 Overview +^^^^^^^^^^^^ + +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +This chapter describes the CDMS Python application programming interface +(API). Python is a popular public-domain, object-oriented language. Its +features include support for object-oriented development, a rich set of +programming constructs, and an extensible architecture. CDMS itself is +implemented in a mixture of C and Python. In this chapter the assumption +is made that the reader is familiar with the basic features of the +Python language. + +Python supports the notion of a module, which groups together associated +classes and methods. The import command makes the module accessible to +an application. This chapter documents the cdms, cdtime, and regrid +modules. + +The chapter sections correspond to the CDMS classes. Each section +contains tables base. If no parent, the datapath is absolute.describing +the class internal (non-persistent) attributes, constructors (functions +for creating an object), and class methods (functions). A method can +return an instance of a CDMS class, or one of the Python types: + + +Table 2.1 Python types used in CDMS + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Description | ++==============+=======================================================================================================================================================================================================+ +| Array | Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Comptime | Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Dictionary | An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Float | Floating-point value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | Integer value. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| List | An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| None | No value returned. | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Reltime | Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +2.2 A first example +^^^^^^^^^^^^^^^^^^^ + +The following Python script reads January and July monthly temperature +data from an input dataset, averages over time, and writes the results +to an output file. The input temperature data is ordered (time, +latitude, longitude). + +.. doctest:: + + >>> import cdms2, cdat_info + >>> from cdms2 import MV + >>> jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc') + >>> tasvar = jones['tas'] + >>> jans = tasvar[0::12] + >>> julys = tasvar[6::12] + >>> janavg = MV.average(jans) + >>> janavg.id = "tas_jan" + >>> janavg.long_name = "mean January surface temperature" + >>> julyavg = MV.average(julys) + >>> julyavg.id = "tas_jul" + >>> julyavg.long_name = "mean July surface temperature" + >>> out = cdms2.open('janjuly.nc','w') + >>> out.write(janavg) + >> out.write(julyavg) + >> out.comment = "Average January/July from Jones dataset" + >>> jones.close() + >>> out.close() + + ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| 2,3 | Makes the CDMS and MV modules available. MV defines arithmetic functions. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 4 | Opens a netCDF file read-only. The result jones is a dataset object. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 5 | Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 6 | Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 7 | Reads all July data into a masked array julys. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 8 | Calculate the average January value for each grid zone. Any missing data is handled automatically. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 9,10 | Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 14 | Create a new netCDF output file named ‘janjuly.nc’ to hold the results. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 15 | Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 17 | Set the global attribute ‘comment’. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 18 | Close the output file. | ++--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.3 cdms module + +The cdms module is the Python interface to CDMS. The objects and methods +in this chapter are made accessible with the command: + +.. raw:: html + +
+ +:: + + import cdms2 + +.. raw:: html + +
+ +The functions described in this section are not associated with a class. +Rather, they are called as module functions, e.g., + +.. raw:: html + +
+ +:: + + file = cdms2.open('sample.nc') + +.. raw:: html + +
+ + +Table 2.2 cdms module functions + ++-------------+-------------------------------------------------------------------------+ +| Type | Definition | ++=============+=========================================================================+ +| ``Variable``| ``asVariable(s)``: Transform ``s`` | +| | into a transient variable. ``s`` is | +| | a masked array, Numeric array, or | +| | Variable. If ``s`` is already a | +| | transient variable, ``s`` is | +| | returned. See also: ``isVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createAxis(data, bounds=None)``: | +| | Create a one-dimensional coordinate | +| | Axis, which is not associated with a | +| | file or dataset. This is useful for | +| | creating a grid which is not | +| | contained in a file or dataset. | +| | ``data`` is a one-dimensional, | +| | monotonic Numeric array. ``bounds`` | +| | is an array of shape | +| | ``(len(data),2)``, such that for all | +| | ``i``, ``data[i]`` is in the range | +| | ``[bounds[i,0],bounds[i,1] ]``. If | +| | ``bounds`` is not specified, the | +| | default boundaries are generated at | +| | the midpoints between the | +| | consecutive data values, provided | +| | that the autobounds mode is 'on' | +| | (the default). See | +| | ``setAutoBounds``. Also see: | +| | ``CdmsFile.createAxis`` | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createEqualAreaAxis(nlat)``: | +| | Create an equal-area latitude axis. | +| | The latitude values range from north | +| | to south, and for all axis values | +| | ``x[i]``, ``sin(x[i])sin(x[i+1])`` | +| | is constant. ``nlat`` is the axis | +| | length. The axis is not associated | +| | with a file or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createGaussianAxis(nlat)``: Create | +| | a Gaussian latitude axis. Axis | +| | values range from north to south. | +| | ``nlat`` is the axis length. The | +| | axis is not associated with a file | +| | or dataset. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGaussianGrid(nlats, xorigin= | +| | 0.0, order="yx")``: | +| | Create a Gaussian grid, with shape | +| | ``(nlats, 2*nlats)``. ``nlats`` is | +| | the number of latitudes. ``xorigin`` | +| | is the origin of the longitude axis. | +| | ``order`` is either "yx" (lat-lon, | +| | default) or "xy" (lon-lat) | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, | +| | order="yx", mask=None)``: | +| | Create a generic grid, that is, a | +| | grid which is not typed as Gaussian, | +| | uniform, or equal-area. The grid is | +| | not associated with a file or | +| | dataset. ``latArray`` is a NumPy | +| | array of latitude values. | +| | ``lonArray`` is a NumPy array of | +| | longitude values. ``latBounds`` is a | +| | NumPy array having shape | +| | ``(len(latArray),2)``, of latitude | +| | boundaries. ``lonBounds`` is a NumPy | +| | array having shape | +| | ``(len(lonArray),2)``, of longitude | +| | boundaries. ``order`` is a | +| | ``string`` specifying the order of | +| | the axes, either "yx" for (latitude, | +| | longitude), or "xy" for the reverse. | +| | ``mask`` (optional) is an | +| | ``integer``-valued NumPy mask array, | +| | having the same shape and ordering | +| | as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createGlobalMeanGrid(grid)``: | +| | Generate a grid for calculating the | +| | global mean via a regridding | +| | operation. The return grid is a | +| | single zone covering the range of | +| | the input grid. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createRectGrid(lat, lon, order, ty | +| | pe="generic", mask=None)``: | +| | Create a rectilinear grid, not | +| | associated with a file or dataset. | +| | This might be used as the target | +| | grid for a regridding operation. | +| | ``lat`` is a latitude axis, created | +| | by ``cdms.createAxis``. ``lon`` is a | +| | longitude axis, created by | +| | ``cdms.createAxis``. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). ``type`` is one of | +| | 'gaussian','uniform','equalarea',or | +| | 'generic'. If specified, ``mask`` is | +| | a two-dimensional, logical Numeric | +| | array (all values are zero or one) | +| | with the same shape as the grid. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createUniformGrid(startLat, nlat, | +| | deltaLat, start-Lon, nlon, deltaLon, | +| | order="yx", mask=None)``: | +| | Create a uniform rectilinear grid. | +| | The grid is not associated with a | +| | file or dataset. The grid boundaries | +| | are at the midpoints of the axis | +| | values. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. If ``nlat`` is | +| | 1, the grid latitude boundaries will | +| | be ``startLat`` +/- ``deltaLat/2``. | +| | ``deltaLat`` is the increment | +| | between latitudes. ``startLon`` is | +| | the starting longitude value. | +| | ``nlon`` is the number of | +| | longitudes. If ``nlon`` is 1, the | +| | grid longitude boundaries will be | +| | ``startLon`` +/- ``deltaLon/2``. | +| | ``deltaLon`` is the increment | +| | between longitudes. ``order`` is a | +| | string with value "yx" (the first | +| | grid dimension is latitude) or "xy" | +| | (the first grid dimension is | +| | longitude). If specified, ``mask`` | +| | is a two-dimensional, logical | +| | Numeric array (all values are zero | +| | or one) with the same shape as the | +| | grid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLatitudeAxis(startLat | +| | , nlat, deltaLat)``: | +| | Create a uniform latitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular latitude | +| | axis. ``startLat`` is the starting | +| | latitude value. ``nlat`` is the | +| | number of latitudes. ``deltaLat`` is | +| | the increment between latitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``RectGrid``| ``createZonalGrid(grid)``: Create a | +| | zonal grid. The output grid has the | +| | same latitude as the input grid, and | +| | a single longitude. This may be used | +| | to calculate zonal averages via a | +| | regridding operation. ``grid`` is a | +| | RectGrid. | ++-------------+-------------------------------------------------------------------------+ +| ``Axis`` | ``createUniformLongitudeAxis(startLo | +| | n, nlon, delta-Lon)``: | +| | Create a uniform longitude axis. The | +| | axis boundaries are at the midpoints | +| | of the axis values. The axis is | +| | designated as a circular longitude | +| | axis. ``startLon`` is the starting | +| | longitude value. ``nlon`` is the | +| | number of longitudes. ``deltaLon`` | +| | is the increment between longitudes. | ++-------------+-------------------------------------------------------------------------+ +| ``Variable``| ``createVariable(array, typecode=Non | +| | e, copy=0, savespace=0, mask=None, f | +| | ill_value=None, grid=None, axes=None | +| | , attributes=None, id=None)``: | +| | This function is documented in Table | +| | 2.34 on page 90. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``getAutoBounds()``: Get the current | +| | autobounds mode. Returns 0, 1, or 2. | +| | See ``setAutoBounds``. | ++-------------+-------------------------------------------------------------------------+ +| ``Integer`` | ``isVariable(s)``: Return ``1`` if | +| | ``s`` is a variable, ``0`` | +| | otherwise. See also: ``asVariable``. | ++-------------+-------------------------------------------------------------------------+ +| ``Dataset`` | ``open(url,mode='r')``: Open or | +| | create a ``Dataset`` or | +| | ``CdmsFile``. ``url`` is a Uniform | +| | Resource Locator, referring to a | +| | cdunif or XML file. If the URL has | +| | the extension '.xml' or '.cdml', a | +| | ``Dataset`` is returned, otherwise a | +| | ``CdmsFile`` is returned. If the URL | +| | protocol is 'http', the file must be | +| | a '.xml' or '.cdml' file, and the | +| | mode must be 'r'. If the protocol is | +| | 'file' or is omitted, a local file | +| | or dataset is opened. ``mode`` is | +| | the open mode. See Table 2.24 on | +| | page 70. | +| | **Example**: Open an existing | +| | dataset: | +| | ``f = cdms.open("sampleset.xml")`` | +| | | +| | **Example**: Create a netCDF file: | +| | ``f = cdms.open("newfile.nc",'w')`` | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``order2index (axes, orderstring)``: | +| | Find the index permutation of axes | +| | to match order. Return a list of | +| | indices. ``axes`` is a list of axis | +| | objects. ``orderstring`` is defined | +| | as in ``orderparse``. | ++-------------+-------------------------------------------------------------------------+ +| ``List`` | ``orderparse(orderstring)``: Parse | +| | an order string. Returns a list of | +| | axes specifiers. ``orderstring`` | +| | consists of: | +| | | +| | - Letters t, x, y, z meaning time, | +| | longitude, latitude, level | +| | - Numbers 0-9 representing position | +| | in axes | +| | - Dash (-) meaning insert the next | +| | available axis here. | +| | - The ellipsis ... meaning fill | +| | these positions with any | +| | remaining axes. | +| | - (name) meaning an axis whose id | +| | is name | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setAutoBounds(mode)``: Set | +| | autobounds mode. In some | +| | circumstances CDMS can generate | +| | boundaries for 1-D axes and | +| | rectilinear grids, when the bounds | +| | are not explicitly defined. The | +| | autobounds mode determines how this | +| | is done: If ``mode`` is ``'grid'`` | +| | or ``2`` (the default), the | +| | ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid if | +| | the axis is designated as a latitude | +| | or longitude axis, and the | +| | boundaries are not explicitly | +| | defined. If ``mode`` is ``'on'`` or | +| | ``1``, the ``getBounds`` method will | +| | automatically generate boundary | +| | information for an axis or grid, if | +| | the boundaries are not explicitly | +| | defined. If ``mode`` is ``'off'`` or | +| | ``0``, and no boundary data is | +| | explicitly defined, the bounds will | +| | NOT be generated; the ``getBounds`` | +| | method will return ``None`` for the | +| | boundaries. Note: In versions of | +| | CDMS prior to V4.0, the default | +| | ``mode`` was ``'on'``. | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``setClassifyGrids(mode)``: Set the | +| | grid classification mode. This | +| | affects how grid type is determined, | +| | for the purpose of generating grid | +| | boundaries. If ``mode`` is ``'on'`` | +| | (the default), grid type is | +| | determined by a grid classification | +| | method, regardless of the value of | +| | ``grid.get-Type()``. If ``mode`` is | +| | ``'off'``, the value of | +| | ``grid.getType()`` determines the | +| | grid type | ++-------------+-------------------------------------------------------------------------+ +| ``None`` | ``writeScripGrid(path, grid, gridTit | +| | le=None)``: | +| | Write a grid to a SCRIP grid file. | +| | ``path`` is a string, the path of | +| | the SCRIP file to be created. | +| | ``grid`` is a CDMS grid object. It | +| | may be rectangular. ``gridTitle`` is | +| | a string ID for the grid. | ++-------------+-------------------------------------------------------------------------+ + + +Table 2.3 Class Tags + ++--------------+---------------------+ +| Tag | Class | ++==============+=====================+ +| ‘axis’ | Axis | ++--------------+---------------------+ +| ‘database’ | Database | ++--------------+---------------------+ +| ‘dataset’ | Dataset, CdmsFile | ++--------------+---------------------+ +| ‘grid’ | RectGrid | ++--------------+---------------------+ +| ‘variable’ | Variable | ++--------------+---------------------+ +| ‘xlink’ | Xlink | ++--------------+---------------------+ + + +2.4 CdmsObj +^^^^^^^^^^^ + +A CdmsObj is the base class for all CDMS database objects. At the +application level, CdmsObj objects are never created and used directly. +Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the +basis of user application programming. + +All objects derived from CdmsObj have a special attribute .attributes. +This is a Python dictionary, which contains all the external +(persistent) attributes associated with the object. This is in contrast +to the internal, non-persistent attributes of an object, which are +built-in and predefined. When a CDMS object is written to a file, the +external attributes are written, but not the internal attributes. + +**Example**: get a list of all external attributes of obj. + +.. raw:: html + +
+ +:: + + extatts = obj.attributes.keys() + +.. raw:: html + +
+ + +Table 2.4 Attributes common to all CDMS objects + ++--------------+--------------+--------------------------------------------------+ +| Type | Name | Definition | ++==============+==============+==================================================+ +| Dictionary | attributes | External attribute dictionary for this object. | ++--------------+--------------+--------------------------------------------------+ + + +Table 2.5 Getting and setting attributes + ++--------------------------------------+--------------------------------------+ +| Type | Definition | ++======================================+======================================+ +| various | ``value = obj.attname`` | +| | Get an internal or external | +| | attribute value. If the attribute is | +| | external, it is read from the | +| | database. If the attribute is not | +| | already in the database, it is | +| | created as an external attribute. | +| | Internal attributes cannot be | +| | created, only referenced. | ++--------------------------------------+--------------------------------------+ +| various | ``obj.attname = value`` | +| | Set an internal or external | +| | attribute value. If the attribute is | +| | external, it is written to the | +| | database. | ++--------------------------------------+--------------------------------------+ + + +2.5 CoordinateAxis +^^^^^^^^^^^^^^^^^^ + +A CoordinateAxis is a variable that represents coordinate information. +It may be contained in a file or dataset, or may be transient +(memoryresident). Setting a slice of a file CoordinateAxis writes to the +file, and referencing a file CoordinateAxis slice reads data from the +file. Axis objects are also used to define the domain of a Variable. + +CDMS defines several different types of CoordinateAxis objects. Table +2.9 on page 45 documents methods that are common to all CoordinateAxis +types. Table 2.10 on page 48 specifies methods that are unique to 1D +Axis objects. + + +Table 2.6 CoordinateAxis types + ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Definition | ++======================+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``CoordinateAxis`` | A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis2D`` | A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``AuxAxis1D`` | A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``. | ++----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.7 CoordinateAxis Internal Attributes + ++------------------+------------------+--------------------------------------------+ +| Type | Name | Definition | ++==================+==================+============================================+ +| ``Dictionary`` | ``attributes`` | External attribute dictionary. | ++------------------+------------------+--------------------------------------------+ +| ``String`` | ``id`` | CoordinateAxis identifer. | ++------------------+------------------+--------------------------------------------+ +| ``Dataset`` | ``parent`` | The dataset which contains the variable. | ++------------------+------------------+--------------------------------------------+ +| ``Tuple`` | ``shape`` | The length of each axis. | ++------------------+------------------+--------------------------------------------+ + + +Table 2.8 Axis Constructors + ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================+ +| ``cdms.createAxis(data, bounds=None)`` | Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Dataset.createAxis(name,ar)`` | Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented. ) | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``CdmsFile.createAxis(name,ar,unlimited=0)`` | Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|   | B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited`` | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createEqualAreaAxis(nlat)`` | See Table 2.2 on page 33. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createGaussianAxis(nlat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` | See Table 2.2 on page 18. | ++-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.9 CoordinateAxis Methods + ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+====================================================================+================================================================================================================================================================================================================================================================================+ +| ``Array`` | ``array = axis[i:j]`` | Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``axis[i:j] = array`` | Write a slice of data to the external file. Dataset axes are read-only. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``assignValue(array)`` | Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Axis`` | ``clone(copyData=1)`` | Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLatitude(persistent=0)`` | Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLevel(persistent=0)`` | Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateLongitude(persistent=0, modulo=360.0)`` | Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateTime(persistent=0, calendar = cdtime.MixedCalendar)`` | Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getBounds()`` | Get the associated boundary array. The shape of the return array depends on the type of axis: | +|   |   | * ``Axis``: ``(n,2)`` | +|   |   | * ``Axis2D``: ``(i,j,4)`` | +|   |   | * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. | +|   |   | If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``getCalendar()`` | Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: | +|   |   | * ``cdtime.GregorianCalendar``: the standard Gregorian calendar | +|   |   | * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar | +|   |   | * ``cdtime.JulianCalendar``: years divisible by 4 are leap years | +|   |   | * ``cdtime.NoLeapCalendar``: a year is 365 days | +|   |   | * ``cdtime.Calendar360``: a year is 360 days | +|   |   | * ``None``: no calendar can be identified | +|   |   | Note: If the axis is not a time axis, the global, file-related calendar is returned. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Array`` | ``getValue()`` | Get the entire axis vector. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLatitude()`` | Returns true iff the axis is a latitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLevel()`` | Returns true iff the axis is a level axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLongitude()`` | Returns true iff the axis is a longitude axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isTime()`` | Returns true iff the axis is a time axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``len(axis)`` | The length of the axis if one-dimensional. If multidimensional, the length of the first dimension. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``size()`` | The number of elements in the axis. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``String`` | ``typecode()`` | The ``Numeric`` datatype identifier. | ++---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.10 Axis Methods, additional to CoordinateAxis + ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============================+===============================================+==========================================================================================================================================================================================================================================================================================================================+ +| ``List`` of component times | ``asComponentTime(calendar=None)`` | ``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``List`` of relative times | ``asRelativeTime()`` | ``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``None`` | ``designateCircular(modulo, persistent=0)`` | Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isCircular()`` | Returns ``True`` if the axis has circular topology. An axis is defined as circular if: | +|   |   | * ``axis.topology == 'circular'``, or | +|   |   | * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0 | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Integer`` | ``isLinear()`` | Returns ``True`` if the axis has a linear representation. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``Tuple`` | ``mapInterval(interval)`` | Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``(i,j,k)`` | ``mapIntervalExt(interval)`` | Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: | +|   |   | * ``(x,y)`` | +|   |   | * ``(x,y,indicator)`` | +|   |   | * ``(x,y,indicator,cycle)`` | +|   |   | * ``None or ':'`` | +|   |   | * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: | +|   |   | * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis| +|   |   | * ``'n'`` - select node values which are contained in the interval | +|   |   | * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval | +|   |   | * ``'e'`` - same as n, but include an extra node on either side | +|   |   | * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval | +|   |   | * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. | +|   |   | * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. | +|   |   | * An interval of ``None`` or ``':'`` returns the full index interval of the axis. | +|   |   | * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. | +|   |   | * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` | +|   |   | * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. | +|   |   | * otherwise the interval wraps around the axis endpoint. | +|   |   | * see also: ``mapinterval``, ``variable.subregion()`` | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``transientaxis`` | ``subaxis(i,j,k=1)`` | create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute. | ++-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +table 2.11 axis slice operators + ++---------------+-----------------------------------------------------------------------------+ +| slice | definition | ++===============+=============================================================================+ +| ``[i]`` | the ``ith`` element, starting with index ``0`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:]`` | the ``ith`` element through and including the end | ++---------------+-----------------------------------------------------------------------------+ +| ``[:j]`` | the beginning element through, but not including, element ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[:]`` | the entire array | ++---------------+-----------------------------------------------------------------------------+ +| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | ++---------------+-----------------------------------------------------------------------------+ +| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | ++---------------+-----------------------------------------------------------------------------+ + +**example:** + +a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length +``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index +interval(s), with wraparound. the result index interval ``-2 <= n < 3`` +wraps around, since ``-2 < 0``, and has a stride of ``1``. this is +equivalent to the two contiguous index intervals ``2 <= n < 0`` and +``0 <= n < 3`` + +.. raw:: html + +
+ +:: + + >>> axis.isCircular() + 1 + >>> axis.mapIntervalExt((-5.0,5.0,'co')) + (-2,3,1) + +.. raw:: html + +
+ + +2.6 CdmsFile +^^^^^^^^^^^^ +A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` +interface. netCDF files are accessible in read-write mode. All other +formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. + +As of CDMS V3, the legacy cuDataset interface is also supported by +Cdms-Files. See “cu Module” on page 180. + + +Table 2.12 CdmsFile Internal Attributes + ++------------------+------------------+---------------------------------------+ +| Type | Name | Definition | ++==================+==================+=======================================+ +| ``Dictionary`` | ``attributes`` | Global, external file attributes | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``grids`` | Grids contained in the file. | ++------------------+------------------+---------------------------------------+ +| ``String`` | ``id`` | File pathname. | ++------------------+------------------+---------------------------------------+ +| ``Dictionary`` | ``variables`` | Variables contained in the file. | ++------------------+------------------+---------------------------------------+ + + +Table 2.13 CdmsFile Constructors + ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++==========================================+==================================================================================================================================================================================+ +| ``fileobj = cdms.open(path, mode)`` | Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``fileobj = cdms.createDataset(path)`` | Create the file specified by path, a string. | ++------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.14 CdmsFile Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| ``Transient-Variable`` | ``fileobj(varname, selec | Calling a ``CdmsFile`` | +| | tor)`` | object as a function | +| | | reads the region of data | +| | | specified by the | +| | | ``selector``. The result | +| | | is a transient variable, | +| | | unless ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | nc') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| ``Variable``, ``Axis``, | ``fileobj['id']`` | Get the persistent | +| or ``Grid`` | | variable, axis or grid | +| | | object having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. | +| | | | +| | | **Example:** The | +| | | following gets the | +| | | persistent variable | +| | | ``v``, equivalent to | +| | | ``v = f.variables['prc'] | +| | | ``. | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.nc') | +| | | v = f['prc'] | +| | | | +| | | **Example:** The | +| | | following gets the axis | +| | | named time, equivalent | +| | | to | +| | | ``t = f.axes['time']``. | +| | | | +| | | ``t = f['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``copyAxis(axis, newname | Copy ``axis`` values and | +| | =None)`` | attributes to a new axis | +| | | in the file. The | +| | | returned object is | +| | | persistent: it can be | +| | | used to write axis data | +| | | to or read axis data | +| | | from the file. If an | +| | | axis already exists in | +| | | the file, having the | +| | | same name and coordinate | +| | | values, it is returned. | +| | | It is an error if an | +| | | axis of the same name | +| | | exists, but with | +| | | different coordinate | +| | | values. ``axis`` is the | +| | | axis object to be | +| | | copied. ``newname``, if | +| | | specified, is the string | +| | | identifier of the new | +| | | axis object. If not | +| | | specified, the | +| | | identifier of the input | +| | | axis is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Grid`` | ``copyGrid(grid, newname | Copy grid values and | +| | =None)`` | attributes to a new grid | +| | | in the file. The | +| | | returned grid is | +| | | persistent. If a grid | +| | | already exists in the | +| | | file, having the same | +| | | name and axes, it is | +| | | returned. An error is | +| | | raised if a grid of the | +| | | same name exists, having | +| | | different axes. ``grid`` | +| | | is the grid object to be | +| | | copied. ``newname``, if | +| | | specified is the string | +| | | identifier of the new | +| | | grid object. If | +| | | unspecified, the | +| | | identifier of the input | +| | | grid is used. | ++--------------------------+--------------------------+--------------------------+ +| ``Axis`` | ``createAxis(id, ar, unl | Create a new ``Axis``. | +| | imited=0)`` | This is a persistent | +| | | object which can be used | +| | | to read or write axis | +| | | data to the file. ``id`` | +| | | is an alphanumeric | +| | | string identifier, | +| | | containing no blanks. | +| | | ``ar`` is the | +| | | one-dimensional axis | +| | | array. Set ``unlimited`` | +| | | to ``cdms.Unlimited`` to | +| | | indicate that the axis | +| | | is extensible. | ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a ``RectGrid`` in | +| | , lon, order, type="gene | the file. This is not a | +| | ric", mask=None)`` | persistent object: the | +| | | order, type, and mask | +| | | are not written to the | +| | | file. However, the grid | +| | | may be used for | +| | | regridding operations. | +| | | ``lat`` is a latitude | +| | | axis in the file. | +| | | ``lon`` is a longitude | +| | | axis in the file. | +| | | ``order`` is a string | +| | | with value ``"yx"`` (the | +| | | first grid dimension is | +| | | latitude) or ``"xy"`` | +| | | (the first grid | +| | | dimension is longitude). | +| | | ``type`` is one of | +| | | ``'gaussian'``,\ ``'unif | +| | | orm'``,\ ``'equalarea'`` | +| | | , | +| | | or ``'generic'``. If | +| | | specified, ``mask`` is a | +| | | two-dimensional, logical | +| | | Numeric array (all | +| | | values are zero or one) | +| | | with the same shape as | +| | | the grid. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariable(String | Create a new Variable. | +| | id, String datatype,List | This is a persistent | +| | axes, fill_value=None)`` | object which can be used | +| | | to read or write | +| | | variable data to the | +| | | file. ``id`` is a String | +| | | name which is unique | +| | | with respect to all | +| | | other objects in the | +| | | file. ``datatype`` is an | +| | | ``MA`` typecode, e.g., | +| | | ``MA.Float``, | +| | | ``MA.Int``. ``axes`` is | +| | | a list of Axis and/or | +| | | Grid objects. | +| | | ``fill_value`` is the | +| | | missing value | +| | | (optional). | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | ``createVariableCopy(var | Create a new | +| | , newname=None)`` | ``Variable``, with the | +| | | same name, axes, and | +| | | attributes as the input | +| | | variable. An error is | +| | | raised if a variable of | +| | | the same name exists in | +| | | the file. ``var`` is the | +| | | ``Variable`` to be | +| | | copied. ``newname``, if | +| | | specified is the name of | +| | | the new variable. If | +| | | unspecified, the | +| | | returned variable has | +| | | the same name as | +| | | ``var``. | +| | | | +| | | **Note:** Unlike | +| | | copyAxis, the actual | +| | | data is not copied to | +| | | the new variable. | ++--------------------------+--------------------------+--------------------------+ +| ``CurveGrid`` or | ``readScripGrid(self, wh | Read a curvilinear or | +| ``Generic-Grid`` | ichGrid='destination', c | generic grid from a | +| | heck-Grid=1)`` | SCRIP netCDF file. The | +| | | file can be a SCRIP grid | +| | | file or remapping file. | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. If | +| | | ``checkGrid`` is ``1`` | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``sync()`` | Writes any pending | +| | | changes to the file. | ++--------------------------+--------------------------+--------------------------+ +| ``Variable`` | :: | Write a variable or | +| | | array to the file. The | +| | write(var, attribute | return value is the | +| | s=None, axes=None, extbo | associated file | +| | unds=None, id=None, exte | variable. | +| | nd=None, fill_value=None | | +| | , index=None, typecode=N | If the variable does not | +| | one) | exist in the file, it is | +| | | first defined and all | +| | | attributes written, then | +| | | the data is written. By | +| | | default, the time | +| | | dimension of the | +| | | variable is defined as | +| | | the unlimited dimension | +| | | of the file. If the data | +| | | is already defined, then | +| | | data is extended or | +| | | overwritten depending on | +| | | the value of keywords | +| | | ``extend`` and | +| | | ``index``, and the | +| | | unlimited dimension | +| | | values associated with | +| | | ``var``. | +| | | | +| | | ``var`` is a Variable, | +| | | masked array, or Numeric | +| | | array. ``attributes`` is | +| | | the attribute dictionary | +| | | for the variable. The | +| | | default is | +| | | ``var.attributes``. | +| | | ``axes`` is the list of | +| | | file axes comprising the | +| | | domain of the variable. | +| | | The default is to copy | +| | | ``var.getAxisList()``. | +| | | ``extbounds`` is the | +| | | unlimited dimension | +| | | bounds. Defaults to | +| | | ``var.getAxis(0).getBoun | +| | | ds()``. | +| | | ``id`` is the variable | +| | | name in the file. | +| | | Default is ``var.id``. | +| | | ``extend = 1`` causes | +| | | the first dimension to | +| | | be unlimited: | +| | | iteratively writeable. | +| | | The default is ``None``, | +| | | in which case the first | +| | | dimension is extensible | +| | | if it is ``time.Set`` to | +| | | ``0`` to turn off this | +| | | behaviour. | +| | | ``fill_value`` is the | +| | | missing value flag. | +| | | ``index`` is the | +| | | extended dimension index | +| | | to write to. The default | +| | | index is determined by | +| | | lookup relative to the | +| | | existing extended | +| | | dimension. | +| | | | +| | | **Note:** data can also | +| | | be written by setting a | +| | | slice of a file | +| | | variable, and attributes | +| | | can be written by | +| | | setting an attribute of | +| | | a file variable. | ++--------------------------+--------------------------+--------------------------+ + + +Table 2.15 CDMS Datatypes + ++-----------------+-----------------------------------+ +| CDMS Datatype | Definition | ++=================+===================================+ +| ``CdChar`` | character | ++-----------------+-----------------------------------+ +| ``CdDouble`` | double-precision floating-point | ++-----------------+-----------------------------------+ +| ``CdFloat`` | floating-point | ++-----------------+-----------------------------------+ +| ``CdInt`` | integer | ++-----------------+-----------------------------------+ +| ``CdLong`` | long integer | ++-----------------+-----------------------------------+ +| ``CdShort`` | short integer | ++-----------------+-----------------------------------+ + + +2.7 Database +^^^^^^^^^^^^ +A Database is a collection of datasets and other CDMS objects. It +consists of a hierarchical collection of objects, with the database +being at the root, or top of the hierarchy. A database is used to: + +- search for metadata +- access data +- provide authentication and access control for data and metadata + +The figure below illustrates several important points: + +- Each object in the database has a relative name of the form tag=id. + The id of an object is unique with respect to all objects contained + in the parent. + +- The name of the object consists of its relative name followed by the + relative name(s) of its antecedent objects, up to and including the + database name. In the figure below, one of the variables has name + ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. + +- Subordinate objects are thought of as being contained in the parent. + In this example, the database ‘CDMS’ contains two datasets, each of + which contain several variables. + +|Diagram 1| + +Figure 1 + + +2.7.1 Overview + +To access a database: + +#. Open a connection. The connect method opens a database connection. + connect takes a database URI and returns a database object: + ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` +#. Search the database, locating one or more datasets, variables, and/or + other objects. + + The database searchFilter method searches the database. A single + database connection may be used for an arbitrary number of searches. + + **Example**: Find all observed datasets + + ``result = db.searchFilter(category="observed",tag="dataset")`` + + Searches can be restricted to a subhierarchy of the database. + + **Example:** Search just the dataset ``'ncep_reanalysis_mo'``: + + ``result = db.searchFilter(relbase="dataset=ncep_reanalysis")`` + +#. Refine the search results if necessary. The result of a search can be + narrowed with the searchPredicate method. +#. Process the results. A search result consists of a sequence of + entries. Each entry has a name, the name of the CDMS object, and an + attribute dictionary, consisting of the attributes located by the + search: + + `` for entry in result: print entry.name, entry.attributes`` + +#. Access the data. The CDMS object associated with an entry is obtained + from the getObject method: + + ``obj = entry.getObject()`` + + If the id of a dataset is known, the dataset can be opened directly + with the open method: + + ``dset = db.open("ncep_reanalysis_mo")`` + +#. Close the database connection: + + ``db.close()`` + + +Table 2.16 Database Internal Attributes + ++------------------+------------------+----------------------------------------+ +| Type | Name | Summary | ++==================+==================+========================================+ +| ``Dictionary`` | ``attributes`` | Database attribute dictionary | ++------------------+------------------+----------------------------------------+ +| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``netloc`` | Hostname, for server-based databases | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``path`` | path name | ++------------------+------------------+----------------------------------------+ +| ``String`` | ``uri`` | Uniform Resource Identifier | ++------------------+------------------+----------------------------------------+ + + +Table 2.17 Database Constructors + ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================+==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``db = cdms.connect(uri=None, user="", password="")`` | Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection | ++---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.18 Database Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| None | ``close()`` | Close a database | +| | | connection. | ++--------------------------+--------------------------+--------------------------+ +| List | ``listDatasets()`` | Return a list of the | +| | | dataset IDs in this | +| | | database. A dataset ID | +| | | can be passed to the | +| | | ``open`` command. | ++--------------------------+--------------------------+--------------------------+ +| Dataset | ``open(dsetid, mode='r') | Open a dataset. | +| | `` | | +| | | ``dsetid`` is the string | +| | | dataset identifier | +| | | | +| | | ``mode`` is the open | +| | | mode, 'r' - read-only, | +| | | 'r+' - read-write, 'w' - | +| | | create. | +| | | | +| | | ``openDataset`` is a | +| | | synonym for ``open``. | ++--------------------------+--------------------------+--------------------------+ +| SearchResult | :: | Search a CDMS database. | +| | | | +| | searchFilter(filter= | ``filter`` is the string | +| | None, tag=None, relbase= | search filter. Simple | +| | None, scope=Subtree, att | filters have the form | +| | names=None, timeout=None | "tag = value". Simple | +| | ) | filters can be combined | +| | | using logical operators | +| | | '&', '\|', '!' in prefix | +| | | notation. | +| | | | +| | | **Example:** | +| | | | +| | | The filter | +| | | ``'(&(objec)(id=cli))'`` | +| | | finds all variables | +| | | named "cli". | +| | | | +| | | A formal definition of | +| | | search filters is | +| | | provided in the | +| | | following section. | +| | | | +| | | ``tag`` restricts the | +| | | search to objects with | +| | | that tag ("dataset" \| | +| | | "variable" \| "database" | +| | | \| "axis" \| "grid"). | +| | | | +| | | ``relbase`` is the | +| | | relative name of the | +| | | base object of the | +| | | search. The search is | +| | | restricted to the base | +| | | object and all objects | +| | | below it in the | +| | | hierarchy. | +| | | | +| | | **Example:** | +| | | | +| | | To search only dataset | +| | | 'ncep\_reanalysis\_mo', | +| | | specify: | +| | | | +| | | ``relbase="dataset=ncep_ | +| | | reanalysis_mo" `` | +| | | | +| | | To search only variable | +| | | 'ua' in | +| | | 'ncep\_reanalysis\_mo', | +| | | use: | +| | | | +| | | ``relbase="variable=ua,d | +| | | ataset=ncep_reanalysis_m | +| | | o"`` | +| | | | +| | | If no base is specified, | +| | | the entire database is | +| | | searched. See the | +| | | ``scope`` argument also. | +| | | | +| | | ``scope`` is the search | +| | | scope (**Subtree** \| | +| | | **Onelevel** \| | +| | | **Base**). | +| | | | +| | | - **Subtree** searches | +| | | the base object and | +| | | its descendants. | +| | | - **Onelevel** searches | +| | | the base object and | +| | | its immediate | +| | | descendants. | +| | | - **Base**\ searches | +| | | the base object | +| | | alone. | +| | | | +| | | The default is | +| | | **Subtree**. | +| | | | +| | | ``attnames``: list of | +| | | attribute names. | +| | | Restricts the attributes | +| | | returned. If ``None``, | +| | | all attributes are | +| | | returned. Attributes | +| | | 'id' and 'objectclass' | +| | | are always included in | +| | | the list. | +| | | | +| | | ``timeout``: integer | +| | | number of seconds before | +| | | timeout. The default is | +| | | no timeout. | ++--------------------------+--------------------------+--------------------------+ + + +2.7.2 Searching a database + +The ``searchFilter`` method is used to search a database. The result is +called a search result, and consists of a sequence of result entries. + +In its simplest form, ``searchFilter`` takes an argument consisting of a +string filter. The search returns a sequence of entries, corresponding +to those objects having an attribute which matches the filter. Simple +filters have the form (tag = value), where value can contain wildcards. +For example: + +.. raw:: html + +
+ +:: + + (id = ncep*) + (project = AMIP2) + +.. raw:: html + +
+ ++--------------------------------------------------------------------+------------------------+ +| Simple filters can be combined with the logical operators ‘&’, ‘ | ’, ‘!’. For example, | ++--------------------------------------------------------------------+------------------------+ + +.. raw:: html + +
+ +:: + + (&(id = bmrc*)(project = AMIP2)) + +.. raw:: html + +
+ +matches all objects with id starting with bmrc, and a project attribute +with value ‘AMIP2’. + +Formally, search filters are strings defined as follows: + +.. raw:: html + +
+ +:: + + filter ::= "(" filtercomp ")" + + filtercomp ::= "&" filterlist | # and + "|" filterlist | # or + "!" filterlist | # not + simple + + filterlist ::= filter | filter filterlist + simple ::= tag op value + op ::= "=" | # equality + + "~=" | # approximate equality + "<=" | # lexicographically less than or equal to + ">=" # lexicographically greater than or equal to + + tag ::= string attribute name + value ::= string attribute value, may include '*' as a wild card + +.. raw:: html + +
+ +Attribute names are defined in the chapter on “Climate Data Markup +Language (CDML)” on page 149. In addition, some special attributes are +defined for convenience: + +- ``category`` is either “experimental” or “observed” +- ``parentid`` is the ID of the parent dataset +- ``project`` is a project identifier, e.g., “AMIP2” +- ``objectclass`` is the list of tags associated with the object. + +The set of objects searched is called the search scope. The top object +in the hierarchy is the base object. By default, all objects in the +database are searched, that is, the database is the base object. If the +database is very large, this may result in an unnecessarily slow or +inefficient search. To remedy this the search scope can be limited in +several ways: + +- The base object can be changed. +- The scope can be limited to the base object and one level below, or + to just the base object. +- The search can be restricted to objects of a given class (dataset, + variable, etc.) +- The search can be restricted to return only a subset of the object + attributes +- The search can be restricted to the result of a previous search. +- A search result is accessed sequentially within a for loop: + +.. raw:: html + +
+ +:: + + result = db.searchFilter('(&(category=obs*)(id=ncep*))') + for entry in result: + print entry.name + +.. raw:: html + +
+ +Search results can be narrowed using ``searchPredicate``. In the +following example, the result of one search is itself searched for all +variables defined on a 94x192 grid: + +.. raw:: html + +
+ +:: + + >>> result = db.searchFilter('parentid=ncep*',tag="variable") + >>> len(result) + 65 + >>> result2 = result.searchPredicate(lambda x: + + x.getGrid().shape==(94,192)) + >>> len(result2) + 3 + >>> for entry in result2: print entry.name + variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + + o=LLNL, c=US + +.. raw:: html + +
+ + +Table 2.19 SearchResult Methods + ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++================+============================================+==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ResultEntry | ``[i]`` | Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):`` | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``len()`` | Number of entries in the result. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| SearchResult | ``searchPredicate(predicate, tag=None)`` | Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag. **Note**: In the current implementation, ``searchPredicate``\ is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches. | ++----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +A search result is a sequence of result entries. Each entry has a string +name, the name of the object in the database hierarchy, and an attribute +dictionary. An entry corresponds to an object found by the search, but +differs from the object, in that only the attributes requested are +associated with the entry. In general, there will be much more +information defined for the associated CDMS object, which is retrieved +with the ``getObject`` method. + + +Table 2.20 ResultEntry Attributes + ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+=======================================================================================================================+ +| String | ``name`` | The name of this entry in the database. | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +| Dictionary | ``attributes`` | The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key | ++--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ + + +Table 2.21 ResultEntry Methods + ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Type | Method | Definition | ++===============+===================+======================================================================================================================================================================================================================================================================================+ +| ``CdmsObj`` | ``getObject()`` | Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. | ++---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.7.3 Accessing data + +To access data via CDMS: + +#. Locate the dataset ID. This may involve searching the metadata. +#. Open the dataset, using the open method. +#. Reference the portion of the variable to be read. + +In the next example, a portion of variable ‘ua’ is read from dataset +‘ncep\_reanalysis\_mo’: + +.. raw:: html + +
+ +:: + + dset = db.open('ncep_reanalysis_mo') + ua = dset.variables['ua'] + data = ua[0,0] + +.. raw:: html + +
+ + +2.7.4 Examples of database searches + +In the following examples, db is the database opened with + +.. raw:: html + +
+ +:: + + db = cdms.connect() + +.. raw:: html + +
+ +This defaults to the database defined in environment variable +``CDMSROOT``. + +**Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", + tag = "variable"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all axes with bounds defined: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter="bounds=*",tag="axis"): + print entry.name + +.. raw:: html + +
+ +**Example:** Locate all GDT datasets: + +.. raw:: html + +
+ +:: + + for entry in + db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all variables with missing time values, in observed +datasets: + +.. raw:: html + +
+ +:: + + def missingTime(obj): + time = obj.getTime() + return time.length != time.partition_length + + result = db.searchFilter(filter="category=observed") + for entry in result.searchPredicate(missingTime): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all CMIP2 datasets having a variable with id “hfss”: + +.. raw:: html + +
+ +:: + + for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): + print entry.getObject().parent.id + +.. raw:: html + +
+ +**Example:** Find all observed variables on 73x144 grids: + +.. raw:: html + +
+ +:: + + result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): + print entry.name + +.. raw:: html + +
+ +**Example:** Find all observed variables with more than 1000 timepoints: + +.. raw:: html + +
+ +:: + + result = db.searchFilter(category='obs*') + for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): + print entry.name, len(entry.getObject().getTime()) + +.. raw:: html + +
+ +**Example:** Find the total number of each type of object in the +database + +.. raw:: html + +
+ +:: + + print len(db.searchFilter(tag="database")),"database" + print len(db.searchFilter(tag="dataset")),"datasets" + print len(db.searchFilter(tag="variable")),"variables" + print len(db.searchFilter(tag="axis")),"axes" + +.. raw:: html + +
+ + +2.8 Dataset +^^^^^^^^^^^ +A Dataset is a virtual file. It consists of a metafile, in CDML/XML +representation, and one or more data files. + +As of CDMS V3, the legacy cuDataset interface is supported by Datasets. +See “cu Module” on page 180. + + +Table 2.22 Dataset Internal Attributes + ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Type | Name | Description | ++==============+==================+==========================================================================================================+ +| Dictionary | ``attributes`` | Dataset external attributes. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``axes`` | Axes contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``datapath`` | Path of data files, relative to the parent database. If no parent, the datapath is absolute. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``grids`` | Grids contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``mode`` | Open mode. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Database | ``parent`` | Database which contains this dataset. If the dataset is not part of a database, the value is ``None``. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| String | ``uri`` | Uniform Resource Identifier of this dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``variables`` | Variables contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ +| Dictionary | ``xlinks`` | External links contained in the dataset. | ++--------------+------------------+----------------------------------------------------------------------------------------------------------+ + + +Table 2.23 Dataset Constructors + ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++===========================================================+===================================================================================================================================================================================================================+ +| ``datasetobj = cdms.open(String uri, String mode='r')`` | Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open`` | ++-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.24 Open Modes + ++--------+-----------------------------------------------------------------------+ +| Mode | Definition | ++========+=======================================================================+ +| ‘r’ | read-only | ++--------+-----------------------------------------------------------------------+ +| ‘r+’ | read-write | ++--------+-----------------------------------------------------------------------+ +| ‘a’ | read-write. Open the file if it exists, otherwise create a new file | ++--------+-----------------------------------------------------------------------+ +| ‘w’ | Create a new file, read-write | ++--------+-----------------------------------------------------------------------+ + + +Table 2.25 Dataset Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Transient-Variable | ``datasetobj(varname, se | Calling a Dataset object | +| | lector)`` | as a function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless | +| | | ``raw = 1`` is | +| | | specified. See | +| | | "Selectors" on page 103. | +| | | **Example:** The | +| | | following reads data for | +| | | variable 'prc', year | +| | | 1980: | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('test. | +| | | xml') | +| | | x = f('prc', time=(' | +| | | 1980-1','1981-1')) | ++--------------------------+--------------------------+--------------------------+ +| Variable, Axis, or Grid | ``datasetobj['id']`` | The square bracket | +| | | operator applied to a | +| | | dataset gets the | +| | | persistent variable, | +| | | axis or grid object | +| | | having the string | +| | | identifier. This does | +| | | not read the data for a | +| | | variable. Returns | +| | | ``None`` if not found. | +| | | | +| | | **Example:** | +| | | | +| | | :: | +| | | | +| | | f = cdms.open('sampl | +| | | e.xml') | +| | | v = f['prc'] | +| | | | +| | | gets the persistent | +| | | variable v, equivalent | +| | | to | +| | | ``v = f.variab | +| | | les['prc']``. | +| | | | +| | | **Example:** | +| | | | +| | | | ``t = f['time']`` | +| | | | gets the axis named | +| | | 'time', equivalent to | +| | | ``t = f.axes['time']`` | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``close()`` | Close the dataset. | ++--------------------------+--------------------------+--------------------------+ +| ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | +| | , lon, order, type="gene | dataset. This is not a | +| | ric", mask=Non | persistent object: the | +| | e)`` | order, type, and mask | +| | | are not written to the | +| | | dataset. However, the | +| | | grid may be used for | +| | | regridding operations. | +| | | | +| | | ``lat`` is a latitude | +| | | axis in the dataset. | +| | | | +| | | ``lon`` is a longitude | +| | | axis in the dataset. | +| | | | +| | | ``order`` is a string | +| | | with value "yx" (the | +| | | first grid dimension is | +| | | latitude) or "xy" (the | +| | | first grid dimension is | +| | | longitude). | +| | | | +| | | ``type`` is one of | +| | | 'gaussian','uniform','eq | +| | | ualarea',or | +| | | 'generic' | +| | | | +| | | If specified, ``mask`` | +| | | is a two-dimensional, | +| | | logical Numeric array | +| | | (all values are zero or | +| | | one) with the same shape | +| | | as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(id)`` | Get an axis object from | +| | | the file or dataset. | +| | | | +| | | ``id`` is the string | +| | | axis identifier. | ++--------------------------+--------------------------+--------------------------+ +| Grid | ``getGrid(id)`` | Get a grid object from a | +| | | file or dataset. | +| | | | +| | | ``id`` is the string | +| | | grid identifier. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths()`` | Get a sorted list of | +| | | pathnames of datafiles | +| | | which comprise the | +| | | dataset. This does not | +| | | include the XML metafile | +| | | path, which is stored in | +| | | the .uri attribute. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``getVariable(id)`` | Get a variable object | +| | | from a file or dataset. | +| | | | +| | | ``id`` is the string | +| | | variable identifier. | ++--------------------------+--------------------------+--------------------------+ +| CurveGrid or GenericGrid | ``readScripGrid(self, wh | Read a curvilinear or | +| | ichGrid='destination', c | generic grid from a | +| | heck-or Generic-Grid=1)` | SCRIP dataset. The | +| | ` | dataset can be a SCRIP | +| | | grid file or remapping | +| | | file. | +| | | | +| | | If a mapping file, | +| | | ``whichGrid`` chooses | +| | | the grid to read, either | +| | | ``"source"`` or | +| | | ``"destination"``. | +| | | | +| | | If ``checkGrid`` is 1 | +| | | (default), the grid | +| | | cells are checked for | +| | | convexity, and | +| | | 'repaired' if necessary. | +| | | Grid cells may appear to | +| | | be nonconvex if they | +| | | cross a ``0 / 2pi`` | +| | | boundary. The repair | +| | | consists of shifting the | +| | | cell vertices to the | +| | | same side modulo 360 | +| | | degrees. | ++--------------------------+--------------------------+--------------------------+ +| None | ``sync()`` | Write any pending | +| | | changes to the dataset. | ++--------------------------+--------------------------+--------------------------+ + + +2.9 MV module +^^^^^^^^^^^^^ + +The fundamental CDMS data object is the variable. A variable is +comprised of: + +- a masked data array, as defined in the NumPy MA module. +- a domain: an ordered list of axes and/or grids. +- an attribute dictionary. + +The MV module is a work-alike replacement for the MA module, that +carries along the domain and attribute information where appropriate. MV +provides the same set of functions as MA. However, MV functions generate +transient variables as results. Often this simplifies scripts that +perform computation. MA is part of the Python Numeric package, +documented at http://www.numpy.org. + +MV can be imported with the command: + +.. raw:: html + +
+ +:: + + import MV + +.. raw:: html + +
+ +The command + +.. raw:: html + +
+ +:: + + from MV import * + +.. raw:: html + +
+ +allows use of MV commands without any prefix. + +Table 2.26 on page 75 lists the constructors in MV. All functions return +a transient variable. In most cases the keywords axes, attributes, and +id are available. axes is a list of axis objects which specifies the +domain of the variable. attributes is a dictionary. id is a special +attribute string that serves as the identifier of the variable, and +should not contain blanks or non-printing characters. It is used when +the variable is plotted or written to a file. Since the id is just an +attribute, it can also be set like any attribute: + +.. raw:: html + +
+ +:: + + var.id = 'temperature' + +.. raw:: html + +
+ +For completeness MV provides access to all the MA functions. The +functions not listed in the following tables are identical to the +corresponding MA function: ``allclose``, ``allequal``, +``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, +``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, +``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, +``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, +``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, +``putmask``, ``rank``, ``ravel``, ``set_fill_value``, +``set_print_limit``, ``shape``, ``size``. See the documentation at +http://numpy.sourceforge.net for a description of these functions. + + +Table 2.26 Variable Constructors in module MV + ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Constructor | Description | ++====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MA.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MA.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | return an array of all ones of the given length or shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``reshape(a, newshape, axes=none, attributes=none, id=none)`` | copy of a with a new shape. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``resize(a, new_shape, axes=none, attributes=none, id=none)`` | return a new array with the specified shape. the original arrays total size can be any size. | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | an array of all zeros of the given length or shape | ++--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +The following table describes the MV non-constructor functions. with the +exception of argsort, all functions return a transient variable. + + +Table 2.27 MV functions + ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Function | Description | ++=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+ +| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numeric array of indices for sorting along a given axis. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asarray(data, typecode=None)`` | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``average(a, axis=0, weights=None)`` | Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``choose(condition, t)`` | Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``concatenate(arrays, axis=0, axisid=None, axisattributes=None)`` | Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``count(a, axis=None)`` | Count of the non-masked elements in ``a``, or along a certain axis. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``isMaskedVariable(x)`` | Return true if ``x`` is an instance of a variable. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_equal(x, value)`` | ``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_greater(x, value)`` | ``x`` masked where ``x > value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_greater_equal(x, value)`` | ``x`` masked where ``x >= value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_less(x, value)`` | ``x`` masked where ``x < value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_less_equal(x, value)`` | ``x`` masked where ``x ≤ value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_not_equal(x, value)`` | ``x`` masked where ``x != value`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_outside(x, v1, v2)`` | ``x`` with mask of all values of ``x`` that are outside ``[v1,v2]`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``masked_where(condition, x, copy=1)`` | Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``maximum(a, b=None)`` | Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``minimum(a, b=None)`` | Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``outerproduct(a, b)`` | Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``power(a, b)`` | ``a**b`` | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``product(a, axis=0, fill_value=1)`` | Product of elements along axis using ``fill_value`` for missing elements. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``repeat(ar, repeats, axis=0)`` | Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``set_default_fill_value(value_type, value)`` | Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``sort(ar, axis=-1)`` | Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``sum(a, axis=0, fill_value=0)`` | Sum of elements along a certain axis using ``fill_value`` for missing. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numeric manual. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``transpose(ar, axes=None)`` | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes. | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``where(condition, x, y)`` | ``x`` where ``condition`` is true, ``y`` otherwise | ++---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +2.10 HorizontalGrid +^^^^^^^^^^^^^^^^^^^ + +A HorizontalGrid represents a latitude-longitude coordinate system. In +addition, it optionally describes how lat-lon space is partitioned into +cells. Specifically, a HorizontalGrid: + +- consists of a latitude and longitude coordinate axis. +- may have associated boundary arrays describing the grid cell + boundaries, +- may optionally have an associated logical mask. + +CDMS supports several types of HorizontalGrids: + + +Table 2.28 + ++-------------------+----------------------------------------------------------------------------------+ +| Grid Type | Definition | ++===================+==================================================================================+ +| ``RectGrid`` | Associated latitude an longitude are 1-D axes, with strictly monotonic values. | ++-------------------+----------------------------------------------------------------------------------+ +| ``CurveGrid`` | Latitude and longitude are 2-D coordinate axes (Axis2D). | ++-------------------+----------------------------------------------------------------------------------+ +| ``GenericGrid`` | Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D) | ++-------------------+----------------------------------------------------------------------------------+ + + +Table 2.29 HorizontalGrid Internal Attribute + ++-----------------------+------------------+------------------------------------------------+ +| Type | Name | Definition | ++=======================+==================+================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+------------------+------------------------------------------------+ +| String | ``id`` | The grid identifier. | ++-----------------------+------------------+------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | ++-----------------------+------------------+------------------------------------------------+ +| Tuple | ``shape`` | The shape of the grid, a 2-tuple | ++-----------------------+------------------+------------------------------------------------+ + +Table 2.31 on page 82 describes the methods that apply to all types of +HorizontalGrids. Table 2.32 on page 86 describes the additional methods +that are unique to RectGrids. + + +Table 2.30 RectGrid Constructors + ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| Constructor | Description | ++=========================================================================================================+==================================================================================+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | Create a grid not associated with a file or dataset. See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``CdmsFile.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a file. See Table 2.14 on page 53. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``Dataset.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a dataset. See Table 2.25 on page 71. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGaussianGrid(nlats, xorigin=0.0, order="yx")`` | See Table 2.2 on page 33. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createGlobalMeanGrid(grid)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None)`` | See Table 2.2 on page 18. | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +| ``cdms.createZonalGrid(grid)`` | See Table 2.2 on page 18 | ++---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ + + +Table 2.31 HorizontalGrid Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| Horizontal-Grid | ``clone()`` | Return a transient copy | +| | | of the grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(Integer n)`` | Get the n-th axis.n is | +| | | either 0 or 1. | ++--------------------------+--------------------------+--------------------------+ +| Tuple | ``getBounds()`` | Get the grid boundary | +| | | arrays. | +| | | | +| | | Returns a tuple | +| | | ``(latitudeArray, longit | +| | | udeArray)``, | +| | | where latitudeArray is a | +| | | Numeric array of | +| | | latitude bounds, and | +| | | similarly for | +| | | longitudeArray.The shape | +| | | of latitudeArray and | +| | | longitudeArray depend on | +| | | the type of grid: | +| | | | +| | | - for rectangular grids | +| | | with shape (nlat, | +| | | nlon), the boundary | +| | | arrays have shape | +| | | (nlat,2) and | +| | | (nlon,2). | +| | | - for curvilinear grids | +| | | with shape (nx, ny), | +| | | the boundary arrays | +| | | each have shape (nx, | +| | | ny, 4). | +| | | - for generic grids | +| | | with shape (ncell,), | +| | | the boundary arrays | +| | | each have shape | +| | | (ncell, nvert) where | +| | | nvert is the maximum | +| | | number of vertices | +| | | per cell. | +| | | | +| | | For rectilinear grids: | +| | | If no boundary arrays | +| | | are explicitly defined | +| | | (in the file or | +| | | dataset), the result | +| | | depends on the auto- | +| | | Bounds mode (see | +| | | ``cdms.setAutoBounds``) | +| | | and the grid | +| | | classification mode (see | +| | | ``cdms.setClassifyGrids` | +| | | `). | +| | | By default, autoBounds | +| | | mode is enabled, in | +| | | which case the boundary | +| | | arrays are generated | +| | | based on the type of | +| | | grid. If disabled, the | +| | | return value is | +| | | (None,None).For | +| | | rectilinear grids: The | +| | | grid classification mode | +| | | specifies how the grid | +| | | type is to be | +| | | determined. By default, | +| | | the grid type (Gaussian, | +| | | uniform, etc.) is | +| | | determined by calling | +| | | grid.classifyInFamily. | +| | | If the mode is 'off' | +| | | grid.getType is used | +| | | instead. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the latitude axis of | +| | | this grid. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMask()`` | Get the mask array of | +| | | this grid, if | +| | | any.Returns a 2-D | +| | | Numeric array, having | +| | | the same shape as the | +| | | grid. If the mask is not | +| | | explicitly defined, the | +| | | return value is | +| | | ``None``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getMesh(self, transpos | Generate a mesh array | +| | e=None)`` | for the meshfill | +| | | graphics method.If | +| | | transpose is defined to | +| | | a tuple, say (1,0), | +| | | first transpose | +| | | latbounds and lonbounds | +| | | according to the tuple, | +| | | in this case (1,0,2). | ++--------------------------+--------------------------+--------------------------+ +| None | ``setBounds(latBounds, l | Set the grid | +| | onBounds, persistent=0)` | boundaries.\ ``latBounds | +| | ` | `` | +| | | is a NumPy array of | +| | | shape (n,2), such that | +| | | the boundaries of the | +| | | kth axis value are | +| | | ``[latBounds[k,0],latBou | +| | | nds[k,1] ]``. | +| | | ``lonBounds`` is defined | +| | | similarly for the | +| | | longitude array. | +| | | **Note:** By default, | +| | | the boundaries are not | +| | | written to the file or | +| | | dataset containing the | +| | | grid (if any). This | +| | | allows bounds to be set | +| | | on read-only files, for | +| | | regridding. If the | +| | | optional argument | +| | | ``persistent`` is set to | +| | | 1, the boundary array is | +| | | written to the file. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setMask(mask, persiste | Set the grid mask. If | +| | nt=0)`` | ``persistent == 1``, the | +| | | mask values are written | +| | | to the associated file, | +| | | if any. Otherwise, the | +| | | mask is associated with | +| | | the grid, but no I/O is | +| | | generated. ``mask`` is a | +| | | two-dimensional, | +| | | Boolean-valued Numeric | +| | | array, having the same | +| | | shape as the grid. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``subGridRegion(latInter | Create a new grid | +| | val, lonInterval)`` | corresponding to the | +| | | coordinate region | +| | | defined by | +| | | ``latInterval, lonInterv | +| | | al.`` | +| | | | +| | | ``latInterval`` and | +| | | ``lonInterval`` are the | +| | | coordinate intervals for | +| | | latitude and longitude, | +| | | respectively. | +| | | | +| | | Each interval is a tuple | +| | | having one of the forms: | +| | | | +| | | - ``(x,y)`` | +| | | - ``(x,y,indicator)`` | +| | | - ``(x,y,indicator,cycl | +| | | e)`` | +| | | - ``None`` | +| | | | +| | | where ``x`` and ``y`` | +| | | are coordinates | +| | | indicating the interval | +| | | ``[x,y)``, and: | +| | | | +| | | ``indicator`` is a | +| | | two-character string, | +| | | where the first | +| | | character is 'c' if the | +| | | interval is closed on | +| | | the left, 'o' if open, | +| | | and the second character | +| | | has the same meaning for | +| | | the right-hand point. | +| | | (Default: 'co'). | +| | | | +| | | If ``cycle`` is | +| | | specified, the axis is | +| | | treated as circular with | +| | | the given cycle value. | +| | | By default, if | +| | | ``grid.isCircular()`` is | +| | | true, the axis is | +| | | treated as circular with | +| | | a default value of | +| | | 360.0. | +| | | | +| | | An interval of ``None`` | +| | | returns the full index | +| | | interval of the axis. | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges.Note: | +| | | The result grid is not | +| | | associated with any file | +| | | or dataset. | ++--------------------------+--------------------------+--------------------------+ +| Transient-CurveGrid | ``toCurveGrid(gridid=Non | Convert to a curvilinear | +| | e)`` | grid. If the grid is | +| | | already curvilinear, a | +| | | copy of the grid object | +| | | is returned. ``gridid`` | +| | | is the string identifier | +| | | of the resulting | +| | | curvilinear grid object. | +| | | If unspecified, the grid | +| | | ID is copied. **Note:** | +| | | This method does not | +| | | apply to generic grids. | ++--------------------------+--------------------------+--------------------------+ +| Transient-GenericGrid | ``toGenericGrid(gridid=N | Convert to a generic | +| | one)`` | grid. If the grid is | +| | | already generic, a copy | +| | | of the grid is returned. | +| | | ``gridid`` is the string | +| | | identifier of the | +| | | resulting curvilinear | +| | | grid object. If | +| | | unspecified, the grid ID | +| | | is copied. | ++--------------------------+--------------------------+--------------------------+ + + +Table 2.32 RectGrid Methods, additional to HorizontalGrid + Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Description | ++==========================+==========================+==========================+ +| String | ``getOrder()`` | Get the grid ordering, | +| | | either "yx" if latitude | +| | | is the first axis, or | +| | | "xy" if longitude is the | +| | | first axis. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getType()`` | Get the grid type, | +| | | either "gaussian", | +| | | "uniform", "equalarea", | +| | | or "generic". | ++--------------------------+--------------------------+--------------------------+ +| (Array,Array) | ``getWeights()`` | Get the normalized area | +| | | weight arrays, as a | +| | | tuple | +| | | ``(latWeights, lon | +| | | Weights)``. | +| | | It is assumed that the | +| | | latitude and longitude | +| | | axes are defined in | +| | | degrees. | +| | | | +| | | The latitude weights are | +| | | defined as: | +| | | | +| | | ``latWeights[i] = 0.5 * | +| | | abs(sin(latBounds[i+1]) | +| | | - sin(latBounds[i] | +| | | ))`` | +| | | | +| | | The longitude weights | +| | | are defined as: | +| | | | +| | | ``lonWeights[i] = abs(lo | +| | | nBounds[i+1] - lonBounds | +| | | [i])/360.0`` | +| | | | +| | | For a global grid, the | +| | | weight arrays are | +| | | normalized such that the | +| | | sum of the weights is | +| | | 1.0 | +| | | | +| | | **Example:** | +| | | | +| | | Generate the 2-D weights | +| | | array, such that | +| | | ``weights[i.j]`` is the | +| | | fractional area of grid | +| | | zone ``[i,j]``. | +| | | | +| | | :: | +| | | | +| | | from cdms import MV | +| | | latwts, lonwts = gri | +| | | d.getWeights() | +| | | weights = MV.outerpr | +| | | oduct(latwts, lonwts) | +| | | | +| | | Also see the function | +| | | ``area_weights`` in | +| | | module | +| | | ``pcmdi.weighting``. | ++--------------------------+--------------------------+--------------------------+ +| None | ``setType(gridtype)`` | Set the grid type. | +| | | ``gridtype`` is one of | +| | | "gaussian", "uniform", | +| | | "equalarea", or | +| | | "generic". | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``subGrid((latStart,latS | Create a new grid, with | +| | top),(lonStart,lonStop)) | latitude index range | +| | `` | [latStart : latStop] and | +| | | longitude index range | +| | | [lonStart : lonStop]. | +| | | Either index range can | +| | | also be specified as | +| | | None, indicating that | +| | | the entire range of the | +| | | latitude or longitude is | +| | | used. | +| | | | +| | | **Example:** | +| | | | +| | | This creates newgrid | +| | | corresponding to all | +| | | latitudes and index | +| | | range [lonStart:lonStop] | +| | | of oldgrid. | +| | | | +| | | ``newgrid = oldgrid.subG | +| | | rid(None, (lonStart, lon | +| | | Stop))`` | +| | | | +| | | If a mask is defined, | +| | | the subgrid also has a | +| | | mask corresponding to | +| | | the index ranges. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ +| RectGrid | ``transpose()`` | Create a new grid, with | +| | | axis order reversed. The | +| | | grid mask is also | +| | | transposed. | +| | | | +| | | **Note:** The result | +| | | grid is not associated | +| | | with any file or | +| | | dataset. | ++--------------------------+--------------------------+--------------------------+ + + +2.11 Variable +^^^^^^^^^^^^^ + +A Variable is a multidimensional data object, consisting of: + +- a multidimensional data array, possibly masked, +- a collection of attributes +- a domain, an ordered tuple of CoordinateAxis objects. + +A Variable which is contained in a Dataset or CdmsFile is called a +persistent variable. Setting a slice of a persistent Variable writes +data to the Dataset or file, and referencing a Variable slice reads data +from the Dataset. Variables may also be transient, not associated with a +Dataset or CdmsFile. + +Variables support arithmetic operations, including the basic Python +operators (+,,\*,/,\*\*, abs, and sqrt), as well as the operations +defined in the MV module. The result of an arithmetic operation is a +transient variable, that is, the axis information is transferred to the +result. + +The methods subRegion and subSlice return transient variables. In +addition, a transient variable may be created with the +cdms.createVariable method. The vcs and regrid module methods take +advantage of the attribute, domain, and mask information in a transient +variable. + + +Table 2.33 Variable Internal Attributes + ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Type | Name | Definition | ++=======================+======================+=============================================================================================================================+ +| Dictionary | ``attributes`` | External attribute dictionary. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``id`` | Variable identifier. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| String | ``name\_in\_file`` | The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the variable. | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +| Tuple | ``shape`` | The length of each axis of the variable | ++-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ + + +Table 2.34 Variable Constructors + ++--------------------------------------+--------------------------------------+ +| Constructor | Description | ++======================================+======================================+ +| ``Dataset.createVariable(String id, | Create a Variable in a Dataset. This | +| String datatype, List axes)`` | function is not yet implemented. | ++--------------------------------------+--------------------------------------+ +| ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | +| String datatype, List axesOr- | ``id`` is the name of the variable. | +| Grids)`` | ``datatype`` is the MA or Numeric | +| | typecode, for example, MA.Float. | +| | ``axesOrGrids`` is a list of Axis | +| | and/or Grid objects, on which the | +| | variable is defined. Specifying a | +| | rectilinear grid is equivalent to | +| | listing the grid latitude and | +| | longitude axes, in the order defined | +| | for the grid. \*\*Note:\*\* this | +| | argument can either be a list or a | +| | tuple. If the tuple form is used, | +| | and there is only one element, it | +| | must have a following comma, e.g.: | +| | ``(axisobj,)``. | ++--------------------------------------+--------------------------------------+ +| :: | Create a transient variable, not | +| | associated with a file or dataset. | +| cdms.createVariable(array, typec | ``array`` is the data values: a | +| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numeric | +| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MA | +| s=None,attributes=None, id=None) | typecode of the array. Defaults to | +| | the typecode of array. ``copy`` is | +| | an integer flag: if 1, the variable | +| | is created with a copy of the array, | +| | if 0 the variable data is shared | +| | with array. ``savespace`` is an | +| | integer flag: if set to 1, internal | +| | Numeric operations will attempt to | +| | avoid silent upcasting. ``mask`` is | +| | an array of integers with value 0 or | +| | 1, having the same shape as array. | +| | array elements with a corresponding | +| | mask value of 1 are considered | +| | invalid, and are not used for | +| | subsequent Numeric operations. The | +| | default mask is obtained from array | +| | if present, otherwise is None. | +| | ``fill_value`` is the missing value | +| | flag. The default is obtained from | +| | array if possible, otherwise is set | +| | to 1.0e20 for floating point | +| | variables, 0 for integer-valued | +| | variables. ``grid`` is a rectilinear | +| | grid object. ``axes`` is a tuple of | +| | axis objects. By default the axes | +| | are obtained from array if present. | +| | Otherwise for a dimension of length | +| | n, the default axis has values [0., | +| | 1., ..., double(n)]. ``attributes`` | +| | is a dictionary of attribute values. | +| | The dictionary keys must be strings. | +| | By default the dictionary is | +| | obtained from array if present, | +| | otherwise is empty. ``id`` is the | +| | string identifier of the variable. | +| | By default the id is obtained from | +| | array if possible, otherwise is set | +| | to 'variable\_n' for some integer n. | ++--------------------------------------+--------------------------------------+ + + + +Table 2.35 Variable Methods + ++--------------------------+--------------------------+--------------------------+ +| Type | Method | Definition | ++==========================+==========================+==========================+ +| Variable | ``tvar = var[ i:j, m:n]` | Read a slice of data | +| | ` | from the file or | +| | | dataset, resulting in a | +| | | transient variable. | +| | | Singleton dimensions are | +| | | 'squeezed' out. Data is | +| | | returned in the physical | +| | | ordering defined in the | +| | | dataset. The forms of | +| | | the slice operator are | +| | | listed in Table 2.36 on | +| | | page 102. | ++--------------------------+--------------------------+--------------------------+ +| None | ``var[ i:j, m:n] = array | Write a slice of data to | +| | `` | the external dataset. | +| | | The forms of the slice | +| | | operator are listed in | +| | | Table 2.21 on page 32. | +| | | (Variables in CdmsFiles | +| | | only) | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``tvar = var(selector)`` | Calling a variable as a | +| | | function reads the | +| | | region of data defined | +| | | by the selector. The | +| | | result is a transient | +| | | variable, unless raw=1 | +| | | keyword is specified. | +| | | See "Selectors" on page | +| | | 103. | ++--------------------------+--------------------------+--------------------------+ +| None | ``assignValue(Array ar)` | Write the entire data | +| | ` | array. Equivalent to | +| | | ``var[:] = ar``. | +| | | (Variables in CdmsFiles | +| | | only). | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``astype(typecode)`` | Cast the variable to a | +| | | new datatype. Typecodes | +| | | are as for MV, MA, and | +| | | Numeric modules. | ++--------------------------+--------------------------+--------------------------+ +| Variable | ``clone(copyData=1)`` | Return a copy of a | +| | | transient variable. | +| | | | +| | | If copyData is 1 (the | +| | | default) the variable | +| | | data is copied as well. | +| | | If copyData is 0, the | +| | | result transient | +| | | variable shares the | +| | | original transient | +| | | variables data array. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | :: | Return a lat/level | +| | | vertical cross-section | +| | crossSectionRegrid(n | regridded to a new set | +| | ewLevel, newLatitude, me | of latitudes newLatitude | +| | thod="log", missing=None | and levels newLevel. The | +| | , order=None) | variable should be a | +| | | function of latitude, | +| | | level, and (optionally) | +| | | time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``newLatitude`` is an | +| | | axis of the result | +| | | latitudes. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzy" or | +| | | "zy". The default is | +| | | ``var.getOrder()``. | +| | | | +| | | *See also:* ``regrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getAxis(n)`` | Get the n-th axis. | +| | | | +| | | ``n`` is an integer. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisIds()`` | Get a list of axis | +| | | identifiers. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``getAxisIndex(axis_spec | Return the index of the | +| | )`` | axis specificed by | +| | | axis\_spec. Return -1 if | +| | | no match. | +| | | | +| | | ``axis_spec`` is a | +| | | specification as defined | +| | | for getAxisList | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisList(axes=None, | Get an ordered list of | +| | omit=None, order=None)` | axis objects in the | +| | ` | domain of the variable. | +| | | | +| | | If ``axes`` is not | +| | | ``None``, include only | +| | | certain axes. Otherwise | +| | | axes is a list of | +| | | specifications as | +| | | described below. Axes | +| | | are returned in the | +| | | order specified unless | +| | | the order keyword is | +| | | given. | +| | | | +| | | If ``omit`` is not | +| | | ``None``, omit those | +| | | specified by an integer | +| | | dimension number. | +| | | Otherwise omit is a list | +| | | of specifications as | +| | | described below. | +| | | | +| | | ``order`` is an optional | +| | | string determining the | +| | | output order. | +| | | | +| | | Specifications for the | +| | | axes or omit keywords | +| | | are a list, each element | +| | | having one of the | +| | | following forms: | +| | | | +| | | - an integer dimension | +| | | index, starting at 0. | +| | | - a string representing | +| | | an axis id or one of | +| | | the strings 'time', | +| | | 'latitude', 'lat', | +| | | 'longitude', 'lon', | +| | | 'lev' or 'level'. | +| | | - a function that takes | +| | | an axis as an | +| | | argument and returns | +| | | a value. If the value | +| | | returned is true, the | +| | | axis matches. | +| | | - an axis object; will | +| | | match if it is the | +| | | same object as axis. | +| | | | +| | | ``order`` can be a | +| | | string containing the | +| | | characters t,x,y,z, or | +| | | -. If a dash ('-') is | +| | | given, any elements of | +| | | the result not chosen | +| | | otherwise are filled in | +| | | from left to right with | +| | | remaining candidates. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getAxisListIndex(axes= | Return a list of indices | +| | None, omit=None, order=N | of axis objects. | +| | one)`` | Arguments are as for | +| | | getAxisList. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getDomain()`` | Get the domain. Each | +| | | element of the list is | +| | | itself a tuple of the | +| | | form | +| | | ``(axis,start,length,tru | +| | | e_length)`` | +| | | where axis is an axis | +| | | object, start is the | +| | | start index of the | +| | | domain relative to the | +| | | axis object, length is | +| | | the length of the axis, | +| | | and true\_length is the | +| | | actual number of | +| | | (defined) points in the | +| | | domain. *See also:* | +| | | ``getAxisList``. | ++--------------------------+--------------------------+--------------------------+ +| Horizontal-Grid | ``getGrid()`` | Return the associated | +| | | grid, or ``None`` if the | +| | | variable is not gridded. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLatitude()`` | Get the latitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLevel()`` | Get the vertical level | +| | | axis, or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getLongitude()`` | Get the longitude axis, | +| | | or ``None`` if not | +| | | found. | ++--------------------------+--------------------------+--------------------------+ +| Various | ``getMissing()`` | Get the missing data | +| | | value, or ``None`` if | +| | | not found. | ++--------------------------+--------------------------+--------------------------+ +| String | ``getOrder()`` | Get the order string of | +| | | a spatio-temporal | +| | | variable. The order | +| | | string specifies the | +| | | physical ordering of the | +| | | data. It is a string of | +| | | characters with length | +| | | equal to the rank of the | +| | | variable, indicating the | +| | | order of the variable's | +| | | time, level, latitude, | +| | | and/or longitude axes. | +| | | Each character is one | +| | | of: | +| | | | +| | | - 't': time | +| | | - 'z': vertical level | +| | | - 'y': latitude | +| | | - 'x': longitude | +| | | - '-': the axis is not | +| | | spatio-temporal. | +| | | | +| | | **Example:** | +| | | | +| | | A variable with ordering | +| | | "tzyx" is 4-dimensional, | +| | | where the ordering of | +| | | axes is (time, level, | +| | | latitude, longitude). | +| | | | +| | | **Note:** The order | +| | | string is of the form | +| | | required for the order | +| | | argument of a regridder | +| | | function. | ++--------------------------+--------------------------+--------------------------+ +| List | ``getPaths(*intervals)`` | Get the file paths | +| | | associated with the | +| | | index region specified | +| | | by intervals. | +| | | | +| | | ``intervals`` is a list | +| | | of scalars, 2-tuples | +| | | representing [i,j), | +| | | slices, and/or Ellipses. | +| | | If no ``argument(s)`` | +| | | are present, all file | +| | | paths associated with | +| | | the variable are | +| | | returned. | +| | | | +| | | Returns a list of tuples | +| | | of the form | +| | | (path,slicetuple), where | +| | | path is the path of a | +| | | file, and slicetuple is | +| | | itself a tuple of | +| | | slices, of the same | +| | | length as the rank of | +| | | the variable, | +| | | representing the portion | +| | | of the variable in the | +| | | file corresponding to | +| | | intervals. | +| | | | +| | | **Note:** This function | +| | | is not defined for | +| | | transient variables. | ++--------------------------+--------------------------+--------------------------+ +| Axis | ``getTime()`` | Get the time axis, or | +| | | ``None`` if not found. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``len(var)`` | The length of the first | +| | | dimension of the | +| | | variable. If the | +| | | variable is | +| | | zero-dimensional | +| | | (scalar), a length of 0 | +| | | is returned. | +| | | | +| | | **Note:** ``size()`` | +| | | returns the total number | +| | | of elements. | ++--------------------------+--------------------------+--------------------------+ +| Transient Variable | ``pressureRegrid (newLev | Return the variable | +| | el, method="log", missin | regridded to a new set | +| | g=None, order=None | of pressure levels | +| | )`` | newLevel. The variable | +| | | must be a function of | +| | | latitude, longitude, | +| | | pressure level, and | +| | | (optionally) time. | +| | | | +| | | ``newLevel`` is an axis | +| | | of the result pressure | +| | | levels. | +| | | | +| | | ``method`` is optional, | +| | | either "log" to | +| | | interpolate in the log | +| | | of pressure (default), | +| | | or "linear" for linear | +| | | interpolation. | +| | | | +| | | ``missing`` is a missing | +| | | data value. The default | +| | | is ``var.getMissing()`` | +| | | | +| | | ``order`` is an order | +| | | string such as "tzyx" or | +| | | "zyx". The default is | +| | | ``var.getOrder()`` | +| | | | +| | | See also: ``regrid``, | +| | | ``crossSectionRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``rank()`` | The number of dimensions | +| | | of the variable. | ++--------------------------+--------------------------+--------------------------+ +| Transient | :: | Return the variable | +| | | regridded to the | +| | regrid (togrid, miss | horizontal grid togrid. | +| | ing=None, order=None, Va | | +| | riable mask=None) | ``missing`` is a Float | +| | | specifying the missing | +| | | data value. The default | +| | | is 1.0e20. | +| | | | +| | | ``order`` is a string | +| | | indicating the order of | +| | | dimensions of the array. | +| | | It has the form returned | +| | | from | +| | | ``variable.getOrder()``. | +| | | For example, the string | +| | | "tzyx" indicates that | +| | | the dimension order of | +| | | array is (time, level, | +| | | latitude, longitude). If | +| | | unspecified, the | +| | | function assumes that | +| | | the last two dimensions | +| | | of array match the input | +| | | grid. | +| | | | +| | | ``mask`` is a Numeric | +| | | array, of datatype | +| | | Integer or Float, | +| | | consisting of ones and | +| | | zeros. A value of 0 or | +| | | 0.0 indicates that the | +| | | corresponding data value | +| | | is to be ignored for | +| | | purposes of regridding. | +| | | If mask is | +| | | two-dimensional of the | +| | | same shape as the input | +| | | grid, it overrides the | +| | | mask of the input grid. | +| | | If the mask has more | +| | | than two dimensions, it | +| | | must have the same shape | +| | | as array. In this case, | +| | | the missing data value | +| | | is also ignored. Such an | +| | | n-dimensional mask is | +| | | useful if the pattern of | +| | | missing data varies with | +| | | level (e.g., ocean data) | +| | | or time. Note: If | +| | | neither missing or mask | +| | | is set, the default mask | +| | | is obtained from the | +| | | mask of the array if | +| | | any. | +| | | | +| | | See also: | +| | | ``crossSectionRegrid``, | +| | | ``pressureRegrid``. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxis(n, axis)`` | Set the n-th axis | +| | | (0-origin index) of to a | +| | | copy of axis. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setAxisList(axislist)` | Set all axes of the | +| | ` | variable. axislist is a | +| | | list of axis objects. | ++--------------------------+--------------------------+--------------------------+ +| ``None`` | ``setMissing(value)`` | Set the missing value. | ++--------------------------+--------------------------+--------------------------+ +| Integer | ``size()`` | Number of elements of | +| | | the variable. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a coordinate region | +| | | of data, returning a | +| | subRegion(*region, t | transient variable. A | +| | ime=None, level=None, la | region is a | +| | titude=None, longitude=N | hyperrectangle in | +| | one, squeeze=0, raw=0) | coordinate space. | +| | | | +| | | ``region`` is an | +| | | argument list, each item | +| | | of which specifies an | +| | | interval of a coordinate | +| | | axis. The intervals are | +| | | listed in the order of | +| | | the variable axes. If | +| | | trailing dimensions are | +| | | omitted, all values of | +| | | those dimensions are | +| | | retrieved. If an axis is | +| | | circular | +| | | (axis.isCircular() is | +| | | true) or cycle is | +| | | specified (see below), | +| | | then data will be read | +| | | with wraparound in that | +| | | dimension. Only one axis | +| | | may be read with | +| | | wraparound. A coordinate | +| | | interval has one of the | +| | | forms listed in Table | +| | | 2.37 on page 102. Also | +| | | see | +| | | ``axis.mapIntervalExt``. | +| | | | +| | | The optional keyword | +| | | arguments ``time``, | +| | | ``level``, ``latitude``, | +| | | and ``longitude`` may | +| | | also be used to specify | +| | | the dimension for which | +| | | the interval applies. | +| | | This is particularly | +| | | useful if the order of | +| | | dimensions is not known | +| | | in advance. An exception | +| | | is raised if a keyword | +| | | argument conflicts with | +| | | a positional region | +| | | argument. | +| | | | +| | | The optional keyword | +| | | argument ``squeeze`` | +| | | determines whether or | +| | | not the shape of the | +| | | returned array contains | +| | | dimensions whose length | +| | | is 1; by default this | +| | | argument is 0, and such | +| | | dimensions are not | +| | | 'squeezed out'. | +| | | | +| | | The optional keyword | +| | | argument ``raw`` | +| | | specifies whether the | +| | | return object is a | +| | | variable or a masked | +| | | array. By default, a | +| | | transient variable is | +| | | returned, having the | +| | | axes and attributes | +| | | corresponding to2,3 the | +| | | region read. If raw=1, | +| | | an MA masked array is | +| | | returned, equivalent to | +| | | the transient variable | +| | | without the axis and | +| | | attribute information. | ++--------------------------+--------------------------+--------------------------+ +| Variable | :: | Read a slice of data, | +| | | returning a transient | +| | subSlice(*specs, tim | variable. This is a | +| | e=None, level=None, lati | functional form of the | +| | tude=None, longitude=Non | slice operator [] with | +| | e, squeeze=0, raw=0) | the squeeze option | +| | | turned off. | +| | | | +| | | ``specs`` is an argument | +| | | list, each element of | +| | | which specifies a slice | +| | | of the corresponding | +| | | dimension. There can be | +| | | zero or more positional | +| | | arguments, each of the | +| | | form: | +| | | | +| | | - a single integer n, | +| | | meaning | +| | | ``slice(n, n+1)`` | +| | | - an instance of the | +| | | slice class | +| | | - a tuple, which will | +| | | be used as arguments | +| | | to create a slice | +| | | - ':', which means a | +| | | slice covering that | +| | | entire dimension | +| | | - Ellipsis (...), which | +| | | means to fill the | +| | | slice list with ':' | +| | | leaving only enough | +| | | room at the end for | +| | | the remaining | +| | | positional arguments | +| | | - a Python slice | +| | | object, of the form | +| | | ``slice(i,j,k)`` | +| | | | +| | | If there are fewer | +| | | slices than | +| | | corresponding | +| | | dimensions, all values | +| | | of the trailing | +| | | dimensions are read. | +| | | | +| | | The keyword arguments | +| | | are defined as in | +| | | subRegion. | +| | | | +| | | There must be no | +| | | conflict between the | +| | | positional arguments and | +| | | the keywords. | +| | | | +| | | In ``(a)-(c)`` and (f), | +| | | negative numbers are | +| | | treated as offsets from | +| | | the end of that | +| | | dimension, as in normal | +| | | Python indexing. | ++--------------------------+--------------------------+--------------------------+ +| String | ``typecode()`` | The Numeric datatype | +| | | identifier. | ++--------------------------+--------------------------+--------------------------+ + +**Example:** Get a region of data. + +Variable ta is a function of (time, latitude, longitude). Read data +corresponding to all times, latitudes -45.0 up to but not +including+45.0, longitudes 0.0 through and including longitude 180.0: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) + +.. raw:: html + +
+ +or equivalently: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, + 180.0) + +.. raw:: html + +
+ +Read all data for March, 1980: + +.. raw:: html + +
+ +:: + + data = ta.subRegion(time=('1980-3','1980-4','co')) + +.. raw:: html + +
+ + + +Table 2.36 Variable Slice Operators + ++-------------------+---------------------------------------------------------------+ +| Operator | Description | ++===================+===============================================================+ +| ``[i]`` | The ith element, zero-origin indexing. | ++-------------------+---------------------------------------------------------------+ +| ``[i:j]`` | The ith element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[i:]`` | The ith element through the end | ++-------------------+---------------------------------------------------------------+ +| ``[:j]`` | The beginning element through, but not including, element j | ++-------------------+---------------------------------------------------------------+ +| ``[:]`` | The entire array | ++-------------------+---------------------------------------------------------------+ +| ``[i:j:k]`` | Every kth element | ++-------------------+---------------------------------------------------------------+ +| ``[i:j, m:n]`` | Multidimensional slice | ++-------------------+---------------------------------------------------------------+ +| ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | ++-------------------+---------------------------------------------------------------+ +| ``[-1]`` | Negative indices ‘wrap around’. -1 is the last element | ++-------------------+---------------------------------------------------------------+ + + + +Table 2.37 Index and Coordinate Intervals + ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| Interval Definition | Example Interval Definition | Example | ++========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ +| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | +| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | +| | | ``'1980-1-3'`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | +| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | +| | | ``slice(,,-1)`` reverses the direction of the axis. | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``':'`` | all axis values of one dimension |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +| ``Ellipsis`` | all values of all intermediate axes |   | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ + + + +2.11.1 Selectors + +A selector is a specification of a region of data to be selected from a +variable. For example, the statement + +.. raw:: html + +
+ +:: + + x = v(time='1979-1-1', level=(1000.0,100.0)) + +.. raw:: html + +
+ +means ‘select the values of variable v for time ‘1979-1-1’ and levels +1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are +generally used to represent regions of space and time. + +The form for using a selector is + +.. raw:: html + +
+ +:: + + result = v(s) + +.. raw:: html + +
+ +where v is a variable and s is the selector. An equivalent form is + +.. raw:: html + +
+ +:: + + result = f('varid', s) + +.. raw:: html + +
+ +where f is a file or dataset, and ‘varid’ is the string ID of a +variable. + +A selector consists of a list of selector components. For example, the +selector + +.. raw:: html + +
+ +:: + + time='1979-1-1', level=(1000.0,100.0) + +.. raw:: html + +
+ +has two components: time=’1979-1-1’, and level=(1000.0,100.0). This +illustrates that selector components can be defined with keywords, using +the form: + +.. raw:: html + +
+ +:: + + keyword=value + +.. raw:: html + +
+ +Note that for the keywords time, level, latitude, and longitude, the +selector can be used with any variable. If the corresponding axis is not +found, the selector component is ignored. This is very useful for +writing general purpose scripts. The required keyword overrides this +behavior. These keywords take values that are coordinate ranges or index +ranges as defined in Table 2.37 on page 102. + +The following keywords are available: Another form of selector +components is the positional form, where the component order corresponds +to the axis order of a variable. For example: + + + +Table 2.38 Selector keywords + ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| Keyword | Description | Value | ++=================+======================================================================+============================================================================+ +| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``grid`` | Regrid the result to the grid. | Grid object | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``raw`` | Return a masked array (MA.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ +| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | ++-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ + +Another form of selector components is the positional form, where the +component order corresponds to the axis order of a variable. For +example: + +.. raw:: html + +
+ +:: + + x9 = hus(('1979-1-1','1979-2-1'),1000.0) + +.. raw:: html + +
+ +reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and +coordinate value 1000.0 of the second axis. Non-keyword arguments of the +form(s) listed in Table 2.37 on page 102 are treated as positional. Such +selectors are more concise, but not as general or flexible as the other +types described in this section. + +Selectors are objects in their own right. This means that a selector can +be defined and reused, independent of a particular variable. Selectors +are constructed using the cdms.selectors.Selector class. The constructor +takes an argument list of selector components. For example: + +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x1 = v1(sel) + x2 = v2(sel) + +.. raw:: html + +
+ +For convenience CDMS provides several predefined selectors, which can be +used directly or can be combined into more complex selectors. The +selectors time, level, latitude, longitude, and required are equivalent +to their keyword counterparts. For example: + +.. raw:: html + +
+ +:: + + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + +.. raw:: html + +
+ +and + +.. raw:: html + +
+ +:: + + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + +.. raw:: html + +
+ +are equivalent. Additionally, the predefined selectors +``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` +take arguments ``(startindex, stopindex[, stride])``: + +.. raw:: html + +
+ +:: + + from cdms import timeslice, levelslice + x = v(timeslice(0,2), levelslice(16,17)) + +.. raw:: html + +
+ +Finally, a collection of selectors is defined in module cdutil.region: + +.. raw:: html + +
+ +:: + + from cdutil.region import * + NH=NorthernHemisphere=domain(latitude=(0.,90.) + SH=SouthernHemisphere=domain(latitude=(-90.,0.)) + Tropics=domain(latitude=(-23.4,23.4)) + NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) + SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) + +.. raw:: html + +
+ +Selectors can be combined using the & operator, or by refining them in +the call: + +.. raw:: html + +
+ +:: + + from cdms.selectors import Selector + from cdms import level + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x1 = hus(sel3) + x2 = hus(sel2, level=1000.0) + +.. raw:: html + +
+ + + +2.11.2 Selector examples + +CDMS provides a variety of ways to select or slice data. In the +following examples, variable hus is contained in file sample.nc, and is +a function of (time, level, latitude, longitude). Time values are +monthly starting at 1979-1-1. There are 17 levels, the last level being +1000.0. The name of the vertical level axis is ‘plev’. All the examples +select the first two times and the last level. The last two examples +remove the singleton level dimension from the result array. + +.. raw:: html + +
+ +:: + + import cdms + f = cdms.open('sample.nc') + hus = f.variables['hus'] + + # Keyword selection + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + + # Interval indicator (see mapIntervalExt) + x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) + + # Axis ID (plev) as a keyword + x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + + # Positional + x9 = hus(('1979-1-1','1979-2-1'),1000.0) + + # Predefined selectors + from cdms import time, level + x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + + from cdms import timeslice, levelslice + x = hus(timeslice(0,2), levelslice(16,17)) + + # Call file as a function + x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + + # Python slices + x = hus(time=slice(0,2), level=slice(16,17)) + + # Selector objects + from cdms.selectors import Selector + sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + x = hus(sel) + + sel2 = Selector(time=('1979-1-1','1979-2-1')) + sel3 = sel2 & level(1000.0) + x = hus(sel3) + x = hus(sel2, level=1000.0) + + # Squeeze singleton dimension (level) + x = hus[0:2,16] + x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) + + f.close() + +.. raw:: html + +
+ + + +2.12 Examples +^^^^^^^^^^^^^ + + +2.12.1 Example 1 +^^^^^^^^^^^^^^^^ + +In this example, two datasets are opened, containing surface air +temperature (‘tas’) and upper-air temperature (‘ta’) respectively. +Surface air temperature is a function of (time, latitude, longitude). +Upper-air temperature is a function of (time, level, latitude, +longitude). Time is assumed to have a relative representation in the +datasets (e.g., with units ‘months since basetime’). + +Data is extracted from both datasets for January of the first input year +through December of the second input year. For each time and level, +three quantities are calculated: slope, variance, and correlation. The +results are written to a netCDF file. For brevity, the functions +``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. + +.. raw:: html + +
+ +:: + + 1. import cdms + import MV + + # Calculate variance, slope, and correlation of + # surface air temperature with upper air temperature + # by level, and save to a netCDF file. 'pathTa' is the location of + # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + # Data is extracted from January of year1 through December of year2. + def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): + + # Open the files for ta and tas + fta = cdms.open(pathTa) + ftas = cdms.open(pathTas) + + 2. #Get upper air temperature + taObj = fta['ta'] + levs = taObj.getLevel() + + #Get the surface temperature for the closed interval [time1,time2] + tas = ftas('tas', time=(month1,month2,'cc')) + + # Allocate result arrays + newaxes = taObj.getAxisList(omit='time') + newshape = tuple([len(a) for a in newaxes]) + cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + + # Remove seasonal cycle from surface air temperature + tas = removeSeasonalCycle(tas) + + # For each level of air temperature, remove seasonal cycle + # from upper air temperature, and calculate statistics + 5. for ilev in range(len(levs)): + + ta = taObj(time=(month1,month2,'cc'), \ + level=slice(ilev, ilev+1), squeeze=1) + ta = removeSeasonalCycle(ta) + cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + + # Write slope, correlation, and variance variables + 6. f = cdms.open('CC_B_V_ALL.nc','w') + f.title = filtered + f.write(b) + f.write(cc) + f.write(v) + f.close() + + 7. if __name__=='__main__': + pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' + pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' + # Process Jan80 through Dec81 + ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') + +.. raw:: html + +
+ +**Notes:** + +#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements + arithmetic functions. +#. ``taObj`` is a file (persistent) variable. At this point, no data has + actually been read. This happens when the file variable is sliced, or + when the subRegion function is called. levs is an axis. +#. Calling the file like a function reads data for the given variable + and time range. Note that month1 and month2 are time strings. +#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are + transient variables, not associated with a file. The assigned names + are used when the variables are written. +#. Another way to read data is to call the variable as a function. The + squeeze option removes singleton axes, in this case the level axis. +#. Write the data. Axis information is written automatically. +#. This is the main routine of the script. ``pathTa`` and ``pathTas`` + pathnames. Data is processed from January 1980 through December 1981. + + + +2.12.2 Example 2 +^^^^^^^^^^^^^^^^ + +In the next example, the pointwise variance of a variable over time is +calculated, for all times in a dataset. The name of the dataset and +variable are entered, then the variance is calculated and plotted via +the vcs module. + +.. raw:: html + +
+ +:: + + #!/usr/bin/env python + # + # Calculates gridpoint total variance + # from an array of interest + # + + import cdms + from MV import * + + # Wait for return in an interactive window + + def pause(): + print Hit return to continue: , + line = sys.stdin.readline() + + 1. # Calculate pointwise variance of variable over time + # Returns the variance and the number of points + # for which the data is defined, for each grid point + def calcVar(x): + # Check that the first axis is a time axis + firstaxis = x.getAxis(0) + if not firstaxis.isTime(): + raise 'First axis is not time, variable:', x.id + + n = count(x,0) + sumxx = sum(x*x) + sumx = sum(x) + variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + + return variance, n + + if __name__=='__main__': + import vcs, sys + + print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + path = string.strip(sys.stdin.readline()) + if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + + 2. # Open the dataset + dataset = cdms.open(path) + + # Select a variable from the dataset + print 'Variables in file:',path + varnames = dataset.variables.keys() + varnames.sort() + for varname in varnames: + + var = dataset.variables[varname] + if hasattr(var,'long_name'): + long_name = var.long_name + elif hasattr(var,'title'): + long_name = var.title + else: + long_name = '?' + + print '%-10s: %s'%(varname,long_name) + print 'Select a variable: ', + 3. varname = string.strip(sys.stdin.readline()) + var = dataset(varname) + dataset.close() + + # Calculate variance, count, and set attributes + variance,n = calcVar(var) + variance.id = 'variance_%s'%var.id + n.id = 'count_%s'%var.id + if hasattr(var,'units'): + variance.units = '(%s)^2'%var.units + + # Plot variance + w=vcs.init() + 4. w.plot(variance) + pause() + w.clear() + w.plot(n) + pause() + w.clear() + +.. raw:: html + +
+ +The result of running this script is as follows: + +.. raw:: html + +
+ +:: + + % calcVar.py + Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: + + Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml + albt : Albedo TOA [%] + albtcs : Albedo TOA clear sky [%] + rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] + rlut : LW radiation TOA (OLR) [W/m^2] + rlutcs : LW radiation upward TOA clear sky [W/m^2] + rscrft : SW Cloud Radiation Forcing TOA [W/m^2] + rsdt : SW radiation downward TOA [W/m^2] + rsut : SW radiation upward TOA [W/m^2] + rsutcs : SW radiation upward TOA clear sky [W/m^2] + Select a variable: albt + + + + Hit return to continue: + + + +.. raw:: html + +
+ +**Notes:** + +#. n = count(x, 0) returns the pointwise number of valid values, summing + across axis 0, the first axis. count is an MV function. +#. dataset is a Dataset or CdmsFile object, depending on whether a .xml + or .nc pathname is entered. dataset.variables is a dictionary mapping + variable name to file variable. +#. var is a transient variable. +#. Plot the variance and count variables. Spatial longitude and latitude + information are carried with the computations, so the continents are + plotted correctly. + + + + diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst new file mode 100644 index 00000000..18a9b365 --- /dev/null +++ b/docs/source/manual/cdms_3.rst @@ -0,0 +1,235 @@ +CHAPTER 3 cdtime Module +----------------------- + +3.1 Time types +^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + +The ``cdtime`` module implements the CDMS time types, methods, and +calendars. These are made available with the command + +.. doctest:: + + >>> import cdtime + +Two time types are available: relative time and component time. Relative +time is time relative to a fixed base time. It consists of: + +- a units string, of the form ‘units since basetime’, and +- a floating-point value + +For example, the time “28.0 days since 1996-1-1” has value=28.0, and +units=’days since 1996-1-1’ + +Component time consists of the integer fields year, month, day, hour, +minute, and the floating-point field second. A sample component time is +``1996-2-28 12:10:30.0`` + +The ``cdtime`` module contains functions for converting between these +forms, based on the common calendars used in climate simulation. Basic +arithmetic and comparison operators are also available. + +3.2 Calendars +^^^^^^^^^^^^^ + +A calendar specifies the number of days in each month, for a given year. +cdtime supports these calendars: + +- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap + years, except century years not evenly divisible by 400. This is + sometimes called the proleptic Gregorian calendar, meaning that the + algorithm for leap years applies for all years. +- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates + before 158210-15 are encoded with the Julian calendar, otherwise are + encoded with the Gregorian calendar. The day immediately following + 1582-10-4 is 1582-10-15. This is the default calendar. +- ``cdtime.JulianCalendar``: years evenly divisible by four are leap + years, +- ``cdtime.NoLeapCalendar``: all years have 365 days, +- ``cdtime.Calendar360``: all months have 30 days. + +Several ``cdtime`` functions have an optional calendar argument. The +default calendar is the ``MixedCalendar``. The default calendar may be +changed with the command: + + +``cdtime.DefaultCalendar = newCalendar`` + +3.3 Time Constructors +^^^^^^^^^^^^^^^^^^^^^ + +The following table describes the methods for creating time types. + + +.. csv-table:: Time Constructors + :header: "Type", "Constructor", "Defintion" + :widths: 10, 40, 80 + + "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." + ,, "``value`` is an integer or floating point value." + ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" + ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + + "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." + ,,"``year`` is an integer." + ,,"``month`` is an integer in the range 1 .. 12" + ,,"``day`` is an integer in the range 1 .. 31" + ,,"``hour`` is an integer in the range 0 .. 23" + ,,"``minute`` is an integer in the range 0 .. 59" + ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + + +3.4 Relative Time +^^^^^^^^^^^^^^^^^ + +A relative time type has two members, value and units. Both can be set. + +Table 3.2 Relative Time Members +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++----------+---------+-------------------------------------------------------+ +| Type | Name | Summary | ++==========+=========+=======================================================+ +| Float | value | Number of units | ++----------+---------+-------------------------------------------------------+ +| String | units | Relative units, of the form “unit(s) since basetime | ++----------+---------+-------------------------------------------------------+ + +3.5 Component Time +^^^^^^^^^^^^^^^^^^ + +A component time type has six members, all of which are settable. + +.. csv-table:: Table 3.3 Component Time + :header: "Type", "Name", "Summary" + :widths: 15, 15, 50 + + "Integer", "year", "Year value" + "Integer", "month", "Month, in the range 1..12" + "Integer", "day", "Day of month, in the range 1 .. 31" + "Integer", "hour", "Hour, in the range 0 .. 23" + "Integer", "minute", "Minute, in the range 0 .. 59" + "Float", "second", "Seconds, in the range 0.0 .. 60.0" + +3.6 Time Methods +^^^^^^^^^^^^^^^^ + +The following methods apply both to relative and component times. + +.. csv-table:: Table 3.4 Time Methods + :header: "Type", "Method", "Definition" + :widths: 20, 75, 80 + + "Comptime or Reltime", "``t.add(value, intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" + ,, "``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." + ,, "``t2`` is the time to compare." + ,, "``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." + ,, "``value`` is the Float number of interval units." + ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" + ,, "``calendar`` is the calendar type. " + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." + ,, "``calendar`` is the calendar type." + "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." + + +3.7 Examples +^^^^^^^^^^^^ +.. doctest:: + + >>> from cdtime import * + >>> c = comptime(1996,2,28) + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.add(1,Day) + 29.000000 days since 1996-1-1 + >>> print c.add(36,Hours) + 1996-2-29 12:0:0.0 + + +**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising. + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(1,Month) + 1979-9-1 0:0:0.0 + + +In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months: + +.. doctest:: + + >>> c = comptime(1979,8,31) + >>> c.add(2,Years) + 1981-8-1 0:0:0.0 + +Compare time values. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print c.cmp(r) + 1 + +.. >>> print r.cmp(c) +.. -1 +.. >>> print r.cmp(r) +.. 1 + +Subtract an interval of time. + +.. doctest:: + + >>> from cdtime import * + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> c = comptime(1996,2,28) + >>> print r.sub(10,Days) + 18.000000 days since 1996-1-1 + >>> print c.sub(30,Days) + 1996-1-29 0:0:0.0 + + +For intervals of years or months, see the **note** under add() in the example above. + +Convert to component time. + +.. doctest:: + + >>> r = cdtime.reltime(28,"days since 1996-1-1") + >>> r.tocomp() + 1996-1-29 0:0:0.0 + + +Convert to relative time. + +.. doctest:: + + >>> c = comptime(1996,2,28) + >>> print c.torel("days since 1996-1-1") + 58.000000 days since 1996-1-1 + >>> r = reltime(28,"days since 1996-1-1") + >>> print r.torel("days since 1995") + 393.000000 days since 1995 + >>> print r.torel("days since 1995").value + 393.0 + diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst new file mode 100644 index 00000000..011d345a --- /dev/null +++ b/docs/source/manual/cdms_4.rst @@ -0,0 +1,686 @@ +CHAPTER 4 Regridding Data +------------------------- + +4.1 Overview +^^^^^^^^^^^^ + +CDMS provides several methods for interpolating gridded data: + +- from one rectangular, lat-lon grid to another (CDMS regridder) +- between any two lat-lon grids (SCRIP regridder) +- from one set of pressure levels to another +- from one vertical (lat/level) cross-section to another vertical + cross-section. + +4.1.1 CDMS horizontal regridr +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + +The simplest method to regrid a variable from one rectangular, lat/lon +grid to another is to use the regrid function defined for variables. +This function takes the target grid as an argument, and returns the +variable regridded to the target grid: + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> import cdms2 + >>> import cdat_info + >>> f1=cdms2.open("clt.nc") + >>> f2=cdms2.open("geos5-sample.nc") + >>> clt=f1('clt') # Read the data + >>> clt.shape + (120, 46, 72) + >>> ozone=f2['ozone'] # Get the file variable (no data read) + >>> outgrid = ozone.getGrid() # Get the target grid + >>> cltnew = clt.regrid(outgrid) + >>> cltnew.shape + (120, 181, 360) + >>> outgrid.shape + (181, 360) + + +A somewhat more efficient method is to create a regridder function. This +has the advantage that the mapping is created only once and can be used +for multiple arrays. Also, this method can be used with data in the form +of an MA.MaskedArray. The steps in this process are: + +#. Given an input grid and output grid, generate a regridder function. +#. Call the regridder function on a Numeric array, resulting in an array + defined on the output grid. The regridder function can be called with + any array or variable defined on the input grid. + +The following example illustrates this process. The regridder function +is generated at line 9, and the regridding is performed at line 10: + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> import cdms2 + >>> from regrid2 import Regridder + >>> f = cdms2.open("clt.nc") + >>> cltf = f['clt'] + >>> ingrid = cltf.getGrid() + >>> g = cdms2.open('geos5-sample.nc') + >>> outgrid = g['ozone'].getGrid() + >>> regridfunc = Regridder(ingrid, outgrid) + >>> cltnew = regridfunc(cltf) + >>> f.close() + >>> g.close() + + +Notes +~~~~~ + +**Line #3** Makes the CDMS module available. + +**Line #4** Makes the Regridder class available from the regrid module. + +**Line #5** Opens the input dataset. + +**Line #6** Gets the variable object named ‘clt’. No data is read. + +**Line #7** Gets the input grid. + +**Line #8** Opens a dataset to retrieve the output grid. + +**Line #9** The output grid is the grid associated with the variable named ‘ozone’ in dataset g. Just the grid is retrieved, not the data. + +**Line #10** Generates a regridder function regridfunc. + +**Line #11** Reads all data for variable cltf, and calls the regridder +function on that data, resulting in a transient variable cltnew. + +4.1.2 SCRIP horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To interpolate between grids where one or both grids is non-rectangular, +CDMS provides an interface to the SCRIP regridder package developed at +Los Alamos National Laboratory (http://oceans11.lanl.gov/trac/SCRIP). + +Figure 3 illustrates the process: + +#. Obtain or generate the source and target grids in SCRIP netCDF + format. A CDMS grid can be written to a netCDF file, in SCRIP format, + using the write-ScripGrid method. +#. Edit the input namelist file scrip\_in to reference the grids and + select the method of interpolation, either conservative, bilinear, + bicubic, or distance-weighted. See the SCRIP documentation for + detailed instructions. +#. Run the scrip executable to generate a remapping file containing the + transformation coefficients. +#. CDMS, open the remapping file and create a regridder function with + the readRegridder method. +#. Call the regridder function on the input variable, defined on the + source grid. The return value is the variable interpolated to the new + grid. Note that the variable may have more than two dimensions. Also + note that the input arguments to the regridder function depend on the + type of regridder. For example, the bicubic interpolation has + additional arguments for the gradients of the variable. + + +FIGURE 3. Regridding data with SCRIP +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Example:** + +Regrid data from a T42 to POP4/3 grid, using the first-order, +conservative interpolator. + +In this example: + +- The input grid is defined in remap\_grid\_T42.nc. +- The output grid is defined in remap\_grid\_POP43.nc. +- The input data is variable src\_array in file sampleT42Grid.nc. +- The file scrip\_in has contents: + +.. raw:: html + +
+ +:: + + &remap_inputs + num_maps = 1 + + grid1_file = 'remap_grid_T42.nc' + grid2_file = 'remap_grid_POP43.nc' + interp_file1 = 'rmp_T42_to_POP43_conserv.nc' + interp_file2 = 'rmp_POP43_to_T42_conserv.nc' + map1_name = 'T42 to POP43 Conservative Mapping' + map2_name = 'POP43 to T42 Conservative Mapping' + map_method = 'conservative' + normalize_opt = 'frac' + output_opt = 'scrip' + restrict_type = 'latitude' + num_srch_bins = 90 + luse_grid1_area = .false. + luse_grid2_area = .false. + +.. raw:: html + +
+ +``num_maps`` specifies the number of mappings generated, either 1 or 2. +For a single mapping, ``grid1_file`` and ``grid2_file`` are the source +and target grid definitions, respectively. The ``map_method`` specifies +the type of interpolation, either ‘conservative’, ‘bilinear’, ‘bicubic’, +or ‘distwgt’ (distanceweighted). The remaining parameters are described +in the SCRIP documentation. + +Once the grids and input file are defined, run the scrip executable to +generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ + +.. raw:: html + +
+ +:: + + % scrip + Using latitude bins to restrict search. + Computing remappings between: + T42 Gaussian Grid + and + POP 4/3 Displaced-Pole T grid + grid1 sweep + grid2 sweep + Total number of links = 63112 + +.. raw:: html + +
+ +Next, run UV-CDAT and create the regridder: + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # Import regrid package for regridder functions + >>> import regrid2, cdms2 + >>> # Read the regridder from the remapper file + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> remapf.close() + +Then read the input data and regrid: + +.. doctest:: + + >>> # Get the source variable + >>> f = cdms2.open('xieArkin-T42.nc') + >>> t42prc = f('prc') + >>> f.close() + >>> # Regrid the source variable + >>> popdat = regridf(t42prc) + +Note that ``t42dat`` can have rank greater than 2. The trailing +dimensions must match the input grid shape. For example, if ``t42dat`` +has shape (12, 64, 128), then the input grid must have shape (64,128). +Similarly if the variable had a generic grid with shape (8092,), the +last dimension of the variable would have length 8092. + +4.1.3 Pressure-level regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To regrid a variable which is a function of latitude, longitude, +pressure level, and (optionally) time to a new set of pressure levels, +use the ``pressureRegrid`` function defined for variables. This function +takes an axis representing the target set of pressure levels, and +returns a new variable ``d`` regridded to that dimension. + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") + >>> ta=f('ta') + >>> ta.shape + (11, 17, 73, 144) + >>> ta.getAxisIds() + ['time', 'level', 'latitude', 'longitude'] + >>> result = ta.pressureRegrid(cdms2.createAxis([1000.0])) + >>> result.shape + (11, 1, 73, 144) + +4.1.4 Cross-section regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To regrid a variable which is a function of latitude, height, and +(optionally) time to a new latitude/height cross-section, use the +``crossSectionRegridder`` defined for variables. This function takes as +arguments the new latitudes and heights, and returns the variable +regridded to those axes. + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") + >>> ta=f('ta') + >>> ta.shape + (11, 17, 73, 144) + >>> levOut=cdms2.createAxis([1000.0,950.]) + >>> levOut.designateLevel() + >>> latOut=cdms2.createAxis(ta.getLatitude()[10:20]) + >>> latOut.designateLatitude() + >>> ta0 = ta[0,:] + >>> ta0.getAxisIds() + ['level', 'latitude', 'longitude'] + >>> taout = ta0.crossSectionRegrid(levOut, latOut) + >>> taout.shape + (2, 10, 144) + + +4.2 regrid module +^^^^^^^^^^^^^^^^^ + +The ``regrid`` module implements the CDMS regridding functionality as +well as the SCRIP interface. Although this module is not strictly a part +of CDMS, it is designed to work with CDMS objects. + +4.2.1 CDMS horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doctest:: + + from regrid2 import Regridder + +makes the CDMS Regridder class available within a Python program. An +instance of Regridder is a function which regrids data from rectangular +input to output grids. + +Table 4.1 CDMS Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: REgridder Constructure + :header: "Constructor", "Description" + :widths: 50, 90 + + "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + +4.2.2 SCRIP Regridder +^^^^^^^^^^^^^^^^^^^^^ + +SCRIP regridder functions are created with the ``regrid.readRegridder`` +function: + +Table 4.2 SCRIP Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: + :header: "Constructor", "Description" + :widths: 80, 90 + + "regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)", "Read a regridder from an open CDMS file object." + "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." + "", "``mapMethod`` is one of:" + "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." + "", "- ``'bilinear'``: bilinear interpolation" + "", "- ``'bicubic'``: bicubic interpolation" + "", "- ``'distwgt'``: distance-weighted interpolation." + "", "It is only necessary to specify the map method if it is not defined in the file." + "", "" + "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + +4.3 Regridder Functions +^^^^^^^^^^^^^^^^^^^^^^^ + +It is only necessary to specify the map method if it is not defined in +the file. + +If ``checkGrid`` is 1 (default), the grid cells are checked for +convexity, and ‘repaired’ if necessary. Grid cells may appear to be +nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of +shifting the cell vertices to the same side modulo 360 degrees. + +4.3.1 CDMS regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A CDMS regridder function is an instance of the CDMS ``Regridder`` +class. The function is associated with rectangular input and output +grids. Typically its use is straightforward: the function is passed an +input array and returns the regridded array. However, when the array has +missing data, or the input and/or output grids are masked, the logic +becomes more complicated. + +Step 1 +~~~~~~ + +The regridder function first forms an input mask. This mask is either +two-dimensional or n-dimensional, depending on the rank of the +user-supplied mask. If no mask or missing value is specified, the mask +is obtained from the data array mask if present. + +**Two-dimensional case:** + +- Let mask\_1 be the two-dimensional user mask supplied via the mask + argument, or the mask of the input grid if no user mask is specified. +- If a missing-data value is specified via the missing argument, let + the implicit\_mask be the two-dimensional mask defined as 0 where the + first horizontal slice of the input array is missing, 1 elsewhere. +- The input mask is the logical AND(mask\_1, implicit\_mask) + +**N-dimensional case:** + +- If the user mask is 3 or 4-dimensional with the same shape as the + input array, it is used as the input mask. + +Step 2 +~~~~~~ + +The data is then regridded. In the two-dimensional case, the input mask +is ‘broadcast’ across the other dimensions of the array. In other words, +it assumes that all horizontal slices of the array have the same mask. +The result is a new array, defined on the output grid. Optionally, the +regridder function can also return an array having the same shape as the +output array, defining the fractional area of the output array which +overlaps a non-missing input grid cell. This is useful for calculating +area-weighted means of masked data. + +Step 3 +~~~~~~ + +Finally, if the output grid has a mask, it is applied to the result +array. Where the output mask is 0, data values are set to the missing +data value, or 1.0e20 if undefined. The result array or transient +variable will have a mask value of 1 (invalid value) for those output +grid cells which completely overlap input grid cells with missing values + +Table 4.3 CDMS Regridder function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: + :header: "Type", "Function", "Description" + :widths: 40, 40, 80 + + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." + , , "``array`` is a Variable, masked array, or Numeric array of rank 2, 3, or 4." + , , + , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." + , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." + , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" + , , "- ``mask`` is a Numeric array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MA module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." + , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." + , , "``dataArray`` is the result data array." + , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." + +4.3.2 SCRIP Regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A SCRIP regridder function is an instance of the ScripRegridder class. +Such a function is created by calling the regrid.readRegridder method. +Typical usage is straightforward: + +.. doctest:: + + >>> import cdms2 + >>> import regrid2 + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> f = cdms2.open('xieArkin-T42.nc') + >>> t42prc = f('prc') + >>> f.close() + >>> # Regrid the source variable + >>> popdat = regridf(t42prc) + + + +The bicubic regridder takes four arguments: + +.. doctest:: + + >>> # outdat = regridf(t42prc, gradlat, gradlon, gradlatlon) + + +A regridder function also has associated methods to retrieve the +following fields: + +- Input grid +- Output grid +- Source fraction: the fraction of each source (input) grid cell + participating in the interpolation. +- Destination fraction: the fraction of each destination (output) grid + cell participating in the interpolation. + +In addition, a conservative regridder has the associated grid cell areas +for source and target grids. + +Table 4.4 SCRIP Regridder functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Return Type | Method | Description | ++===============================+============================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| Array or Transient-Variable | [conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)`` | Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Array or Transient-Variable | [bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)`` |

Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.

\ ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.

\ ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.

gradientLon: df/dj. Same shape as ``array``.

\ ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.

| ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getDestinationArea()`` [conservative regridders only] | Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getDestinationFraction()`` | Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CurveGrid or Generic-Grid | ``getInputGrid()`` | Return the input grid, or None if no input grid is associated with the regridder. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| CurveGrid or Generic-Grid | ``getOutputGrid()`` | Return the output grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getSourceArea()`` [conservative regridders only] | Return the area of the source (input) grid cell. The array is 1- D, with length equal to the number of cells in the input grid. | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Numeric array | ``getSourceFraction()`` | Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid | ++-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +4.4 Examples +^^^^^^^^^^^^ + +4.4.1 CDMS regridder +~~~~~~~~~~~~~~~~~~~~ + +**Example:** + +Regrid data to a uniform output grid. + +.. doctest:: + + + >>> import cdms2 + >>> from regrid2 import Regridder + >>> f = cdms2.open('clt.nc') + >>> cltf = f.variables['clt'] + >>> ingrid = cltf.getGrid() + >>> outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> regridFunc = Regridder(ingrid, outgrid) + >>> newrls = regridFunc(cltf) + >>> f.close() + + +.. csv-table:: REgridder Constructure + :header: "Line", "Notes" + :widths: 8, 90 + + "3", "Open a netCDF file for input." + "6", "Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset." + "7", "Create the regridder function." + "8", "Read all data and regrid. The missing data value is obtained from variable rlsf" + +Return the area fraction of the source (input) grid cell that +participates in the regridding. The array is 1-D, with length equal to +the number of cells in the input grid. + +**Example:** + +Get a mask from a separate file, and set as the input grid mask. + +.. doctest:: + + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/clt.nc + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc + >>> import cdms2 + >>> from regrid2 import Regridder + >>> # + >>> f = cdms2.open('clt.nc') + >>> cltf = f.variables['clt'] + >>> outgrid = cltf.getGrid() + >>> g = cdms2.open('geos5-sample.nc') + >>> ozoneg = g.variables['ozone'] + >>> ingrid = ozoneg.getGrid() + >>> regridFunc = Regridder(ingrid,outgrid) + >>> uwmaskvar = g.variables['uwnd'] + >>> uwmask = uwmaskvar[:]<0 + >>> outArray = regridFunc(ozoneg.subSlice(time=0),mask=uwmask) + >>> f.close() + >>> g.close() + + ++--------+-------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+===================================================================================================================+ +| 7 | Get the input grid. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 10 | Get the output grid | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 11 | Create the regridder function. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 14 | Get the mask. | ++--------+-------------------------------------------------------------------------------------------------------------------+ +| 15 | Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0 | ++--------+-------------------------------------------------------------------------------------------------------------------+ + +**Note:** Although it cannot be determined from the code, both mask and +the input array sof are four-dimensional. This is the n-dimensional +case. + +**Example:** + +Generate an array of zonal mean values. + +1 f = cdms.open(‘rls\_ccc\_per.nc’) 2 rlsf = f.variables[‘rls’] 3 ingrid += rlsf.getGrid() 4 outgrid = cdms.createZonalGrid(ingrid) 5 regridFunc = +Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() + ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+===================================================================================================================================================================================================+ +| 3 | Get the input grid. Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 4 | Create a zonal grid. outgrid has the same latitudes as ingrid, and a singleton longitude dimension. createGlobalMeanGrid could be used here to generate a global mean array. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 5 | Generate the regridder function. | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 6 | Generate the zonal mean array | ++--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +**Example:** + +Regrid an array with missing data, and calculate the area-weighted mean +of the result. + +.. doctest:: + + >>> import cdms2 + >>> from cdms2.MV2 import * + >>> from regrid2 import Regridder + >>> f = cdms2.open("ta_ncep_87-6-88-4.nc") + >>> var = f('ta') + >>> outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0) + >>> outlatw, outlonw = outgrid.getWeights() + >>> outweights = outerproduct(outlatw, outlonw) + >>> grid = var.getGrid() + >>> sample = var[0,0] + >>> latw, lonw = grid.getWeights() + >>> weights = outerproduct(latw, lonw) + >>> inmask = where(greater(absolute(sample),1.e15),0,1) + >>> mean = add.reduce(ravel(inmask*weights*sample))/add.reduce(ravel(inmask*weights)) + >>> regridFunc = Regridder(grid, outgrid) + >>> outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) + >>> outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) + + ++--------+----------------------------------------------------------------------------------------------------------+ +| Line | Notes | ++========+==========================================================================================================+ +| 2 | Create a uniform target grid. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 3 | Get the latitude and longitude weights. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 4 | Generate a 2-D weights array. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 5 | Get the input grid. ``var`` is a 4-D variable. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 6 | Get the first horizontal slice from ``var``. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 7-8 | Get the input weights, and generate a 2-D weights array. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 9 | Set the 2-D input mask. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 10 | Calculate the input array area-weighted mean. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 11 | Create the regridder function. | ++--------+----------------------------------------------------------------------------------------------------------+ +| 12 | Regrid. Because returnTuple is set to 1, the result is a tuple (dataArray, maskArray). | ++--------+----------------------------------------------------------------------------------------------------------+ +| 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | ++--------+----------------------------------------------------------------------------------------------------------+ + +4.4.2 SCRIP regridder +~~~~~~~~~~~~~~~~~~~~~ + +**Example:** + +Regrid from a curvilinear to a generic grid, using a conservative +remapping. Compute the area-weighted means on input and output for +comparison. + +.. doctest:: + + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> import cdms2, regrid2, MV2 + >>> # Open the SCRIP remapping file and data file + >>> fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc') + >>> fdat = cdms2.open('xieArkin-T42.nc') + >>> # Input data array + >>> dat = fdat('prc')[0,:] + >>> # Read the SCRIP regridder + >>> regridf = regrid2.readRegridder(fremap) + >>> # Regrid the variable + >>> outdat = regridf(dat) + >>> # Get the cell area and fraction arrays. Areas are computed only + >>> # for conservative regridding. + >>> srcfrac = regridf.getSourceFraction() + >>> srcarea = regridf.getSourceArea() + >>> dstfrac = regridf.getDestinationFraction() + >>> dstarea = regridf.getDestinationArea() + >>> # calculate area-weighted means + >>> inmean = MV2.sum(srcfrac*srcarea*MV2.ravel(dat)) / MV2.sum(srcfrac*srcarea) + >>> outmean = MV2.sum(dstfrac*dstarea*MV2.ravel(outdat)) / MV2.sum(dstfrac*dstarea) + >>> print 'Input mean:', inmean + Input mean: 2.60376502339 + >>> print 'Output mean:', outmean + Output mean: 2.60376502339 + >>> fremap.close() + >>> fdat.close() + + + + +a diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst new file mode 100644 index 00000000..0da06c4f --- /dev/null +++ b/docs/source/manual/cdms_5.rst @@ -0,0 +1,210 @@ +CHAPTER 5 Plotting CDMS data in Python +-------------------------------------- + +5.1 Overview +~~~~~~~~~~~~ + +Data read via the CDMS Python interface can be plotted using the ``vcs`` +module. This module, part of the Ultrascale Visualization Climate Data +Analysis Tool (UV-CDAT) is documented in the UV-CDAT reference manual. +The ``vcs`` module provides access to the functionality of the VCS +visualization program. + +Examples of plotting data accessed from CDMS are given below, as well as +documentation for the plot routine keywords. + +5.2 Examples +~~~~~~~~~~~~ + +In the following examples, it is assumed that variable ``psl`` is +dimensioned (time, latitude, longitude). ``psl`` is contained in the +dataset named ``'sample.xml'``. + +5.2.1 Example: plotting a gridded variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. testsetup:: * + + import requests + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + r = requests.get(url) + open(file, 'wb').write(r.content) + +.. testcleanup:: * + + import os + fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] + for file in fnames: + os.remove(file) + + + +.. doctest:: Example: plotting a gridded variable + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> sample = clt[0,:] + >>> w=vcs.init() + >>> w.plot(sample) + + >>> f.close() + +**Notes:** + +.. csv-table:: LineNotes + :header: "Line", "Notes" + :widths: 10, 90 + + "3","Get a horizontal slice, for the first time point." + "4","Create a VCS Canvas ``w``." + "5", "Plot the data. Because sample is a transient variable, it encapsulates all the time, latitude, longitude, and attribute information." + "7", "Close the file. This must be done after the reference to the persistent variable ``ps l``." + +Thats it! The axis coordinates, variable name, description, units, etc. +are obtained from variable sample. + +What if the units are not explicitly defined for ``clt``, or a different +description is desired? ``plot`` has a number of other keywords which +fill in the extra plot information. + +5.2.2 Example: using aplot keywords. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> sample = clt[0,:] + >>> w=vcs.init() + >>> w.plot(sample, units='percent', file_comment='', long_name="Total Cloud", comment1="Example plot", hms="00:00:00", ymd="1979/01/01") + + >>> f.close() + + +**Note:** Keyword arguments can be listed in any order. + +5.2.3 Example: plotting a time-latitude slice +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``, +this example selects and plots a time-latitude slice: + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> samp = clt[:,:,0] + >>> w = vcs.init() + >>> w.plot(samp, name='Total Cloudiness') + + +.. csv-table:: LineNotes + :header: "Line", "Notes" + :widths: 10, 90 + + "4", "``samp`` is a slice of ``clt``, at index ``0`` of the last dimension. Since ``samp`` was obtained from the slice operator, it is a transient variable, which includes the latitude and time information." + "6", "The ``name`` keyword defines the identifier, default is the name found in the file." + +5.2.4 Example: plotting subsetted data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Calling the variable ``clt`` as a function reads a subset of the +variable. The result variable ``samp`` can be plotted directly: + +.. doctest:: + + >>> import cdms2, vcs + >>> f = cdms2.open("clt.nc") + >>> clt = f.variables['clt'] + >>> samp = clt(time = (0.0,100.0), longitude = 180.0, squeeze=1) + >>> w = vcs.init() + >>> w.plot(samp) + + >>> f.close() + + +5.3 ``plot`` method +~~~~~~~~~~~~~~~~~~~ + +The ``plot`` method is documented in the UV-CDAT Reference Manual. This +section augments the documentation with a description of the optional +keyword arguments. The general form of the plot command is: + +``canvas.plot(array [, args] [,key=value [, key=value [, ...] ] ])`` + +where: + +- canvas is a VCS Canvas object, created with the vcs.init method. + +- array is a variable, masked array, or Numeric array having between + two and five dimensions. The last dimensions of the array is termed + the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', + and 'w'. For example, if array is three-dimensional, the axes are + (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). + (Note that the t dimension need have no connection with time; any + spatial axis can be mapped to any plot dimension. For a graphics + method which is two-dimensional, such as boxfill, the y-axis is + plotted on the horizontal, and the x-axis on the vertical. + + If array is a gridded variable on a rectangular grid, the plot + function uses a box-fill graphics method. If it is non-rectangular, + the meshfill graphics method is used. + + Note that some plot keywords apply only to rectangular grids only. + +- args are optional positional arguments: + + ``args`` := template\_name, graphics\_method, graphics\_name + + ``template_name``: the name of the VCS template (e.g., 'AMIP') + + ``graphics_method``: the VCS graphics method (boxfill) + + ``graphics_name``: the name of the specific graphics method + ('default') + + See the UV-CDAT Reference Manual and VCS Reference Manual for a + detailed description of these arguments. + +- ``key=value``, ... are optional keyword/value pairs, listed in any + order. These are defined in the table below. + + +.. csv-table:: "plot keywords" + :header: "Key", "Type", "Value" + :widths: 20, 20, 80 + + "``comment1``", "string", "Comment plotted above ``file_comment``" + "``comment2``", "string", "Comment plotted above ``comment1``" + "``comment3``", "string", "Comment plotted above ``comment2``" + "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if ``xaxis`` is longitude, ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" + "``file_comment``", "string", "Comment, defaults to ``variable.parent.comment``" + "``grid``", "CDMS grid object", "Grid associated with the data. Defaults to ``variable.getGrid()``" + "``hms``", "string", "Hour, minute, second" + "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." + "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" + "``name``", "string", "Variable name, defaults to `variable.id``" + "``time``", "cdtime relative or absolute", "Time associated with the data." + ,,"Example:" + ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" + "``units``", "string", "Data units. Defaults to ``variable.units``" + "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." + "``xarray`` (``[y|z|t|w]array``)", "1-D Numeric array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to xaxis[:\] (y|z|t|waxis[:])" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" + "``xbounds`` (``ybounds``)", "2-D Numeric array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." + + "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the x-axis (y-axis). Defaults to 0, with the following exceptions:" + ,,"- If the y-axis is latitude, and has decreasing values, ``yrev`` defaults to 1" + ,,"- If the y-axis is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." + + "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." + + + + +b diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst new file mode 100644 index 00000000..98fe67d5 --- /dev/null +++ b/docs/source/manual/cdms_6.rst @@ -0,0 +1,1793 @@ +CHAPTER 6 Climate Data Markup Language (CDML) +--------------------------------------------- + +6.1 Introduction +~~~~~~~~~~~~~~~~ + +The Climate Data Markup Language (CDML) is the markup language used to +represent metadata in CDMS. CDML is based on the W3C XML standard +(http://www.w3.org). This chapter defines the syntax of CDML. Read this +section if you will be building or maintaining a CDMS database. + +XML, the eXtensible Markup Language, makes it possible to define +interoperable dialects of markup languages. The most recent version of +HTML, the Web hypertext markup language, is an XML dialect. CDML is also +an XML dialect, geared toward the representation of gridded climate +datasets. XML provides rigor to the metadata representation, ensuring +that applications can access it correctly. XML also deals with +internationalization issues, and holds forth the promise that utilities +for browsing, editing, and other common tasks will be available in the +future. + +CDML files have the file extension .xml or .cdml. + +6.2 Elements +~~~~~~~~~~~~ + +A CDML document consists of a nested collection of elements. An element +is a description of the metadata associated with a CDMS object. The form +of an element is: + +`` element-content `` + +or + +```` + +where + +- ``tag`` is a string which defines the type of element +- ``attribute-list`` is a blank-separated list of attribute-value + pairs, of the form: + + ``attribute = "value"`` +- ``element-content`` depends on the type of element. It is either a + list of elements, or text which defines the element values. For + example, the content of an axis element either is a list of axis + values, or is a linear element. For datasets, the content is the + blank-separated list of elements corresponding to the axes, grids, + and variables contained in the dataset. + +The CDML elements are: + +Table 6.1 CDML Tags + + ++------------+---------------------------------------+ +| Tag | Description | ++============+=======================================+ +| attr | Extra attribute | ++------------+---------------------------------------+ +| axis | Coordinate axis | ++------------+---------------------------------------+ +| domain | Axes on which a variable is defined | ++------------+---------------------------------------+ +| domElem | Element of a variable domain | ++------------+---------------------------------------+ +| linear | Linearly-spaced axis values | ++------------+---------------------------------------+ +| rectGrid | Rectilinear Grid | ++------------+---------------------------------------+ +| variable | Variable | ++------------+---------------------------------------+ + +6.3 Special Characters +~~~~~~~~~~~~~~~~~~~~~~ + +XML reserves certain characters for markup. If they appear as content, +they must be encoded to avoid confusion with markup: + +Table 6.2 Special Character Encodings + + ++-------------+------------+ +| Character | Encoding | ++=============+============+ +| < | < | ++-------------+------------+ +| > | > | ++-------------+------------+ +| & | & | ++-------------+------------+ +| “ | " | ++-------------+------------+ +| ‘ | ' | ++-------------+------------+ + +For example, the comment + +**Certain "special characters", such as <, >, and ', must be encoded.** + +would appear in an attribute string as: + +**comment = "Certain "special characters", such as <, >, and ', must be encoded."** + +6.4 Identifiers +~~~~~~~~~~~~~~~ + +In CDMS, all objects in a dataset have a unique string identifier. The +id attribute holds the value of this identifier. If the variable, axis, +or grid has a string name within a data file, then the id attribute +ordinarily has this value. Alternatively, the name of the object in a +data file can be stored in the name_in_file attribute, which can +differ from the id. Datasets also have IDs, which can be used within a +larger context (databases). + +An identifer must start with an alphabetic character (upper or lower +case), an underscore (_), or a colon (:). Characters after the first +must be alphanumeric, an underscore, or colon. There is no restriction +on the length of an identifier. + +6.5 CF Metadata Standard +~~~~~~~~~~~~~~~~~~~~~~~~ + +`The CF metadata standard `__ defines a set +of conventions for usage of netCDF. This standard is supported by CDML. +The document defines names and usage for metadata attributes. CF +supersedes the GDT 1.3 standard. + +6.6 CDML Syntax +~~~~~~~~~~~~~~~ + +The following notation is used in this section: + +- A ``monospaced block`` is used for a syntax specification. +- **Bold** text indicates literals. +- (R|S) denotes either R or S. +- R* denotes zero or more R. +- R+ denotes one or more R. + +A CDML document consists of a prolog followed by a single dataset +element. + +``CDML-document ::= prolog dataset-element`` + +The prolog defines the XML version, and the Document Type Definition +(DTD), a formal specification of the document syntax. +See http://www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML + +Version 1.0. + +``prolog ::= `` + +6.6.1 Dataset Element +^^^^^^^^^^^^^^^^^^^^^ + +A dataset element describes a single dataset. The content is a list of +elements corresponding to the axes, grids, and variables contained in +the dataset. Axis, variable, and grid elements can be listed in any +order, and an element ID can be used before the element is actually +defined. + +``dataset-element ::=`` ** dataset-content`` **** + +``dataset-content ::= (axis-element | grid-element | variable-element)* extra-attribute-element+`` + +Table 6.3 Dataset Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. csv-table:: + :header: "Attribute", "Required", "CF", "GDT", "Notes" + :widths: 10,5,5,5,80 + + "appendices", "N", "N", "Y", "Version number" + "calendar", "N", "N", "Y", "Calendar used for encoding time axes." + ,,,,"``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard``" + ,,,,"Note: for the CF convention, the calendar attribute is placed on the time axis." + "comment", "N", "Y", "Y", "Additional dataset information" + "conventions", "Y", "Y", "Y", "The netCDF metadata standard. Example: 'CF-1.0'" + "cdms_filemap", "Y", "N", "N", "Map of partitioned axes to files. See note below." + "directory", "N", "N", "N", "Root directory of the dataset" + "frequency", "N", "N", "N", "Temporal frequency" + "history", "N", "Y", "Y", "Evolution of the data" + "id", "Y", "N", "N", "Dataset identifier" + "institution", "N", "Y", "Y", "Who made or supplied the data" + "production", "N", "N", "Y", "How the data was produced (see source)" + "project", "N", "N", "N", "Project associated with the data Example: 'CMIP 2'" + "references", "N", "Y", "N", "Published or web-based references that describe the data or methods used to produce it" + "source", "N", "Y", "N", "The method of production of the original data." + "template", "N", "N", "N", "Filename template. This is an alternate mechanism, other than cdms_filemap, for describing the file mapping. See ‘cdimport -h’ for details." + "title", "N", "Y", "N", "A succinct description of the data." + + +**Notes:** + +The ``cdms_filemap`` attribute describes how the dataset is partitioned +into files. The format is: + +* ``filemap ::= [ varmap, varmap, ...]`` + +* ``varmap ::= [ namelist, slicelist ]`` + +* ``namelist ::= [ name, name, ... ]`` + +* ``slicelist ::= [ indexlist, indexlist, ,,, ]`` + +* ``indexlist ::= [ time0, time1, lev0, lev1, path ]`` + +* ``name ::= variable name`` + +* ``time0 ::= first index of time in the file, or '-' if not split on time`` + +* ``time1 ::= last index of time + 1, in the file, or '-' if not split on time`` + +* ``lev0 ::= first index of vertical levels in the file, or '-' if not split on level`` + +* ``lev1 ::= last index +1 of vertical levels in the file, or '-' if not split on level`` + +* ``path ::= pathname of the file containing data for this time/level range.`` + +The pathname is appended to the value of the directory attribute, to +obtain an absolute pathname. + +6.6.2 Axis Element +^^^^^^^^^^^^^^^^^^ + +An axis element describes a single coordinate axis. The content can be a +blank-separated list of axis values or a linear element. A linear +element is a representation of a linearly-spaced axis as (start, delta, +length). + +``axis-element ::=`` ** axis-content`` **** + +``axis-content ::= (axis-values | linear-element) extra-attribute-element*`` + +``axis-values ::= [value*]`` + +``linear-element ::=`` ** ** + +Table 6.4 +^^^^^^^^^ + +.. csv-table:: + :header: "Attribute", "Required?", "CF", "GDT", "Notes" + :widths: 15,1,1,1,80 + + "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates." + "``axis``", "N", "Y", "Y", "The spatial type of the axis:" + ,,,,"- 'T' - time" + ,,,,"- 'X' - longitude" + ,,,,"- 'Y' - latitude" + ,,,,"- 'Z' - vertical level" + ,,,,"- '-' - not spatiotemporal" + "``bounds``", "N", "Y", "Y", "ID of the boundary variable" + "``calendar``", "N", "Y", "N", "See dataset.calendar" + "``climatology``", "N", "Y", "N", "Range of dates to which climatological statistics apply." + "``comment``", "N", "Y", "N", "String comment" + "``compress``", "N", "Y", "Y", "Dimensions which have been compressed by gathering" + "``datatype``", "Y", "N", "N", "Char, Short, Long, Float, Double, or String" + "``dates``", "N", "Y", "N", "Range of dates to which statistics for a typical diurnal cycle apply." + "``expand``", "N", "N", "Y", "Coordinates prior to contraction" + "``formula_terms``", "N", "Y", "N", "Variables that correspond to the terms in a formula." + "``id``", "Y", "N", "N", "Axis identifier. Also the name of the axis in the underlying file(s), if name_in_file is undefined." + "``isvar``", "N", "N", "N", "* 'true' | 'false'" + ,,,,"- 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s)." + ,,,,"- Default: 'true'" + "``leap_month``", "N", "Y", "N", "For a user-defined calendar, the month which is lengthened by a day in leap years." + "``leap_year``", "N", "Y", "N", "An example of a leap year for a user-defined calendar. All years that differ from this year by a multiple of four are leap years." + "``length``", "N", "N", "N", "Number of axis values, including values for which no data is defined. Cf. partition_length." + "``long_name``", "N", "Y", "Y", "Long description of a physical quantity" + "``modulo``", "N", "N", "Y", "Arithmetic modulo of an axis with circular topology." + "``month_lengths``", "N", "Y", "N", "Length of each month in a non-leap year for a user-defined calendar." + "``name_in_file``", "N", "N", "N", "Name of the axis in the underlying file(s). See id." + "``partition``", "N", "N", "N", "How the axis is split across files." + "``partition_lengt h``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." + "``positive``", "N", "Y", "Y", "Direction of positive for a vertical axis" + "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." + "``topology``", "N", "N", "Y", "- Axis topology." + ,,,,"- 'circular' | 'linear'" + "``units``", "Y", "Y", "Y", "Units of a physical quantity" + "``weights``", "N", "N", "N", "Name of the weights array" + +6.6.3 partition attribute +^^^^^^^^^^^^^^^^^^^^^^^^^ + + +For an axis in a dataset, the .partition attribute describes how an axis +is split across files. It is a list of the start and end indices of each +axis partition. + +FIGURE 4. Partitioned axis + + +.. figure:: /images/timeLine.jpg + :alt: + +For example, Figure 4 shows a time axis, representing the 36 months, +January 1980 through December 1982, with December 1981 missing. The +first partition interval is (0,12), the second is (12,23), and the third +is (24,36), where the interval (i,j) represents all indices k such that +i <= k < j. The .partition attribute for this axis would be the list: + +``[0, 12, 12, 23, 24, 36]`` + +Note that the end index of the second interval is strictly less than the +start index of the following interval. This indicates that data for that +period is missing. + +6.6.4 Grid Element +^^^^^^^^^^^^^^^^^^ + +A grid element describes a horizontal, latitude-longitude grid which is +rectilinear in topology, + +``grid-element ::=`` **** +``extra-attribute-element*`` **** + +Table 6.5 RectGrid Attributes + + +.. raw:: html + + + +:: + + + +.. raw:: html + + + +:: + + + + + + + + +.. raw:: html + +
Attribute Required? GDT? Notes
idYNGrid identifier
typeYN

Grid classification

"gaussian" | "uniform" | "equalarea" |"generic"

Default: "generic"

latitudeYNLatitude axis name
longitudeYNLongitude axis name
maskNNName of associated mask variable
orderYN

Grid ordering "yx" | "xy"

Default: “yx”, axis order is latitude, longitude

+ +6.6.5 Variable Element +^^^^^^^^^^^^^^^^^^^^^^ + +A variable element describes a data variable. The domain of the variable +is an ordered list of domain elements naming the axes on which the +variable is defined. A domain element is a reference to an axis or grid +in the dataset. + +The length of a domain element is the number of axis points for which +data can be retrieved. The partition\_length is the number of points for +which data is actually defined. If data is missing, this is less than +the length. + +``variable-element ::=`` **** +``variable-content`` **** + +``variable-content ::=`` variable-domain extra-attributeelement\*\` + +``variable-domain ::=`` **** ``domain-element*`` **** + +``domain-element ::=`` **\*\* + +Table 6.6 Variable Attributes + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + + + +.. raw:: html + +
+ +Attribute + +.. raw:: html + + + +Required? + +.. raw:: html + + + +CF + +.. raw:: html + + + +GDT + +.. raw:: html + + + +Notes + +.. raw:: html + +
+ +id + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Variable identifier. Also, the name of the variable in the underlying +file(s), if name\_in\_file is undefined. + +.. raw:: html + +
+ +add\_offset + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Additive offset for packing data. See scale\_factor. + +.. raw:: html + +
+ +associate + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +IDs of variables containing alternative sets of coordinates + +.. raw:: html + +
+ +axis + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +.. raw:: html + +

+ +Spatio-temporal dimensions. + +.. raw:: html + +

+ +.. raw:: html + +

+ +Example: "TYX" for a variable with domain (time, latitude, longitude) + +.. raw:: html + +

+ +.. raw:: html + +

+ +Note: for CF, applies to axes only. + +.. raw:: html + +

+ +.. raw:: html + +
+ +cell\_methods + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +The method used to derive data that represents cell values, e.g., +"maximum", "mean", "variance", etc. + +.. raw:: html + +
+ +comments + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Comment string + +.. raw:: html + +
+ +coordinates + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +IDs of variables containing coordinate data. + +.. raw:: html + +
+ +datatype + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Char, Short, Long, Float, Double, or String + +.. raw:: html + +
+ +grid\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Id of the grid + +.. raw:: html + +
+ +grid\_type + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +"gaussian" \| "uniform" \| "equalarea" \| "generic" + +.. raw:: html + +
+ +long\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Long description of a physical quantity. + +.. raw:: html + +
+ +missing\_value + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Value used for data that are unknown or missint. + +.. raw:: html + +
+ +name\_in\_file + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the variable in the underlying file(s). See id. + +.. raw:: html + +
+ +scale\_factor + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Multiplicative factor for packing data. See add\_offset. + +.. raw:: html + +
+ +standard\_name + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +N + +.. raw:: html + + + +Reference to an entry in the standard name table. + +.. raw:: html + +
+ +subgrid + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Records how data values represent subgrid variation. + +.. raw:: html + +
+ +template + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +N + +.. raw:: html + + + +Name of the file template to use for this variable. Overrides the +dataset value. + +.. raw:: html + +
+ +units + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Units of a physical quantity. + +.. raw:: html + +
+ +valid\_max + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest valid value of a variable + +.. raw:: html + +
+ +valid\_min + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Smallest valid value of a variable + +.. raw:: html + +
+ +valid\_range + +.. raw:: html + + + +N + +.. raw:: html + + + +Y + +.. raw:: html + + + +Y + +.. raw:: html + + + +Largest and smallest valid values of a variable + +.. raw:: html + +
+ +6.6.6 Attribute Element +^^^^^^^^^^^^^^^^^^^^^^^ + +Attributes which are not explicitly defined by the GDT convention are +represented as extra attribute elements. Any dataset, axis, grid, or +variable element can have an extra attribute as part of its content. +This representation is also useful if the attribute value has non-blank +whitespace characters (carriage returns, tabs, linefeeds) which are +significant. + +The datatype is one of: **Char**, **Short**, **Long**, **Float**, +**Double**, or **String**. + +``extra-attribute-element ::=`` **** ``attribute-value`` +**** + +6.7 A Sample CDML Document +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dataset "sample" has two variables, and six axes. + +**Note:** + +- The file is indented for readability. This is not required; the added + whitespace is ignored. +- The dataset contains three axes and two variables. Variables u and v + are functions of time, latitude, and longitude. +- The global attribute cdms\_filemap describes the mapping between + variables and files. The entry + ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` + indicates that variable ``u`` is contained in file u\_2000.nc for + time index 0, u\_2001.nc for time index 1, etc. + +{% highlight xml %} + +.. raw:: html + + + +.. raw:: html + + + + [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] + +:: + + + + [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. + + 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 + + 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 + + 303.75 315. 326.25 337.5 348.75] + + + + + [ 0. 366. 731.] + + + + + + + + + + + + + + + + + + + {% endhighlight %} + + + + c diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst new file mode 100644 index 00000000..ca533760 --- /dev/null +++ b/docs/source/manual/cdms_7.rst @@ -0,0 +1,165 @@ +CHAPTER 7 CDMS Utilities +------------------------ + +7.1 ``cdscan``: Importing datasets into CDMS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +7.1.1 Overview +^^^^^^^^^^^^^^ + +A dataset is a partitioned collection of files. To create a dataset, the +files must be scanned to produce a text representation of the dataset. +CDMS represents datasets as an ASCII metafile in the CDML markup +language. The file contains all metadata, together with information +describing how the dataset is partitioned into files. (Note: CDMS +provides a direct interface to individual files as well. It is not +necessary to scan an individual file in order to access it.) + +For CDMS applications to work correctly, it is important that the CDML +metafile be valid. The ``cdscan`` utility generates a metafile from a +collection of data files. + +CDMS assumes that there is some regularity in how datasets are +partitioned: + +- A variable can be partitioned (split across files) in at most two + dimensions. The partitioned dimension(s) must be either time or + vertical level dimensions; variables may not be partitioned across + longitude or latitude. Datasets can be parti-tioned by variable as + well. For example, one set of files might contain heat fluxes, while + another set contains wind speeds. + +Otherwise, there is considerable flexibility in how a dataset can be +partitioned: + +- Files can contain a single variable or all variables in the dataset. +- The time axis can have gaps. +- Horizontal grid boundary information and related information can be + duplicated across files. +- Variables can be on different grids. +- Files may be in any of the self-describing formats supported by CDMS, + including netCDF, HDF, GrADS/GRIB, and DRS. + +7.1.2 ``cdscan`` Syntax +^^^^^^^^^^^^^^^^^^^^^^^ + +The syntax of the ``cdscan`` command is + + - cdscan [options] file1 file2 ... + +or + + - cdscan [options] -f file_list + +where + +- ``file1 file2 ...`` is a blank-separated list of files to scan +- ``file_list`` is the name of a file containing a list of files to + scan, one pathname per line. + +Output is written to standard output by default. Use the -x option to +specify an output filename. + +Table 7.1 cdscan command options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "Option:, "Description" + :widths: 20, 80 + + "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. ``variable_id`` is the ID of the variable in the file, and ``alias`` is the name that will be substituted for it in the output dataset. Only variables with entries in the ``alias_file`` are renamed." + "``-c calendar``", "Specify the dataset calendar attribute. One of:" + , "- gregorian (default)" + , "- julian" + , "- noleap" + , "- proleptic_gregorian" + , "- standard" + , "- 360_day" + "``-d dataset_id``", "String identifier of the dataset. Should not contain blanks or non-printing characters. Default: 'None'" + "``-e newattr``", "Add or modify attributes of a file, variable, or axis." + ,"- The form of ``newattr`` is either:" + ," - ``var.attr = value`` to modify a variable or attribute, or" + ," - ``.attr = value`` to modify a global (file) attribute. In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." + "``--exclude var,var,...``", "Exclude specified variables. The argument is a comma-separated list of variables containing no blanks. Also see ``--include``." + "``-f file_list``", "File containing a list of absolute data file names, one per line." + "``-h``", "Print a help message." + "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. ``time_delta`` is a float or integer. For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." + "``--include var,var,...``", "Only include specified variables in the output. The argument is a comma-separated list of variables containing no blanks. Also see ``--exclude``." + "``-j``", "Scan time as a vector dimension. Time values are listed individually." + ,"- **Note:** Turns off the -i option." + "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." + "``-m levelid``", "Name of the vertical level dimension. The default is the vertical dimension as determined by CDMS. See Note 3." + "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. ``cdimport -h`` describes template strings." + "``-q``", "Quiet mode." + "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." + "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. Each line consists of two blank-separated fields: ``directory suffix``. Each file path is compared to the directories in the suffix file. If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. If more than one such directory is found, the first directory found is used. If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." + "``-t timeid``", "ID of the partitioned time dimension. The default is the name of the time dimension as determined by CDMS. See Note 1." + "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list:" + , "- zero is the initial time point, a floating-point value." + , "- delta is the time delta, floating-point." + , "- units are time units as specified in the [-r] option." + , "- calendar is optional, and is specified as in the [-c] option." + , "If omitted, it defaults to the value specified by [-c], otherwise as specified in the file." + , "**Example:** ``--time-linear '0,1,months since 1980,noleap'``" + "``-x xmlfile``", "Output file name. By default, output is written to standard output." + +**Notes:** + +- Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. + + +- By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. + +- Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. + +- Adding or modifying attributes with the -e option: + - time.units = "days since 1979-1-1" + +- sets the units of all variables/axes to "days since 1979-1-1". Note that since this is done before any other processing is done, it allows overriding of non-COARDS time units. + - .newattr=newvalue + +- Set the global file attribute 'newattr' to 'newvalue'. + +- The ``[--time-linear]`` option overrides the time values in the file(s). The resulting dimension does not have any gaps. In contrast, the ``[-i]``, ``[-r]`` options use the specified time units (from ``[-r]``), and calendar from ``[-c]`` if specified, to convert the file times to the new units. The resulting linear dimension may have gaps. + - In either case, the files are ordered by the time values in the files. + - The ``[--time-linear]`` option should be used with caution, as it is applied to all the time dimensions found. + + +7.1.3 Examples +^^^^^^^^^^^^^^ + +- cdscan -c noleap -d test -x test.xml [uv]\*.nc +- cdscan -d pcmdi\_6h -i 0.25 -r 'days since 1979-1-1' *6h*.ctl + +7.1.4 File Formats +^^^^^^^^^^^^^^^^^^ + +Data may be represented in a variety of self-describing binary file +formats, including + +- netCDF, the Unidata Network Common Data Format +- HDF, the NCSA Hierarchical Data Format +- GrADS/GRIB, WMO GRIB plus a GrADS control file (.ctl) The first + non-comment line of the control file must be a dset specification. +- DRS, the PCMDI legacy format. + +7.1.5 Name Aliasing +^^^^^^^^^^^^^^^^^^^ + +A problem can occur if variables in different files are defined on +different grids. What if the axis names are the same? CDMS requires that +within a dataset, axis and variable IDs (names) be unique. What should +the longitude axes be named in CDMS to ensure uniqueness? The answer is +to allow CDMS IDs to differ from file names. + +If a variable or axis has a CDMS ID which differs from its name in the +file, it is said to have an alias. The actual name of the object in the +file is stored in the attribute ``name_in_file``. ``cdscan`` uses this +mechanism (with the ``-a`` and ``s`` options) to resolve name conflicts; +a new axis or variable ID is generated, and the ``name_in_file`` is set +to the axis name in the file. + +Name aliases also can be used to enforce naming standards. For data +received from an outside organization, variable names may not be +recognized by existing applications. Often it is simpler and safer to +add an alias to the metafile rather than rewrite the data diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst new file mode 100644 index 00000000..70e4c29e --- /dev/null +++ b/docs/source/manual/cdms_appendix.rst @@ -0,0 +1,251 @@ +APPENDIX A +---------- + +CDMS Classes +~~~~~~~~~~~~ + +Figure 1, "CDMS Classes", on page 175 illustrates the class inheritance +structure of CDMS. The classes may be categorized as abstract or +concrete. Only concrete classes are meant to be used directly. In +contrast an abstract class defines the common interface of its +subclasses. For example, the class AbstractAxis2D defines the common +interface for two-dimensional coordinate axes. It has concrete +subclasses DatasetAxis2D, FileAxis2D, and TransientAxis2D, which are +used in applications. Abstract classes are denoted in italics. + +For many abstract classes there are three 'flavors' of subclass: +dataset, file, and transient. Dataset-related objects are thought of as +being contained in datasets in the sense that operations on those +objects result in I/O operations on the corresponding dataset. The same +is true of file-related objects. Objects in datasets and files are +examples of persistent objects, whose state persists after the +application exits. On the other hand, transient objects live in memory +and are not persistent. + +In general the concrete subclasses closely mirror the interface of the +abstract parent class. For this reason this document defines the +interfaces of the abstract classes, and only discusses a concrete class +in the few cases where the interface has been extended. This allows +applications to treat the behavior of, say a dataset axis and file axis, +as identical. + +.. figure:: /images/cdms_classes.jpg + :alt: + +FIGURE 1. CDMS Classes + + +APPENDIX B +---------- + +Version Notes +~~~~~~~~~~~~~ + +B.1 Version 4.0 +^^^^^^^^^^^^^^^ + +CDMS version 4.0 adds support for nonrectangular grids: + +- The following grid classes were added: AbstractHorizontalGrid, + AbstractCurve-Grid, AbstractGenericGrid, DatasetCurveGrid, + FileCurveGrid, TransientCurve-Grid, DatasetGenericGrid, + FileGenericGrid, and TransientGenericGrid. +- The following axis classes were added: AbstractCoordinateAxis, + AbstractAuxAxis1D, AbstractAxis2D, DatasetAuxAxis1D, FileAuxAxis1D, + TransientAuxAxis1D, DatasetAxis2D, FileAxis2D, and TransientAxis2D. +- The getMesh and clone methods were added for grids. +- An interface to the SCRIP package was added. + +B.2 Version 3.0 Overview +^^^^^^^^^^^^^^^^^^^^^^^^ + +CDMS version 3.0 is a significant enhancement of previous versions. The +major changes were: + +- UV-CDAT/CDMS was integrated with the Numerical Python masked array + class MA.MaskedVariable. The MV submodule was added as a wrapper + around MA. +- Methods that read data, such as subRegion, subSlice, and the slice + operations, return instances of class TransientVariable. The plot and + regrid modules were modified to handle masked array input. The + specifiers time=..., latitude=..., etc. were added to the I/O + routines. +- The class TransientVariable was added. +- A number of new functions were added, notably subRegion and subSlice, + which return instances of TransientVariable. +- When a masked array is returned from a method, it is "squeezed": + singleton dimensions are removed. In contrast, transient variables + are not squeezed. I/O functions have a squeeze option. The method + setAutoReshapeMode was removed. +- Internal attributes are handled in the InternalAttributes class. This + allows CDMS classes to be subclassed more readily. +- The class Variable was renamed DatasetVariable. +- The cu module was emulated in cdms. cu and cdms methods can be mixed. +- The code was modularized, so that Python, CDMS, and Numerical Python + can be built and installed separately. This significantly enhances + the portability of the code. + +B.3 V3.0 Details +^^^^^^^^^^^^^^^^ + +B.3.1 AbstractVariable +'''''''''''''''''''''' + +- Functions getDomain, getSlice, rank, regrid, setMissing, size, + subRegion, and subSlice were added. +- The functions getRegion, getSlice, getValue, and the slice operators + all return an instance of MA, a masked array. Singleton dimensions + are squeezed. +- The functions subRegion and subSlice return an instance of + TransientVariable. Singleton dimensions are not squeezed. +- The xxSlice and xxRegion functions have keywords time, level, + latitude, and longitude. +- The input functions have the keyword squeeze. +- AbstractVariable inherits from class Slab. The following functions + previously available in module cu are Slab methods: getattribute, + setattribute, listdimattributes, getdimattribute, listall, and info. +- AbstractVariable implements arithmetic functions, astype. +- The write function was added. + +B.3.2 AbstractAxis +'''''''''''''''''' + +- The functions asComponentTime, asRelativeTime, clone, getAxisIds, + getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were + added. +- subaxis was renamed subAxis for consistency. +- Generalized wraparound was implemented, to handle multiple cycles, + reversing, and negative strides. By default, coordinate intervals are + closed. The intersection options 'n','e','b',and 's' were added to + the interval indicator - see mapIntervalExt. + +B.3.3 AbstractDatabase +'''''''''''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.4 Dataset +''''''''''''' + +- The function open is synonymous with openDataset. + +B.3.5 cdms module +''''''''''''''''' + +- The functions asVariable, isVariable, and createVariable were added. +- The function setAutoReshapeMode was removed. It is replaced by the + squeeze option for all I/O functions. + +B.3.6 CdmsFile +'''''''''''''' + +- The function createVariable has a keyword fill\_value. The datatype + may be a Numeric/MA typecode. +- The function write was added. + +B.3.7 CDMSError +''''''''''''''' + +- All errors are an instance of the class CDMSError. + +B.3.8 AbstractRectGrid +'''''''''''''''''''''' + +- The function createGaussianGrid was added. + +B.3.9 InternalAttributes +'''''''''''''''''''''''' + +- The class InternalAttributes was added. It has methods + add\_internal\_attribute, is\_internal\_attribute, and + replace\_external\_attributes. + +B.3.10 TransientVariable +'''''''''''''''''''''''' + +- The class TransientVariable was added. It inherits from both + AbstractVariable and MA. +- The cdms module function createVariable returns a transient variable. +- This class does not implement the functions getPaths or getTemplate. + +B.3.11 MV +''''''''' + +- The MV submodule of cdms was added. + +APPENDIX C +---------- + +``cu`` Module +~~~~~~~~~~~~~ + +The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 +it is emulated in the ``cdms`` module. It is maintained for backward +compatibility. + +The ``cu`` classes are ``Slab``, corresponding to ``TransientVariable`` +in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. + +C.1 Slab +~~~~~~~~ + +Table C.1 Slab Methods +^^^^^^^^^^^^^^^^^^^^^^ + + +.. csv-table:: Slab_Methods + :header: "Type","Method","Definition" + :widths: 20,50,80 + + "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device ``. " + "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." + "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." + + + + +C.2 cuDataset +~~~~~~~~~~~~~ + +Table C.2 cuDataset Methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. csv-table:: cuDataset_Methods + :header: "Type", "Method", "Definition" + :widths: 20, 50, 80 + + "None", "cleardefault()", "Clear the default variable name." + "None", "default_variable(vname)", "Set the default variable name." + ,,"vname is the string variable name." + "Array", "dimensionarray(dname, vname=None)", "Values of the axis named dname." + ,,"dname is the string axis name." + ,,"vname is the string variable name. The default is the variable name set by default_variable." + "Axis", "dimensionobject(dname, vname=None)", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." + "Various", "getattribute (vname, attribute)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." + "String", "getdimensionunits (dname,vname=None)", "Get the units for the given dimension." + ,,"dname is the string name of an axis." + ,,"vname is a string variable name. The default is the variable name set by default_variable." + "Various", "getglobal (attribute)", "Get the value of the global attribute. attribute is the string attribute name." + "Variable", "getslab (vname, \*args)", "Read data for a variable." + ,, "vname is the string name of the variable." + ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" + ,, "- ':' or None -- select the entire dimension" + ,, "- Ellipsis -- select entire dimensions between the ones given." + ,, "- a pair of successive arguments giving an interval in world coordinates." + ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" + "List", "listall (vname=None, all=None)", "Get info about data from the file." + ,, "vname is the string name of the variable." + ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" + "List", "listattribute (vname=None )", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "listdimension (vname=None)", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "listglobal ()", "Return a list of the global attribute names." + "List", "listvariable ()", "Return a list of the variables in the file." + "None", "showall (vname=None, all=None, device=sys.stdout)", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "showattribute (vname=None, device=sys.stdout)", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." + "None", "showdimension (vname=None, device=sys.stdout)", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "showglobal (device=sys.stdout)", "Print the global file attributes. Output is sent to device." + "None", "showvariable (device=sys.stdout)", "Print the list of variables in the file." + diff --git a/docs/source/manual/images/curvilinear_grid.jpg b/docs/source/manual/images/curvilinear_grid.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f09fe0d64c7b7ec234b2b2e3b798cbf1076535eb GIT binary patch literal 105315 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�U%Xb{X$A!pF{r8%bg_XCA&#c_ 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
x-X8tY$yi~!0O^*-Bexv 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 literal 0 HcmV?d00001 diff --git a/docs/source/manual/images/generic_grid.jpg b/docs/source/manual/images/generic_grid.jpg new file mode 100755 index 0000000000000000000000000000000000000000..935a1de237e0206569c987e0a790e2d89d657ea1 GIT binary patch literal 86702 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 literal 0 HcmV?d00001 diff --git a/docs/source/manual/images/uvcdat.png b/docs/source/manual/images/uvcdat.png new file mode 100644 index 0000000000000000000000000000000000000000..75c1cf72d8c2a3938c550b1c938bbf7bf4957667 GIT binary patch literal 37672 zcmV)oK%BpcP)thr000U^X+uL$Nkc;* zP;zf(X>4Tx07wm;mUmPX*B8g%%xo{TU6vwc>AklFq%OTkl_mFQv@x1^BM1TV}0C2duqR=S6Xn?LjUp6xrb&~O43j*Nv zEr418u3H3zGns$s|L;SQD-ufpfWpxLJ03rmi*g~#S@{x?OrJ!Vo{}kJ7$ajbnjp%m zGEV!%=70KpVow?KvV}a4moSaFCQKV= zXBIPnpP$8-NG!rR+)R#`$7JVZi#Wn10DSspSrkx`)s~4C+0n+?(b2-z5-tDd^^cpM zz5W?wz5V3zGUCskL5!X++LzcbT23thtSPiMTfS&1I{|204}j|3FPi>70OSh+Xzlyz zdl<5LNtZ}OE>>3g`T3RtKG#xK(9i3CI(+v0d-&=+OWAp!Ysd8Ar*foO5~i%E+?=c& zshF87;&Ay)i~kOm zCIB-Z!^JGdti+UJsxgN!t(Y#%b<8kk67vyD#cE*9urAm@Y#cTXn~yERR$}Y1E!Yd# zo7hq8Ya9;8z!~A3Z~?e@Tn26#t`xT$*Ni)h>&K1Yrto;Y8r}@=h7ZGY@Dh9xekcA2 z{tSKqKZ<`tAQQ9+wgf*y0zpVvOQ<9qCY&Y=5XJ~ILHOG0j2XwBQ%7jM`P2tv~{#P+6CGu9Y;5!2hua>CG_v;z4S?CC1rc%807-x z8s$^ULkxsr$OvR)G0GUn7`GVjR5Vq*RQM{JRGL%DRgX~5SKp(4L49HleU9rK?wsN|$L8GCfHh1tA~lw29MI^|n9|hJ z^w$(=?$kW5IibbS^3=-Es?a*EHLgw5cGnhYS7@Kne#%s4dNH$@Rm?8tq>hG8fR0pW zzfP~tjINRHeBHIW&AJctNO~;2RJ{tlPQ6KeZT(RF<@$~KcMXUJEQ54|9R}S7(}qTd zv4$HA+YFx=sTu_uEj4O1x^GN1_Ap*-Tx)#81ZToB$u!w*a?KPrbudjgtugI0gUuYx z1ZKO<`pvQC&gMe%TJu2*iiMX&o<*a@uqDGX#B!}=o8@yWeX9hktybMuAFUm%v#jf^ z@7XBX1lg>$>9G0T*3_13TVs2}j%w#;x5}>F?uEUXJ>Pzh{cQ)DL#V?BhfaqNj!uqZ z$0o;dCw-@6r(I5iEIKQkRm!^LjCJ;QUgdn!`K^nii^S!a%Wtk0u9>cfU7yS~n#-SC zH+RHM*Nx-0-)+d9>7MMq&wa>4$AjZh>+#4_&y(j_?>XjW;+5fb#Ot}YwYS*2#e16V z!d}5X>x20C`xN{1`YQR(_pSDQ=%?$K=GW*q>F?mb%>QfvHXt})YrtTjW*|4PA#gIt zDQHDdS1=_wD!4lMQHW`XIHV&K4h;(37J7f4!93x-wlEMD7`83!LAX));_x3Ma1r4V zH4%>^Z6cRPc1O{olA;bry^i*dE{nc5-*~=serJq)Okzw!%yg_zYWi`#ol25V;v^kU#wN!mA5MPH z3FFjqrcwe^cBM>m+1wr6XFN|{1#g`1#xLiOrMjh-r#?w@OWT$Wgg6&&5F%x&L(6hXP*!%2{VOVIa)adIsGCtQITk9vCHD^izmgw;`&@D zcVTY3gpU49^+=7S>!rha?s+wNZ}MaEj~6Hw2n%|am@e70WNfM5(r=exmT{MLF4tMU zX8G_6uNC`OLMu~NcCOM}Rk&(&wg2ivYe;J{*Zj2BdTsgISLt?eJQu}$~QLORDCnMIdyYynPb_W zEx0YhEw{FMY&}%2SiZD;WLxOA)(U1tamB0cN!u@1+E?z~LE0hRF;o>&)xJ}I=a!xC ztJAA*)_B)6@6y<{Y1i~_-tK`to_m`1YVIxB`);3L-|hYW`&(-bYby`n4&)tpTo+T< z{VnU;hI;k-lKKw^g$IWYMIP#EaB65ctZ}%k5pI+=jvq-pa_u{x@7kLzn)Wv{noEv? zqtc^Kzfb=D*0JDYoyS?nn|?6(VOI;SrMMMpUD7()mfkkh9^c-7BIrbChiga6kCs0k zJgIZC=9KcOveTr~g{NoFEIl)IR&;jaT-v#j&ZN$J=i|=b=!)p-y%2oi(nY_E=exbS z&s=i5bn>#xz3Ke>~2=f&N;yEFGz-^boBexUH6@}b7V+Mi8+ZXR+R zIyLMw-18{v(Y+Dw$g^K^e|bMz_?Y^*a!h-y;fd{&ljDBl*PbqTI{HlXY-Xb9SH)j< zJvV;-!*8Cy^-RW1j=m7TnEk!!L%G_}Ibekb|EZ?v-uq&3xPZvo2NsT~i1X3dqX9QBf z7iUmXS=V+10sykvkWzkt+oWFs)Bti~kx3#PK+T5&K>(cwM0ACqNZiv~02|r!{1?H( za6Yn~K)o~|W46PPY$x{(Nw*sY^HM1_0;v&5jet1I`}2&2||YpOJ%`OQbMAP14dF64LM%20DVA{^1X*;#>p_StfE0 z&FOQb6A7Mfkb?F=K>QOkV(|y0rqm;wO4GvR;UN>cR}k&UA?{7!vPXfLVYx zfE)m?wlqub+*2Xx=?={XWm^P2llo&h@;bYECgttAUTNtc*Y&1n0}=!fX1Z;%p~xe5 z)D*~jx93YqmeU|>G?h{#kQ#woYXnljcWXWG>vFdfpzJ{1$-M;{2Dx-RNuIBjy*rXqP@dx7k#%#vIW zC4{Mz8iCXZ+zKO*0=`?}DPO019GL@k2RYq@50o8{$qKNt0qh8P7W~F0=H%r0L3tU} zSbP7ZjL-SS2>^0f!^*`F`^g*xe+rc0hLTJYYQYVFJ1f*xgUXxZENf^!H-+q zBkS|L9pE}TJ}b{1X_KSpdc+2nCxMmyFcT?7FW8?Bt4+3+XUPLw3+2(h#ga>HnN&)R zKxzbT>Jdl*-%b5^ug}em&V^L}Y*=S7%D4xd7k|)ZWIjEcwF6c8U|!-yC?S1UCGi2RglvKg^E?KLTp+ z;Iy1+=##F&N$DP*mWio3vEsVG!1)vg+YqjAk%}C*d~k1>d}4p8WTyadevDE(sS&u@ zMj!=zH`^1vPWMBgIo3F$tRA;GGF%dXOpdgY4Zsq@{@IpcP;N?2G!Dx1pzwUyC-q0U zTpmE|L;EV_eYcfM=g_o#_4{XKIvCUxVs!VZ+3AGx%lmhh%l-Q*Bs<$F)7~I7J|iGU z%FhJ6NFLkQN-@|H;m9I20BXa-V5`2`B+c_;w<^)LlyGK zt|BPN#1xF~U}`@#0;v(WAx9tud^hA{duKb{(mSpG=7lzS8EnhEOs9PDlRKp-*DVIX zV|vCXPrlwRKYhDXYVti&1U6+xnhn5WXmCt-*<{zrfBGg})#mQq0eAt@c$7B910OT1^n@3J{$(g1; z8ACrc^%r|V98)8d?A8O2H~#uvYvj7MXvxmhWwII=crD)-dumjHNO8dRuV**-Zd{j+|}#sv02xg;c6E>L@i zsSRe?+wFG9y$9FIZQD!b#Wz~yWb**ze_+X)l_FaQ0GNP#_`;yncaF z-d`mJ9(!!jaE%aznt@pn|Ey9$KQ0!)@tnTLn5M&r><|e_y9Jqwr&4MJ zQX_EfM<4}!*M5v|iYuJ&oYYj_v*!ndz~F?o-F(7?KRWG~7XXeQJhTREQJOUvvS&?>yjtHcevnzQEJ)TR+PERJoACOi zA9A~jk_-vJ7BCEX_#58UGQKd)XvmD$FBbL_^=7FsgEC}e5^plVn*G52wP1saoNOA< z$}qe}bYef!oL2F|4)D8gUXoLn#^ehRRjU1k0O*-f2~G5fnwu0g)eACr0C^*#y!atc z{9f#jg~2VlQFEXDwE}S6*#JCfs(K3HdZs{0c9mE%O2sJLEJj{!Y?sX1scmWmQX_Dc zBai~Vs~o^vq54zD`_wm{y9ni!SpZO&LIQ?JKa^E^ho_{yXF~q*)fNdxs6TT|ICE2* zQiBfuP{v1x3IFt3o0R0G$^CnZAy)%V(BMzgWoFGdTNJrxYq4wti_{Mw(*Os=1C(iC zv;f6O+fmj?C76GFx*p&dl7m}IW&7r$Fy)61X?7^eQ1kNx_txtEox0EuO;KPG`bQaM zbkYC_MV<4#6Y`(_rC$Dg-7~T?cvwQyV-oQDQ6IFf1wU>L)a8$fR2=!Gym@Y!RAdpr zfe8gAG&zW!ehCdVhtDC;usOuYEEUVf_bc1Je`kmzlQmN*H3F#-Sj7=Y$@o@rFmJY| z2q52lrd9ppn;l>qDoyD{-y^BHqI4%%ofhexn!N%vSeC>M(Z&PHYYKoxvxF+h{r==v zc1U5KTOWgkDsR>e$p8FB;}zPStnLR;9a>i)zx^RlLZIUO;9-)DNp>W01#p2<@YaI% zpLn53-T;uzp$;iQJAmwwLu=Bux>tx(;mFwn96*N$D13!Nh}3xoL~+Ww)AcA198 zqk$03i^no2pU-(p8 z%0I2CMVSS)I5#eqybWSK_`711-3D|gGdYz~Baj+_)fj;k#kU%xcoVkKJ2I>O^rubo zY{LN9krr{7luXpUlHEB186HzKKtvVMRM&@hmC2Sh+4AKd*K3F(%W-nj2dd94LA0Bd z4y{X2lQb}owzXqBgfuFf6lS@^fqu}5b(q=eeaP);FX6=<#|v3b|GWv@n-S@nmvlc|U-~1@_@XdrPGY-dZ^8Q$E-;HYl0 zk8YOzn+kM(Kh8%Of@XES^@7aWQ=KdCg?$|pn$zV-&C$yz$vRSfmdLgOZp}VXkS@89 z<2AGm>pC^n`C<7U>*L4kM2J3pJ_s-+E)^AJ$VVU8B;S3yPSzA<$@;aq@=rgn)AB`K z5P$3jz!MPquVdTgoUc?qcTb_*y}KGG(xK&(VHR827E~h87GAX>^Fy+h9|*TIH;xXb zD8BGur2eKx;Oa+U=~?aS+fTJ{gN?wMwh8s6AJ)so!Kr0IZ?RhghG@kWA6S^Tug{b6 zf;7#R^Z@jr_o$UhdZ+wwSJnmK%hv#Q7d)pt-`KyPNexawsoU1&NljI{3{OJ&1)0p} zH3(J)WP6nEF_(J*041r$_d$8)-u+boJOCZaQT7)uAFfBRG!yfKIN#AZCYb=t|NG;6 zQ7{)RIY2e~L2X_J9)hRa;*+}R9QlKn?eYidF8R=|s{}o>Gx4_0lsQGbVM*ns zMqs5QkOIDyj@(UHukO;M`r`NNrDJSb(jk*uX(FY!p}->_f`R(&HMu%o-cOEp$|P8p zwAEV=k1aj$qLSlrXoVMEXV->2*;1S#C!s{*j3}5;5ypl6OotsT(+IT(P_vq-1@Izh z5%TE9j4V&?Q}Kp&e54K)P%2zJ43Ii63iNnw8#F9i+lS=I7tU*q&)c?^$j;5Bk`8~N zzxwc2dF8E3(%d~7_WQ{SNN5^ikAl!1osj?j#AzUBt@_a3VrHjOY6Mav@Gc*LWoNg} z@BEDl&Cw<)xo^7Y{T~ol+1lhPEi+hwi4oQJ)Dsezg4`uCIWAR2LC9kd%!tc7AgT^up4~y z?G8D7wo5D3unjX&Q*{pG{@;GwNPtxzzU>A8KWdoCFyRi%%+vmdH@4<&_#o@ft|L(HDcj<2dG!v6}9}=8^Ih){>&fKzv zz_+Sn;vXB7j&D6Kvwfqm^R3;QR#3t*jK@YeL!Ka;6QUH8QA?(c#Jd#wst1TS7 zcvigM{suG{q0Erzf&=%eya1OE{Ib~ge=w;obdS!d-~E?!p!8;R)B-e>bmC*51$fX0 zC*^p@y2fM>QD*5O#S3jpbDhH5xd6YJJF9Z!gZs-hnvp^Tm8KrpSu7_nj>=Q#dc_0T zBFoO;1s(=aLa#*wA3GMr2@5W0Dynb><&Vjv`l9p9b8L_Oj7`)utyy0nr3i_167JRB ztnZdOP=Hg<_~gMm*2}u8Jh}V!HPQq3YW0_fbV#M>HmEu32l)NTla1nX+SNnb^UO;| z7kg*-1F$U|Z&5M zmcMR%8ShVWi?--CmfPn$z(tWxIG`i-N~cGvJOxsbU8Z)GZI#;W3fWY!!LVGzek|9| z*z=>4bLyKfw8$Aacc&Y_M3N8R-N)dn?<;Gw5-G0BjG+A&|Miqi3{8nOioKt31MiZ8 zekiq7Zz+*I_pT%GUD2y6b7G1ZHhPx8FG=9LCMzerr1Skr0Qk6WWUy1O-zpxMLq*$C z$J}PzLj&Jmpze+9417@4uRn}QA6`6?`S5@oMutbMI}T#@U-q%i-!JXJzxjNt2G|X7 zG1eRL$TD9bfgPGUq+#-Z-=-3It9?{DM!m8Pt1UOkw7Y6@jP1X@PyP2N8sy2kKJC2v z{`L8?4{pmGz&1oMQl#dn(dkBofB%6EidvkM_c@?78a6AyEpfuak1{?29$A_MKT?2P z;E+Njr5TJW$1(;?D48~B+?MyO+LstiIkollox;3Gqui6Nwarc0{s_6&OayR?kw3^RIBc< z*d>qD-iJllJO3=3`=;gmKv)D3fAp>#F@Be)x+i65Y)<88gPKhs=_n?6&*{rQ@qephOlD>R2nd_5%>%F) z;l(ruGlbxM1-VY+k3O+g?K_bx-#gMFtx#5(fwz|#1hb{mN+4p+z`nDh`NOVGeAT0& ziRaBcla|qS@Fy0-sNHG70xuT;*xWNFPOyAw`}gYUPU#t(fWOdem^q}$xEGv&IFq*x zb^9S7{o@~>m%se;sZi&OVd{>fLURba z=Nk3s#%rzIsU>J5Vic-Q#kq zeMCEMUZnUH*#wv%faw6VEd2Ef|)ns+A8MUqKBBM4JSOP?7VH!BC#j>U{}x!ouyBK(%Vp- zBX7cIC4wC0Pe z^LbAH_&1#9^RZ*rn?J`q^B`(V_6R$$8D3&)%W^dPl{dqQhvp3DT8E{NvJc(KsERSW zY2e|WY#WiUKMi?W%(;~us=+!HeDmwd|Fh4D|Cv9K!0GR!8Gv%l`*9;tiXiYBqb~fD z3Z3{L0KIk;0pMx2cf7k@Nl$LAI(#ol1w!dXe$jJIKK=7QmY+2|vl@>yse!D6;#o74 z&a5k7L%XnOJJUKQ!xMAYz28aQoNN0#9O`${AYAL6h7?MeCLA2!I` zY*3L6uYnAOxHUnFTLO^}Q5eYHWCASfZFnEY03eo&PP%>^xFPko3|{GG2y*K|)&1&Y z+hsG9TF5Ebu_h0!u&@lVx;zImJjbH4KC>?b`yUxP12^zo=9HO9dOg4VR$srbEz6rBxdN52)sjxheUN zul}Wc`_vOE$T7Z7=`g~7QBfu8^-uW9R5m-0#aey$RKj&`g@QLdt5ZKjOrW9iS_FTC z@ESfPub3^Dc+ym+33gqSU`La(uHSQcqFJKON>7C@fz3JGi$#3YV==*wjZ!DUjtpze zTndds+om#TiVOnbVMrZM<`d}@qxm#Wgg}kK4h^i|W_V|L8`NI3f%bC!XTa8N@R0KF z0D2Bka6W(@=?(&m2}Jnb7QhcFzvljF`TRehl}>~!8i%Ild8lUZTAvdJBuM!b(24)i z49)L!eGa(!W4|=8#oWGmp4Ug$E+-rl@OVC6Vt#aSvy7(jz_Pq^UzHR=;b-5DGO@jO z5mabUYkwZ8?^(1>vyJdLgyes}cu}@hWT-8r2s^Y~!s05_eO!e)j!Nj#E1=rIQl%ma z`SmgEO53(y!i{m1kYI`sI`bE(_blEGXCyz~orR01{;q5UTvoe|Ao7L7e=Eb&qw4c_ z{KoRnbY+*CuQdlBeW$@@2Lptk|B4dhPQG?_08ZZXS5*IItQ0lF-i)^wxhGIFMn)E7 zA{!+5_9?BUn(*D)Y!VtCkznh20q`YUZ6yT*%?%P79Yp`2fIyOo^I8U!IhQq47+zUt74rmfLAco&)#347qomy~5fHc&e4l1 zc;P7tb)673)CBhW6yAX}JWKpy6DSQMXANxO_RpVDXa7ot+5vhrf6;e1e=4=J$|FE_ zqs#7;Z=C&!lxF0qPwx28;xE7|T)P>R+J&BJu`i*axZGtJ{_EA&5g8fxsoX5bHSOzcqjlwn;`>rr5XLDZXPzF`*>6cEU<8)bzHQ#ZJvtlU%VAS}< zwie-S+>u$8S7nzu2b)w3KQ%r*{t)fka3G**Mu84$sso$S5SiXNd$Hw}%BxdsWo zZq+fEF<7wRx|+9|3q^7;UTq$}2EDv7o4hqBK0F)chpVL04Tf#)7Ue(v7Cm; zh*?>Ufud?UF1Ec7E>`NQ@`Ei6m?4J%dRV#hsl;M40gj&+^3@D{Q^G_;yy({q94LR_ zGh*Kh4L?$O`V)j36tK&5LYz2b?4k@nwAqyZuvh{57H~Us0NH-JKMGS};lhdkrN-L} zh{k@jWkh<1X5>@%ts(dsZglGsqC30uA!WD(b@;d(|_?;c=kv~87kMd{l z`y#H6XSs@L2#eEG?XV|Z;WrxH6`C?M_DxAw|BNaxNiBnyAS?udEdlK|as?NL`o|2jd*mc^(SLYD_d1w`O*d*9P zl*<>}miNJaZ=+%4tTT*U{@`w@WLNlyAg2B;pET+#KPj^o4}d5HHeE^^g12*MHU|EdWExxRy!;PwH*_3;_E1@1BE^I@MD( zc5C>KR~OnlOM)`iI5w=@$(9z5iLPRR_V1hFoqA;I*8qFrIfpPQ4jyP9$~laizw%SfX4n zmENflpuF#ii-+ae#+Md-XII*{V;4qb5K3UctgB8GEp)yHP{8aaDFzDsW*PH zR8)zjblsAlM#n@*jUdF1%>cCrr0In}z6*#pU?u8YWzuX;2;QHq@0auK$7U3W6>w|CworOOfrl{;lYvDXypC@BF zpzFr1HD5j99a4R1X*St|C=MPcWWcy+2=c&kXuEncobup%Hp;I(yiIB=^K{4~deInx zJGjST;^2pAyk+w*8Ma6M+OR+PXJXy<5j=a>((e}Jf7Y^HViayOWU2#ly{B=1E0_Bu zcBA1Di;OC&tk&`3S6{6w#A|2qtFHWv4GZEK{JweW3Gw=-dD&G<$lm_RH;ktKRJ{HQo5(%E#&z!Y4OB{8n3N;csPK;xegx@gaaTvb() zZg`Re87If{ z9DIy!-&mx59hSgf=|gv|m+$`U9PAfu(mpsTr{S`#bu6H2a-miW)|gRwhheKcBb=(lo?_liV0u?1j7-=H@Buzxiv4f5F&!8;V)SAm=|m+N-}b0-L$m2BRBKZl6>e?eZ9J&kg`cwq-h{u7u2tTB2Q$g{>=1pMPIXU^71g z-nO}K?wDl=?6Ju_$NcEiIzKuiw&D`Ul)0R~&@Zo^>JTT`y_Dnep6Su0Yj{fFa#Y(~ z&BC)y0n9$`yS-WlG46%A>5`R`CY?S*HsIO>{BXjU(Exq;Vz`s@`H|D0_NcIA6u~d& zRHsrshf(<|KV5yLtbl`CPpp3vr?NxN?id*6RbwRuHblbQ9_^vq5jBJG9de6sqh!^Fk zl(o`C06p=1vrLY7^`bD*c35vcyg^lMDngYNexRsnh9z>~`;3?3=f*2}6Xn_VzE6BV zdjd<6#VMsLZWk|&f(RJ*#FI+iqT$?YIWm$Lz2!n%hf;p9R z&xBM3Vi2-!sOyLdyz<{fjdtO^0?RWt!PLc4`)dHHOhcW2LMen3TKW5jQ6b=ERKfGh z{bI@4%-DDUJxtc`u(y|cH{NaF7kl^D!dJ27O*=JUjIJ zm+VDJIbN9PmzSDemPfZgnr!te%D;hlkX}$;X>mg8Tv0fQ3@*}MIMXlh-&-8FR$h_E zc;q*3k9#iJ%;wWQY67zUs1@F_O@#2xY`bHvy!Vqk^|!HXg%uWvH>IwysT-%7rEDFv z<4QT}Ce>-0H3YjZ0Fc@_r>;s0w4Q~cN;`lf286L77iw-UlBlI>-+52t>UbWFu27+cs|QeAmNgHF_0ZSEvhkN;aES@VUGR>B z-g0BU+UH$Pk5Q4g*0{6!pz;44_>A$xNB>0bE!+sU^&H-*(dG8R-n4G`xL9_6-Vj&*wRs7a z>%+VB{KmqK#$P=6hw_24?V#d)^RHGi-DLpXw|X0-Vd&!J7b2MkB4rx@Os#{{pgvds z5%JR>#{&3uuu^a3bV~vsCl2f8+rc`*$~k7mzU<2Y$}HG;6qDH1uSyu_FW7htB$-P> zBY=ejp9bZD*0r^8Lqp!AkASFHVnI zES5U~b|m-Cfa;tB^|7YRLr_z_V?Oml+d18f$E7}4?n7C_qr4EkE{+NmEOb1xWorqBJ znPjqKUg?Et%4>+@ zx6;JNf24T?^73o5K;@#>iv{o-h|zZ|rv#_kn{SA$h}K{&tAbJqc!5bI0|8?F_3)`U zGr7_!X#Q$ybU*@ajhX@ojo?v`%Hy=emO%h&AdGhvC_-2_?}snWyhSImfmsE2TbF@| zE4>qEyJct!K~xuEMdFIrBoUm-G6C+m?hnBZox_Cw`A2Ky-mUpiOf`%Pos;l;=#)Qt zWV75`Qvk=(N}7A8WC}OHeiOh-!=r!r!!46pmixpG9#d4Rk0W_z*>G<1 ze_5Y^zH3XVtSQX~l@RU~ftt2^ekiuQ-Ovk10a&?1+jD3-Bxjn&WJCWma`&;{l#;>2 zqDbXMYZQXbM!>Ue|F~EyAZLNng>}sx@Xfg%CJdb_G=6bm`9!-7H)lpxwOF=%7WGMY zr_y30kb`gPiw8d|ZYU3#@7ZEym5(y>{YG_nKZD*6H6u)Sw2>?0);V;NC z8mNZ`qNqLsUwWKxhn`ombH!G(C4QsGC3~<76D?(FOq`6z#%D3{!Y=4KgC4JM$A>lv ztY)x@yc#VP!kn*F+hzo4a zp@~_&$nZkPv)DE(huZ$9>^S*H;+h?lkXDY0JRo)|0ELtET(RHxWwGA*CBw4uVLUjn zIT?k4Y2-W%vEc0`8YshOmiddDhT?^FJ!FJwV3(%SvLmp+YOnDbL|mWodzUR6TY%nN z&Ou(=GdU1@Dxu>Rcvoo}onBN8$o@RZr41bX_*v!{u zxz$Ld?zYwzNo8S%20h9t55a2-wLSYrW)YR%DR(+rE$modv)Ayl@2aLr zSKPA6w*79Xb^kq3f_@W|U;$y)3^dk@6GCuUX|8Depy#WC7n^X|$V(2e(>^%6VNhEg zra~>5pkF+g!lzKiT%v$tvu@c6*$?clVv?HbQ!>&l(}TSd%KwnALZF+3&%YLUYDpU3 zW7@x(LvS>8b=nV7)>sei&l8u1r7XiOpS^b-6hSN+=m?HfiZj`pL@@#v^Vxq=RAC?s z16(){Cs~f?^)4wdb01q~>ilqC_-J+h(s^}GmRo-9u^s3?s8fLT%SSHB&rkG8R&Yvw zFZ&JoMCOa)u}+9jL8crvsW~h@Xac&$w(XVclR@k~OR;9|UA_Ry+xK81GgDw%Lai^Tz#CtK z$N&FJ0zdkU_y^9T+3-YXhkS|Z^aGGJt(K=2^U}#~2}~CJF;}#=A+q^bKDk})*AsN@VA_h#4k?-L#k-Ou@IhW^q`~mL^w4VF?k&^SeHFVT6VHI}V={@QPl4STge*Rp zbgFq&b&bs?Z8%P?;^cbB^|m4Xh(`T(OT<}vG9A4M%HGnz$LD9?br&YcR{bd?>r*c>)(dbbj!99|zp( zAM!a*nfu{wm;&St@c3FJxDyaR7A3aHe))3t6Y{mfe~|6&1^}J|_YnTfG~ihRxG$^x zyl1z3?ZN}{%3y``UU(ZmShdITxLs3_?I|y#T_g#7RBFj1cOd&6eDZN`>4wPMzh=Lb zd*Ev|Neyl;>_%oMrDwD&ske>p>?Q$5=E5+MLE<-14yO-pd|Q0)lS!x|&z&PBsJWwLIllt8g`r`eXw6^ zL;OI*IB7r4>XWgER&vUjSN(3 z@j|JjyLViB44J>_>%2oyD~DF+=O5i9+c)G&2An$AuF007e78(^$<(|INc?#9aU_rX zn!Sk~0wELg2!h;(f$d7!o<66`hCz>Y&HC6~)f9k;ODE5onmGkRNvLlDf$fnMli)zVsq#>1Ysn;a??Guv-~x5ox1f^8%n!lkI3_ z1-&Q9o3}0L_tWh2t-f{IUB>PC)#}1HsO=<@fd$Ys9M887w@XDHzQqL6EFzPfXrIvT z?!XXFIL*M=`;Ogt(m(8#moAMa<#vs-zBACCrontcu5-aVmv9Ge(1N!-#b?PbH0)dU zi1Hy|T@uM~z>7;;orDHEImafIf}O1r?C;cO3~?*ssVI1D@weHr(uYIc3?;UzfY>(R z#LR0FIQ=is@B^EaQMYyQ(y)Be3eCWg>}}$6o*2KB2CR879swmT7rfacL=xs^QgP8#nx^v5Sq?0{KWIvi`^ez*A1+V!4udQK^jIJHgiu|F z`;oFN&!o@ePqM4xaP4@1ac!`ZX_r?rcuWqw{d=PsZpQfltoY8^BGt#Zr=A(@i)!U=3Qg9Dvp6%i&p()LbG76JD?f za=z|1L`_d@RcAIEY6Y8f2I}i+8D`d%Tg;oGVZ;E0`oA5@E|x;V0TNNbh*7Aau`Q@Q z3p~s8=kFIUz|bB5wFuJ-x(FMG0rfj!#-O{4kCESFP6mJuUD6=NkP%UdpDT0B`Gpjo z&ch!wpU3=ZRwwqDPtmL{$9(LuKCi`VgzI5v!7&Q1LJ9)#xMIxkc1X>|e~{9yXT|Ot zmw=55N8$I!0#gK1dES6iULD*hPjzpT*4aGqdNO4c?6X2LiVrsCr^}Yo3h0LWuOQT$ZYM0WyrEaEJPR- zV@U=_or0reI;XwfiCT`7>$#!$VTBn3C8-hk)_^tNpU5rpSc6{VSeM1V1~Ht|N-x~% za-^l0XC8+^Q0GPRvC(CiXM!s8R+>V1AOYAwu2H_Zvm?l?Cz+D1{U(+ljr+6HIj&<0RwX2N6%8$QFjr$YR#Pb%fb0>=Yz zO~ZSZ$j#t>b;zNV8G|{ZE84msPAE&ymrJ9aNdX_DHH=IRB0P={L15yC05Ut&H#)11 zcZ`Z73BclePiGK^s>AOL0qpLr1@dYe*sDpj!^rGyqcd{0b3y=oW|waIZQ`^1%{&xX z)mb-hmq5d*@QON7b|=b(2H=IG=K@$#+oSPj(a{Q=dmZvQ&_2$kfznz5(4#4XCVQfq zqcRO$mciiJde48sHtKga&k+p3< zlJbt9O2$MR;Eh0dc`~yhraE-$WWvanBf;C{$)-~2olTcHur)_KIpU)%7B>?MdS;hw zU`e<1FXAPH2I!d{)W`UZjEThuijl{B>PtOWOuU9O*Sth(yTTE0LZp%7&cfJVLJNsc zmke}E&o5rTS7q4a2YofWbmaW7OoC!_CIMJv7-YHaa@UqZvl-b|mLd7@7&L`%Z?Om| z^MxZj`ZdB!{$}H_JOr~M%KdJIl=zdp$w$M!>t30A>IdKrk|CF1;;e}B{!=fDvub-n zl>&7qz~5SerGXdPk_&}*lhT`S71yGAx+@#rU0{q3b!jU;E;Fff-&LX0-xup`e~zs1 z%get7kO8=`GNcj-yL&y-9Lz3kpvwY1WHq;r}NMX^SK{xV`+Rqu`7}SwH3f5lr`NgWqmIK^u8zV$u3R#1>jKJ97s}l zcIA^{YoRn)w#hMdyG*!BWYB|{hn_U?f~|?G!}Az>vv{KXwHq#^`~kWH#??UR#A|v3ixr{Q;i(vHgM3W2DBIEy!O!-xQmLui` zOth67t6U2BBG1bxuQjYCB`Vn7ju$-fmj+)1D8)K)J_^8G#;iesG7Pm}Lb=O;wcvH( z43A4&N#xHJF5X9nQZqr`x2u<401`{hYYHefq)y>t(q|n57w#F(X&%EIZ|> z+9%`oVoA@jqTr* z7u8aD_rSVb`QC{hnA6}3ihg&lD7i3$@8I)w{VCvEI4rluk#+k$V*K=9!ZU56FAY|M zA%qtSwq8KIv(1YSlnO{N;;qF1Z$56qyk|-0v>lW165H0!RN^ z6jkFfDbCrlWX72d5Dc?x2|6w~eJ(8Uz!@#tO=2=OuanG{L*_?c-$WFM-J1&~53Csa zt~4pocx`d2pP%lrV^Vm`GjTxg;|#YZ;BlYgPkqdD$e0H_?DKs14|lFiyiNd$OfJ|y z77d&LOY>zZ2Zd(^g+(pRAWcT7MTulmcte(AX|mLUrMXXr0eCsk(p+CwA{qI4n79m? zo|r?R-{d{yaNHQZB08XLydLW{ydCdOq+bL-H8BOxJ^;T|x@IF#mR$~NoT_7qFNi6I z7=eR{aoF3IF48l88*d?I8rHb1&W-SHp z3Be1e#eVQ%%#xTe<0LhNcxvtNp^121OQzUY4u-Ins{LYF_rQWPs_P9EIQ?Brf_Q{v z(eWR)0RXWTY!Ikl%wOhuDz|WzISb{T83e)21-Jy^TysIk=X-T|M}rg&310L2IG#61 zXMW@y&l3=NcU)1kf|(Z$d^mkY;`oFxA+bNsz@)5ge@04sUXLcKQ_I9#~&ol@wOo*JAMbgmNoT_UZ*E0A; zid>P+CmevH*rCmNlIDsP2m_j3R$~Xu8rnvnER_WEap63Kh1*e3pa8xru6wg(q<}B# zi5h7+hNXI|lC!6m)w+zTru}1vT25p2J*14B_%Y9d?H47`17Dg9KAJ>Q1iqTbFv&&n zDdDFx@Y>hl-*EzpX5sdN)-)*`J|^26|5h3{d={W!7b~dDIe_x;$P6fwsQO7dsd3OUXb+ZE+~x5L4F5MD|To~BAE&+J}9yD7-e$8dO*&HHi*}e zFX>rXQd?cFw-(5ODc>dNnTd|7=?Faf-pq4LZNrc$GVW87O&j>dk}e2%*DTD-1F4-M zxRzN^E!Ji#f7ua8ctNskOA8A$4@^n(;IufLiL+8EO2~CPU@8P~io5~~TNSx)XR-Xa zejqk`$z#qA;2$7j%D8+Ip|h;^MH*kSl^f?|3ix84m9=)K7%%@s`{GcuW;+RV zL(bRNCDxocj15dwAvz+4)}Ac$La7e7m~qF66n zv8An(^5%b)%$asMz3KCqtP$80Y){ILuGPmI-7oGF42p8xk^wf1AN?mw(M)=eNEJ!u zE~!;BanA$}G^G<2PN=zQo@03v3`zZ&l%82HTnp3?D7+w8kXbW5l0SSxM?Ej>J1kZx z2ZcZ>(^+&#dt2d4UT_kO*%7pEqL;AozPt>e|O;P*%6uh{! z_D`t|H#xgA1$;3tkF9o(SPIG{*wF^hUI{5w?JGgfCA}cb9CN<%H*x@=HViD2Gn{zPz>N zKg)D(wG`%gpwWr8!cB%7x(0t~wvd6<=v}+Y!F@HfdVUzL!u{txpbI+bA&czmP2>bO z`iDOe+|zSG$(}${%I68lM~R+ zyk_p-ri+N7Bh8dVKMpep4Ke{SH>+3tu+X*(eGWVM0M`v3L(4ERnqyJDkL4rx5$^93p7L zpD28C2G0Eu1+eOm3Pek-&S3sVncn?bnK(Zp-F8w<|2G@bb1p>Bc-gUsH8jKQOqdVAOrgh8Aq}AJ zPOF_VX~`0MMvfE~=1X2#5uEX0;e&~WHe4!-rKvj<^N0O&f@Q_{hqL7I&M#GB3NCRN zzSG4D;2tKR5zL!LpB5xOQ(X57(7Q&@dcn1CfrGJ`QG7QGzv<;}I|wdM7PvK@sP8no z&e_&6)rkPnW`O4CbBpcssnf05(dJ?Kw}1IIur>Z0LjdbW+w{tkY$6apccxz++gEy1 z8?&c?FV34`-*G_vue})O%o14uyHIaGeivcZP_tlW3e>%^M8%j>oWI85*Rs@ zp4gcQaI6FcYj{D}t19;uTe$T;(cPKd)h1TZ9MK|O_AB+||r z@MI2d#B!wGx>K5=tkP)Iir11UxdmBLnV&D&#f4&phMkt*nY>or!qR^cU*Meg`y0>k<0sf`m^01F!&ZGghDC zisJ8Ma2!Fl;06Z-V}o)vSjC20S>xlDgAYEbpIvS-$8#FMpbLpR}oBXoVrl z^HMej%l2+z0SesHpwO~)J;LB%_V$6=i$=QTE@cjl*4c<^nsYaQnx#p39qx_C7ErkE zxqc}hctP^}k4e@q&1Gy|eqP>uxcWvIKTF3#@~s54+Q=|-%M==e=c{a<8(PH|{ zGv0tY-2(^K%hX@&G^xZSd~7V%Ox%1zJk2X!JUt-4c3)N8GB-nJ3i#qYMT847>|1v$ z->abd5|;B}n#F_{IDbwY5Au}`e<-2WlS&QsCI_JWB=81W@B5M%v*#sn_3OEZCT^VFTD{GY(RA5r@$PJh~E7m>@GRl92^j3>~YRgJzb&u?oQ3k9nNhu4n}OL7y6fJzlah zKAJJ)!ZCR^{CviyMnpsC8J*Q~_t)gXU}>X#A*)-yH+4WdRVL^l_<>vmnly+;5Q+O~P}e_n+Zu6!wbpuRL|Xgk z8p+VIy^R&{M+j;!Kxz-keEjBi{@zW5i=L6$WfahE!@%F9tz8IUX9opcFnU(9htEph z$Qj8SJtIy~b~*s80TTs!z=;3??*ZyX)YAm0+oajP1+2^(X_0l(C&gI5xFoj{(cck% zDkBepdSM98F(TlZU7GLX3U)~KX2TXCCks?|KV)%9Bu+HBh*xNha(Sm(pI3q7ePCP8WrqNK))=|{a;;Js%LcN{X1UVV z?)arK8JzM-S`xAMmb>0+o+sCcW)?JN-%xRL8na&m;KPhY_5EqEX5LMSfRIEoO4o?B zpa5nAr$7VC7ZxG)7d=9p$f@33oRg-70u8_eF#rE;piM_xPGAyZJB z?t@D-(swjFU@~znmd$Abp~=>y$w7!LOjNKF$l;STf9isi^t~cEFf31-=@%!$0ckcS zT*;YiOkRUBJK8D|WqpWxJ}&uk&bCLILe(;C6w0hE8!X>+sV>f!jNCjB%Pz32Aos(V zgsy_RzEw+$|SBH6iu&|ZIjoZMYVdNsb@q80n#Yb^sb|Hn&!jbn_gI;FT zB8car6O}PQ5et2NMwEJ@Pp9@18-XdjlWo((Nh`Mmznd*~cE(B5R;JO%MzMyy=mJ-cn`&bTqoXbKe?C z2le;F%T3bMIV$@haL>wi=@3NbIwKlP33|-eUiJe*Z8j+ee8zK%B_*9G8_`ir*H zWD^)X%Jj(IG}199<{-yy9^c9w92|Iu!1uj%0*uBTimS-%g(<^W05atm09&d_zVmi0 zN(-UY$tVrcsT(ZLx-NQaS(qPP=AGW>mlnW^^?1ved~|=gaySxvq2K9_CvpAdfp5u= zD~T(uLebzD!twZ$HxTB8=dRk2Tn|81**5Q%z%c*~$G{|2mTAR+7G|&&zz51j^>#ur zWmpV%SdD&}s`|9TM`kTqFP1f%uPAP**e{Y~7{j1^dyA@q$hJN}qRJ(02t?}ZtfJ=QhS zW~{|;jr760$_SjJdEo!FuqYQ49;iHk9!(K6E0fReI=#c39;UcBAOgloS{oI26T~3! z?rLo#a)+lu?sV13wqUbJ%Pjn^f)m`$(S2KX^sNxq!>wWRX}J$G`4+`DIwqmHMO3<%Y7cXVEi-xg(^j(!6Ajp%09>s= zu+%lobC4YcIxfMBOPiuWd#p{LS!~fQR$7+zklVSlFOxWt!bag%!?yWDDsb$t(Jm%H zOm0R_C9ZW!RNW7hGjFRD6+R{-?s9E_O^V72%&=$&yN2xEQX&oQL*hdpjZCorW~ZfY zBuAQ^IkG#WUw$R+w7fRAMj8V-Qn{uO#OFf#(F8rS@1z8?pwO|gJXbmfCgoDssC4#D z%B0VbN8Yg!*X`hkslgbK{!5N*gIYgde#s@u_ncS&7a?-{f`pgh zmAU~f6JL=3E$8X=LUxouaIEL0OW=tZ5*6n zg-9`S8`KicVi#-8DA{NjWowig9m31M>>455489V~ZxVR@N8&#NZ!O6H>m_ZvNB)iDaoMGgNNw4vjtjJcvAKa^G8iNtjtRo)9SoZ52>*_b|n9qIBK+n`i|rF_WIDhJ#RQs(GIF4(xB z{(O}0DX=Z069u6D830|8SZY5gmb?nsa()XX@DP((P!jw`>P6N(jLs$a{zmuX7T@>7 zl;Px9Czut@CsdLb)PW4Sv2keGO42t~R=|1_$!Ll2ozsYoR`LBWV zRI&+^j}Hd7tDSs^KSqkr61y^9;z9~5aC<>IJlJyzNtWj~ zuFw-r7&i;d5UlI>EdHfoGPB?NWh0ngr~;?{NkZ*!YQuJ;c(-9I-YrLtzNRc4FUyXO z$ED`t-^*0yS{e0hl+nB$GEs87?ATH%7klBW5+5@OIvRn`rGr(7iFOR`u%4N%lHCO} zvSIW!nUxJPkg*kIL0MjL4_wzm=@gMyciJwKAJR{FWjDHK{qR zg$eH}W+Lm73{V6H(tnxnLl~e-mW^6o*Q<(T&|0inm_gLfgv+&QN0D^T9+NepRs@Hc zk=miBB{=$`Ok~wcf5Gk2TYA3?XIy3v)69WjdMy*d+XQi5iGCLqqH{2JFQ~dr&Q96k zIxib-LsDVy10c>|t>OUKaTR%aCCPs3g&ECL&}#!K@Rn^K6YIu@#3w(6w~pMK7X4+ljH`H0O}oVCzl z{jo-HTd-J7R0f>*6|YT6E9R~`IMVJJ@~YDOo6DGeS>SWSIq&#eB=;|WsLKsAWomPX zGqu`jwtGy1Aiph{an!pPyBNU4iU{NuP&g||)?M!v`QdkxTxnw}qkE}jtxUn9v({{h zk@3XoH5@Bj5BgdZ?kJJHMeF5MV7(ll%$2F2OQu3;GGxt>5S(GVeKT^n-y>UHn`M*gl6Cz* z1NiO0q>gY$h+UU8b4fC$J0xQYa=D312-pgc3(bn#09(!qj}m<_B8RDgLV3SEY-mrQ zv%#(o(k;yE7MU^9Axm__gGz?9gQDw{O6dv}ix>Iyk!f+bCEeqeiu^3eLg*hWWLjQd zNKPJUkm{Kh4VHdHqoDFj7EB$oM$gHbOOMM~&KBvcd`t#%cFC-(5R@Z^5@X78tC6T^ zqc9mzPDu*dft7X8G?n5%yi*4k^nxa;45gvDo}k!**&W< z1h-ThuXLT%@$_7axE)(;Fu20ln^OhAygcXd6?~(0M7y)20@RI=Na#)=GW!ds`{h&j zuelMroNynP1wM!NNT1xw*}wx2OpZgFdPLbgxqJ_IzCy7ZXS=osgT)VxHFq11(mfJtcw7aK{-uPx z!?F)@z5+*{bWS*B!pN4x#z85_+AWoV3z9q6DOs~a@}RR-9&-LdX5DGh=`WQwe~Dc1 z=gW{v*Hn@N4xZOHzAi=CN;2nqq-OFjFw=*`?i+{K6dHz;reOlWYc>$f3G_acE})oU zKu&1|^#W!lKnL@+*1oKiVJM-Dp-2nL((h9l^7$-^%V4xv4HIbs8g zSj!Y6tUVVLW`+t6No)J-vR;~SJy0{~2R*f5E3Sm1Z@%bWS0hH3$-qtgnF8G0MMeq zj+C7RV`Br@aqRlMxzaoec5}rp+4H^+ioI-S{BH&FPXm;@>VGSmP~-zxJ`t=tUQ7Ys z@*}mN#Q5~EI?@XtyI4HLe<%xzFF4?Axu3%4TU*e~bv5%IRSNXC}j<@%7&dH=|O@^*JZRIzNA z7qmw^Hb;JeSlufm)j4TyzeoIU9fQ0s3E*4Mi{%d#?0&4JrDBw?U%qg3353nD?EJK0 z+4!&uU3yhq4L_1C{fA|{g%p?zl$8t0CLT~z9#{mxSQ|j)4{;1_n1lne4j{O})hrKS zs>W9yZkZD^6i0&~+No(t>WxVQ%_3}O&AcQjgr)6NFb!q~l``fmltDx-9}MN9xh(Aj zn)Y^1sB&wH4rUv473RRA#F3T;u!B)K-ZlNhbBj(kD_GWW1=rNOL#ln`K!jPX;W7kZ zOz@EvwiD(M8yf#kDm#86;~6#5S9-T}7r$4gokb`E$ic^Kq5a=7iOg6+Sn23-S=aK< zpz0tSor6pj>|JgtZwt|o9^+#Mu;rIRjamYn9ez=n=vNfZa=9Wjc-H(XcTbG;>Em`ZrA(Tiu%r882^Gp9h*$`x`#(0}DvZ|N7#?lSlT4!JD zIxQy#o5dY#QnJi25cJXkmb)uzy?5Bc1HwM<%P%jH~8hO~@lfYx)t<4i70GfE{Z7ZhDykrZTSiw8D# z4i^mX(G=!~@Ene7(8ixX}cb*vLx+78*#^H)&%@rn<|=3&Jg z8X<$a#fajK$5@e-3u_awjwb_Y(B`zts4q<}Ojbzebe3GgZzAA?FGNKC1EuQ609c_s zwq;A{|KHx1M#puY=RJ2;U7T4h+Y8gT+~%!Dp@ZjYu1R{!J4{-i;iAr^W6>g@=VTR_1`ItjeoBtx}k> zIB(-Y72|InMZtlOXg-@1c3W|i$#>pDVwyQ_SxZ0cmftxJXH7kSUOix$sfAgp80C2C zC<6}``)QUxu8v=LLkRVhslJsv>A5VII0l0&yw$Dv$$%Y)l-=-I$KX>2kQW~&p};6Z z>Vt5oOfOLRFytw9t3t;_?MH6NxkJxHGg%GX0V{JM%ob`^+)nnho2f<4Z6q2@f{re^ zjjU=IrLoJ%u?=HWMFvLw3_pppJP$+kXM))%^<~pcT#iVP(TmgM#N-&m_PjaY8$0L! zapp}%>|!0@AImf|`9U47AjWK^D2xgKEVJR<*8+esO(hgMK<1zKFBs zzr){XmK6E zJa)YImoOLZP?e&+$&aP`0C(07&z=5f92%k-o7d#>SL4!ij*{YRUsW5UrZe7?^T=I>Jh2og`M0H!qIiH+Gb$ z_B$k*Jt^?nxXN~v7s7vjfB=?s^Y=t=q3LSmSFgk0epbzH-TvN1@ZJVGKE%T_>cGpd zF*5VIu&YIDjlLT>m&qFE;G&PXf}nfld<5Sc%S4muf>!vq4+WHB27`67Gyt5TFEe6d z@lmF4jZKZ9j|?4&TnB=hb|-ZrOxV)A0rzgNz^~r!MDOWqXew}##Ur)bLt#`d`VS== z@r}QWtQeS-c=x+7XIGPSwJ5a%-q_O}|IOj9H`V`n@`tdAUsvaBqg=q2Fz0etF}3pr z?fkWA^h||x0iPUOtSy^J8Ky%?TyWGIKi*T9i~o0~Ul;I6FBvuyjxw2jh^E>y?<_sy zjlJJq-y}sct0z}+R@SJKr@D0kpJ<2inFOwU=R4T+SBV>nie9dRYx@iZZul|rxa-@?=@u8dYK_w7G%&ESrRm*7MvD|i(Qc;|*4wI1C zTRvNLATl$9z{C{7Atp;RC1jeVN5mgDNf{+vD*7%Cp|^Wj%S972WZXtWAVJGIuAru= zh|!e}oIiC9Q{*l+)9#;TSKwpVy{v_NwrMojt}^Rx6fSC#frK5gi3w7mh2SDvmfaFz z8cGZ{YKB%b`=lmmqt>Y{BD8^vN;Cs|lukuW0<*~u3+E)C1*in@B*j5|iYqk%JjRt` zQprP?sTyyagp|94l&QJM3D{6TOO(VPrGkBu5T8k3WbNiA^mJt4t-%5glmFQ>Nt$DU zojytjc}(+N4hHEsC@Th2dHZo>`aDhS6cE8P%9Y2qdLKUeU>!flFg!fXg@p-^wHB^4 zjYYpHg}W8SQJ@MNi|%VsQX7~{nK<$dm^S}`ik!tYBNrX$F8$-@7k{b#$JhTF!%=$1 zsU_=eVJb_M-Z)DxHZFM^@ zv6nzX0fDQJW<@U6_;9wevVxU`YCW@C^FkIaO-iT4LSgN5bxRaKez_f21|~^TLk>ya z_>$|#MJ!Bq4+@!BeT&hQU2o#K_Lsrs*s4H}9&wsRZFszLH_e>1iO;oAIIg}O5E>Xj%^y9hI%*nduTFN@ID=zG)N9}Sdt7_&1;nYPn7E?W z)o3PAc(PoL)b?n$SaV}8kGW|R64$!d+|{BE1X)-&&$8{&MPIM=k3t5qIw)qT5+wQ) z#j#|Nl0|qQ+1&IoKKMW*zW>r$3{TBaGa}3oh~#WvyfTFLPL&jqB*msFM~gHg@%AU` zY6&zf1H{!}gzPV){Uf*%=NaOl zMEeWT#L6-9&lo{95%eRQ6kQ38{!2zjoDmI+X3higpQ13{t5su|{Y84ANt<9NeGah% z(J9LgoKqSw#w2(L!M?88%M^(`*k~%(B1TtPnPC|0x9C)SeeKp)JeG zvg5J)YB2f28H~`(_3(~L6f=-Twm*E5G-4#8{zOYTNxrE*r`mWvl+p*F^t?)+JAJgP zxvoX?V??TY?r))XzeskNN>$0J<2AT}CSdZwIv8lPo^k7(KO=>Bj2oW;GtrP57MeEB zbG=%K9J<}3T^RBY;{xB0@YOMXjS;pJG&wV#VU>2p7#EQZE+6*S?prkUqx6jpOp|nD z6;s+w|F7G5V_Bm`2hj0{kWFtZ&sJY~cZk=aJ~7KxdT}Ixb62L+#){iNy7R`XZwW!V z>YI>JSj;HRZr#8qfi4O)zp=yb;`rI$N8a8os_#PwU@P#FKhvqLqU9+Pr{)o5(sy*+ zkI{p#P*XgH@DQ~E-XOX`Pv*cgYoaMCZ_n-}X0*DmY`YF1`tui7xASs)@rJQBP@{Ha zuj1BNu2Ue}swiH&qV@zRhZTCBeV7xENSs^B8|}$Q8u9Y$m(Vjfg&97;Wu+%YXC<9L zdma&}#N;UE(g>?GcvycLVkF!GBKa#PCaWbN+-a54$^E(;7jdbxA0ae0iQLmNO8B;tNx2uRyP%%L=*iW ziBJNAFTRa|e>nsTeMYt%vQ=n_vd^k1gsWx8 zTCV4XUBXmS%U3ZHy`+xPo1ng^r}zI*Sy|k?k--*eZUS~C4ioxjX6x*wB7_KS|79f} zJbhpjx=1+PPd}8r_l-_#j`>iOpeG9%o=+jLe&t{XN($Vw5BY2d&3mklz;p!%{bBym zQS^+N&}Dv{&}I+D)5q4vmPq+$e4Ivd}C`EHNNO0B^QJ1GVZ8 zpoxrf8C;b|0GH2F3$VA(Pnx$N9(A6BdWp1at`gO9@1Le}dfuCXsp?}$^u12dqy|j@ zTU`@DFJTE0lk<8ut^fDW_rgPI+B1KTulE?_c|>0^Db$xqh*>zQ_PUK@)VOFHq)tC>bI)lt{*Y2Aq~+@H0znDk(leZCO`HnwkUI&lnYY{ zbuu!it)^(E)C%%U!uu4 zXa;@i(I(VXdud*c!A*0ZldL~8lauHiVg8-^Fe-88ToBvmAY=-JF@QdyCAuyC%6Cd1r3GRn}LSa#)ye9oI0MVW~XQzMR}l_b^`P&0Fp z@ADwPw1|E;Ql9Zz677y_`xIupzMF__<`pOlwddZUDS~+vRW+3WwbS^?=cu99s-}%k zrG8Vns}*zELu&le^AuXT(`!;6#_A-ua{mGm`e0&pqe$0YvaA#~qkp&UDdad7vs9hG z=EvoMX=_r={khOLO|D-*TB_0y z%6iAMmhDqU1vfP(_ohm9;&>+)iYf25?AWw|nv&qO4lN-M?_v*p`#+NA-ub|9xfjZ7 zKh}a9Rwls1tyS*^>&!m|We9k-A?tflCztZ%Xy1?D2# zihO?J;RYN$as?+Z4r*1`rRJVcbWxFkpB$=_L29pa#}Q3SG#n?B*d?fDngDpYFM@96 zA^383qkQHF>W+Q`_Us&7DfkeHro{}J&zwN|8(HBXpJ@PMBGj}1uFflmU(w8?hpi9d zgt862YN6Jz&zq0D;sOSl%;sDP%TQeGrMFlUFbJs-@GYhQ3^EBc zTPH!j1XAtYn9rc8lrM+H$4>Isz7`+8`({s)t#16;%7@5cAdKVPlXnmB$;>u1S2CAXz*Jg}cux<_vHH?07EOf@X9*NC zH87f!PWAO_GAN@& zS^0+O*IL*#|KS`6xd?zczI?PF@4(Mq@1y@~6EcDYIFK`nhVCDs{@VA^m%S71nR^l2 zuob5}Mp^66hBD?6MhT+hCNKWc@(ixVX})GL*2LnMb>YVJW!lhK%n<5zYBj}KN_CDyy)YKk9c?O$ z-PhYk@N`?Lnqi+`=C0E~*Rfk&s$1TD_aU!s3q}r}fW?^xQ{OsFOiY|vjN~kN>XUTV zr}z-jF%BhfgJP;~QR7{m+-nWM$A`7TU=T|k16$Uy*(rj?Y%`8g>(k|ESYk|~35tKO zrjnuhRrzSC^=W}HCof6}x{*banGU@UZujzOR-`xQAskL%v?s;_ zwmI0?@HFb2L)dWoWwbe8#Po%7@&h)ar*t=p9^8opZ??{O1txPWsNYb;NX=~45v0#p zw7csfDwi1c2mY1JU&ea$Y(MIlu>Mf<`*c>?;G8~1aY`V=>;faz0V`z>D$3|-RlQ6L z#DYS;sqSxVw|WW4f-phT{D0W`+o&(RF(-0xGK@3*Q?Ti@YK7@XuPMvM2BsdYR}<6g zy$$&|`Rgu?3Qf;(g!ScQ?<59DV^&eHij*2X2V2K&bpfBro~4w3;Td)6>_x-^WLwIVSnX{$GDY$ z)cqLrY}=!h{pJ%;saf4p_ZT0@F@FGMpLv45y(gBu7}IqkEG_qwTazKZYcQ`#bfjhT zJ-pJFh^$N3K&c|YmH@210XCJ<|hV*4l_~{pX>2N1HI)|C_M>8%T z_yUq)e*Xq@*90!DTmjPz1b;9LabZMg<{kDFpg+G9K_-@8nR4Q9F1O*Emp+2$dUvqo z(i>R9q`)1~9)W)_txHDk{*=o0>#|G8huCJ z!XVv)eZ$X{xoJ|l< z_c4tAG~$IYEfgOv-Gpy_=qt#)&aXEwqN{^J_43&JxvBHtCwmu7GB?YH*4mt8o38nH zUtWgNTA8h$qB)kiLAsh;!5zGw&vs6#&DH76Kh`ynHEgVN%Cko@*&Ry#*S=1N&sQ<@ z^4l!?MiWc=Z|9V!6$^%#y3mHY|MX`tr8yCNxj|UBJ%s3+uQNbp=@s8{`)S|P4`yy^ zq^Yywrb=y-$Ba=%7D}OwbRJmDnm(F1Kl^wKPM;gV1qN`O=^Ca9G=frs-c{xSMyVaj zN^!X+HSDCtiHehChndK5!^wQNP{j3nIOyAFE4LRG{!$EOCUz; zPLyd2pRe18Ki>NVG7BwVQR86yFvbInaMroPB<^7&wXiIQ&K*;p#o`TjGOgjCkM(Qr z2eHni+9c&@l2P1mb&i6-m+Ee})OM=^J^_akc?O3S4EW*|PNnBzS+uX0x^T*P;xFwuA+FeMS!dq0a`)4}pgmoqjqO}+@_mR^{dJYLrIJc|2X z#Yo;3T;1?d^m!kk2FRcU9?Q(Y2OEQO&R-s7E@KeSd~`8m|9hRM^8-s4nRomd66gOx zO?1CR(;UTQvBp#E_Cr|?YcClrfi`JgtT**nJMaLL7U>Mfeh zVcy?J9@v}ITB~WrAdAa@pOk7k0yO0wmEfMYyC(3NU`%z~B%n^GSXK>uG6+jnwzBar z{tGK0{15fo|NSZ1SHi4xzWhaz&Vk2gCae(y^(x#}mtUdwn)Ir)mEX`32- z^AMBSC8!|9CXta0S5|7bq_{(RH>-7S17u z0*|K{XD$w)izYvdo|WaC78oW8K_t_oX@QOyt4qvGVSFYN7Xn_qbhR4wc>(58b)(vU z5!F*aK+Tos5VRFw#J3$o`MWUYZqn-i1zE_IB?OspEWjkeHv);NHu7&4l;A>d8#V;K zPye0`F-B4<u9{j<>B=B~nTiVNv+m;Pe z%fD4j`J2_mrGFwR^#uYT8D7jxnVF+*TV_w=>je^s@!AW}m*?fe>!I>{@Q3$2japw_ zQnjdOFrc36og&e@zVHdT5Nr76a1=xmb0bgtKruAu-n zR@{DC-|cnkO&BQK zkALW>!NV<^aR0`<6t9l?qov`!c&}nA*bb%l*J`5g5Y%CsKVvgQectjKC+GZ-=HJtB z%-ggJ30RR!Ox}gRGs?wGA)jj>uiJ-D)jx>c6+2TF(m7I;^^AvLlZY}MO}J@yaj~d3 z*wB$b{PDav{l9J6K~)i76%$^1kf z*IZbGiv!Kr9)E-6*bA*292u|m7>m(nO?04s;yk_-^C3UF8|v8SSOKA$@jN2!o7iaT zRW>}Lm`fgjI@PJFgYU2?@DU`Y`?xw`6$E*)@G#4EaI$M&1E)5zIL)tfn*8-U2;c;{ zsGVh(z5ds9{>^0$#~?4M#$cmG!Ag_3iyXl%?jqb*u><#2?nF(_268N>4q(D7`-`(f zS{eh{0y$u96_s@0vX!5!(4CE}AYxnPgEHw+mfoPX+5;zP04M3E*M_|GW=no6=jmrB z2l3?YQZ;jlDkDOCA7MndC7$|qFOlMLzLsnvs5CvS(t5R9bA3wD$3KmN10N#*zKo$) z-#~!TpP~Li#8{d|R+}aQgs}2!s)jsV<`X;x;P{e@MJlJO!p0#4&a^>imKMNSR}Jq2 z_rUk)Z;+mFF-yXdLb?fGnu==_>*h8!*4a+YHwE?;`U~jzfu&{FO&HzEhY%jm#)zu6 zPe{;7+ODUi56aW3omo*Y({$lVH&Vk-d=1vDEONZ&VUX9%vED(b6Jcc1_nOB%!Bb3= zu*SE+6&^yhr3bajMHD%v;kBNJcl-#@{R0A62152c_&xRTyID%eQGsbksbN zVc0j#no&Lj%|*qy*trKS6Gs`(D|+pXH+6!5BfpfeI(@w3r-*d_66Ug9s=4_oC`GL# zBTeC2Sz3~-`<8w_C8v?~BpZSH--0PLqN?N6zWrB8dBzeoVXpYYjPBFU(&`S8@?KG< zTr87pUqaB??yX@pkQ5e?DIf604aH|GC5T)MpenOvqBgr2jlNpccx#c9>EQxpbr1itHruAs1j zsXHnu4Rv6-_(-$!*FQ0yi&$;=*9|&-f6iRJs7mU?%#{Jm^mJ*j@YsYFl#-ALLx#nQ z`O?htHdgX83MkrH!8*h1gQL0unUy7Q)mKx~YfRr$Gkw#O2L>~`X+lbAHBVWKsp&d0 z+jI^`PhTX7z}q7+^%_eT>2yixIgDoNJWGDh=YH0%o5Cs81F_T?f)Q%4g5vxvW=K2z zf%cgoGU(%SMng~-2qiF8=82MZhQO3D0$-vZ#pr{NHU7k3r)eVss4Vmv%J9-m>P5(w zOP?Xhx2@Tj$?#!jxEJ-qKVwN=0$VESEOL* znsevEEL|&;MV&AFgR)@mp>`iE{FmuBrSG<%3{45KA>Jby1fx_RLJP+}AgZ+&>ZK`PAu8VSf&$ zbl5W)D6o!g-GOiM*kepGpHk!D2*HkuGBvvdO7#20c{X%@_!lUM%iezvrR2t% zbgA`cY-LEmkic3bkXBP?@_|@rlFC&quH;)9TihH8h!6grJQLm==4zGYi*8)ErC}UI zK06s+1f0z4q)}WCdNOL!`@|e7Ey^I2D5K^=^y8@X363$!XJ11#;?yt#Q_~n@A>_fC z8XRZEj0F8&+14QPF^YVJufzb{i3wyW0c5Jw9#wKMf{V9Q=0cy9_|cTSYM6`ffvIXA zwZ7fDd`H>@jDHLX7!pXE1a30$rET0sM`@IRo7LLeybN|3ierM=?db+T3$>i4IxmiO z45V??`nnPjl>ep0XlW>9!hJz$p_bktR)z?x!biyd6J^wGghi19{%Q0D%5a(AhY8qL z3kw^AnxZm^&qV(>r1JZcz$bwl;>#5qkZ5;hbEeJG9YA*Zx|(lhXJ`CtNWhRlG6@*K zmrO!;$?r@vQ`&qMMta85uK9`czN|PK)vWH`L1uTog*nrC3WR~f!}3ZW+FeE9V%o)A z1et|FS5~cRJ0X(e6%y=(nBxgzVfqOp!5NJEqbM2s1+v1EG;&_&%onhegmD(tRkBN9 z-msg|yB~&<%iJ&P`Z4XNQ#M9lh6L^w2^he4x18w|=ILVW#cpbTZ!yhbjAqYtxtGQ1 z?{;ONzA|5zz4cM1}+m2_%z% z0es0MbQk|FT3(aKthj9^_2gI_(-QG1Zm%`SL@Q53&1?SywX8C2!=ckx5hp4MpXYiu z0o?}r7=<)DPId@AO&D56kcU&2PouhRJMQ0HM6MU384@rgaJx#tFm>LpXYMACo1mwj zW;vs4EMzONvDTCaNn{rQeYay6zkcTmu8pvA0|8OYp=$xwrNkm`I?|KkcRt>Vq5?NH zzW0MzmfC*dcQRM9biy<}iCTLYTWX5aJ-mg7Gd>#(atHx|%l?FV zZc?;AM((dwNh5^VtQL%q1#tM}HC*f(!PsNmb!8@mWaqjAvHoCQ%K;w+$6tI|ROp^c@R+d4IO+iJLf*O}uk@|&3GbCV0 z;LehO0epAX`TRg;(-TOj9a9Vd3D2U+S~Wn?uPg++{{AVvc&Gzi15+A%y`IU5IkU1T z8{0P)qoKx2zoh7-H=>^Q4gV1>k5*7rI!&l@nc&n@DqhdPjBO1G7!vrvC13#G2Yw3f zi~&gA-xx_PJEr0oV&XdkKsBgY3kcfDpglYs!1rHz7ya}DO7Kf6O^R98kRt7q`!^z+ z<*q{1Ag|Z-M7xuhxDuUID63pdP^T|1%K*GoL~LwhNZ_`XfB}5B_367c2T!^)wTu40 zVQPSrq&^dX5zJbRA25?u+fTjQj~~3+t~nEzs=}~P3IcFq82#Min^9Kkp-*pd1gB_r zG9CvLdGhGPD{+_zcqYZVn!znRu<_ZDfFXg~Mgm42-)(cMZl8hXGIt<1&x{})X4L*v zp*|Z5B@kpJsF*ROX>a@|8Qz26xJ{aCJ`-6KuKUokZAsWehQLwE&(qu{;C5fFAcHSJ&P5K4V6v$7CN#BJ99hi zxNl1twzibODuFWmUMjQa*nk27yG#WcR2hwc6-{);KZXSES_v4ych{c!4|d{HOo$gV zs1(0tdIY2rJTVaws%Qd+^7nibh%*z&68zyHlid%V=s}P`C@?7i=OBS}UX~r7|5!7L zu(MetHjXTQ@1gxNKZEh2vluzwo$+o+z>vUQE&&7h?(z%ZR++wNe={uHCuw%Gz&Fbf zBif)O%ZqL&nxB|5`})Q)9SFg0v%p4x%cS|!%OIADLZ@OE)zN5%1Plon5?Db32Jo#Q z9OEZL0)_+(2^bQ%^CV!bkMF#5YRt%xfFS`x0)_-ukbnVvD+tH<$&i2{0Yd_Y1nxWu s7{GVuol|2*h6D@=7!oifu!02sKY8z97Hk@I*8l(j07*qoM6N<$f_Q(<^8f$< literal 0 HcmV?d00001 diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst deleted file mode 100644 index 43aa0530..00000000 --- a/docs/source/mvBaseWriter.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvBaseWriter -======== - -.. automodule:: cdms2.mvBaseWriter - :members: - diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst deleted file mode 100644 index 3d2de85f..00000000 --- a/docs/source/mvCdmsRegrid.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvCdmsRegrid -======== - -.. automodule:: cdms2.mvCdmsRegrid - :members: - diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst deleted file mode 100644 index 057ed975..00000000 --- a/docs/source/mvSphereMesh.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvSphereMesh -======== - -.. automodule:: cdms2.mvSphereMesh - :members: - diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst deleted file mode 100644 index e8c41c17..00000000 --- a/docs/source/mvVsWriter.rst +++ /dev/null @@ -1,6 +0,0 @@ -mvVsWriter -======== - -.. automodule:: cdms2.mvVsWriter - :members: - diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst deleted file mode 100644 index 89fef4aa..00000000 --- a/docs/source/selectors.rst +++ /dev/null @@ -1,6 +0,0 @@ -selectors -======== - -.. automodule:: cdms2.selectors - :members: - diff --git a/docs/source/sliceut.rst b/docs/source/sliceut.rst deleted file mode 100644 index e14aab4e..00000000 --- a/docs/source/sliceut.rst +++ /dev/null @@ -1,6 +0,0 @@ -sliceut -======== - -.. automodule:: cdms2.sliceut - :members: - diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst deleted file mode 100644 index 8fd37354..00000000 --- a/docs/source/tvariable.rst +++ /dev/null @@ -1,6 +0,0 @@ -tvariable -======== - -.. automodule:: cdms2.tvariable - :members: - diff --git a/docs/source/variable.rst b/docs/source/variable.rst deleted file mode 100644 index 8438c35d..00000000 --- a/docs/source/variable.rst +++ /dev/null @@ -1,6 +0,0 @@ -variable -======== - -.. automodule:: cdms2.variable - :members: - From b92460f556338ee191adde615ae46838bf1fac91 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 15 Nov 2017 09:51:23 -0800 Subject: [PATCH 028/239] add requirements.txt --- docs/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..7dd06d02 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +easydev +cdat_info + From 96a258105ac4eeb0ef9cfe88d48f4cec92a881ab Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 15 Nov 2017 09:55:34 -0800 Subject: [PATCH 029/239] remove cdat_info --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 7dd06d02..a662e3e1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ easydev -cdat_info +#cdat_info From d629683fdb0884e9f1cf1d42320f12c2a37b8e22 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 7 Dec 2017 12:46:33 -0800 Subject: [PATCH 030/239] remote cdat_info --- docs/requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index a662e3e1..e48f7c2c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1 @@ easydev -#cdat_info - From c53333185023b320cf9cb80a2403ce0052fa2be1 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 7 Dec 2017 13:02:17 -0800 Subject: [PATCH 031/239] fix latex_logo png --- docs/source/conf.py | 2 +- docs/source/manual/cdms_2.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4b1b3e01..74d19e1a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -273,7 +273,7 @@ # The name of an image file (relative to this directory) to place at the top of # the title page. -latex_logo = "uvcdat.png" +latex_logo = 'manual/images/uvcdat.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index b42df836..253c8098 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1109,7 +1109,7 @@ The figure below illustrates several important points: In this example, the database ‘CDMS’ contains two datasets, each of which contain several variables. -|Diagram 1| +%|Diagram 1| Figure 1 From 0ca4050f4841763f608a4b50f87fc28376117595 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 7 Dec 2017 14:29:59 -0800 Subject: [PATCH 032/239] pin pyopenssl to 17.2.0 due to myproxyclient failure in py3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7ac40982..3131eadc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy=7.1.0.dev34 ; fi - export UVCDAT_ANONYMOUS_LOG=False From 263d814619c0f5d6683640ad97d357db047e186f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 7 Dec 2017 16:26:12 -0800 Subject: [PATCH 033/239] update TOC --- docs/source/conf.py | 4 +- docs/source/index.rst | 10 ++-- docs/source/manual/cdms_1.rst | 74 ++++++++++++++-------------- docs/source/manual/cdms_2.rst | 59 +++++++++++----------- docs/source/manual/cdms_3.rst | 32 ++++++------ docs/source/manual/cdms_4.rst | 52 +++++++++---------- docs/source/manual/cdms_5.rst | 32 ++++++------ docs/source/manual/cdms_6.rst | 52 +++++++++---------- docs/source/manual/cdms_7.rst | 28 +++++------ docs/source/manual/cdms_appendix.rst | 70 +++++++++++++------------- 10 files changed, 208 insertions(+), 205 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 74d19e1a..b6ecab49 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -92,9 +92,9 @@ # built documents. # # The short X.Y version. -version = '' +version = '2.12' # The full version, including alpha/beta/rc tags. -release = '' +release = '2.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/index.rst b/docs/source/index.rst index 860cd577..bf9642cb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,12 +3,16 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to cdms2's documentation! -================================= +CDMS documentation +================== + +**Version :** |release| -Contents: +**Table of content:** .. toctree:: + :numbered: 4 + manual/cdms_1 manual/cdms_2 manual/cdms_3 diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 4b73df67..74707b8d 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -1,10 +1,8 @@ -CHAPTER 1 ---------- +Introduction +------------ -CHAPTER 1 Introduction - -1.1 Overview -^^^^^^^^^^^^ +Overview +^^^^^^^^ The Climate Data Management System is an object-oriented data management system, specialized for organizing multidimensional, gridded data used @@ -17,8 +15,8 @@ Numeric module (http://www.numpy.org). A number of excellent tutorials on Python are available in books or on the Internet. For example, see the `Python Foundation's homepage `__. -1.2 Variables -^^^^^^^^^^^^^ +Variables +^^^^^^^^^ The basic unit of computation in CDMS is the variable. A variable is essentially a multidimensional data array, augmented with a domain, a @@ -52,8 +50,8 @@ This illustrates several points: longitude coordinates as ``u`` and ``v``, and the time coordinate is the first time of ``u`` and ``v``. -1.3 File I/O -^^^^^^^^^^^^ +File I/O +^^^^^^^^ A variable can be obtained from a file or collection of files, or can be generated as the result of a computation. Files can be in any of the @@ -117,8 +115,8 @@ A variable can be written to a file with the write function: >> g.close() -1.4 Coordinate Axes -^^^^^^^^^^^^^^^^^^^ +Coordinate Axes +^^^^^^^^^^^^^^^ A coordinate axis is a variable that represents coordinate information. Typically an axis is associated with one or more variables in a file or @@ -210,8 +208,8 @@ example: >>> print t.units months since 1978-12 -1.5 Attributes -^^^^^^^^^^^^^^ +Attributes +^^^^^^^^^^ As mentioned above, variables can have associated attributes , name-value pairs. In fact, nearly all CDMS objects can have associated @@ -249,8 +247,8 @@ In general internal attributes should not be modified directly. One exception is the id attribute, the name of the variable. It is used in plotting and I/O, and can be set directly. -1.6 Masked values -^^^^^^^^^^^^^^^^^ +Masked values +^^^^^^^^^^^^^ Optionally, variables have a mask that represents where data are missing. If present, the mask is an array of ones and zeros having the @@ -298,8 +296,8 @@ is based, at `http://www.numpy.org/ `__. -1.7 File Variables -^^^^^^^^^^^^^^^^^^ +File Variables +^^^^^^^^^^^^^^ A variable can be obtained either from a file, a collection of files, or as the result of computation. Correspondingly there are three types of @@ -396,8 +394,8 @@ The datatype of the variable is determined with the typecode function: >>> u.typecode() 'f' -1.8 Dataset Variables -^^^^^^^^^^^^^^^^^^^^^ +Dataset Variables +^^^^^^^^^^^^^^^^^ The third type of variable, a *dataset variable*, is associated with a *dataset*, a collection of files that is treated as a single file. A @@ -432,8 +430,8 @@ The metafile **cdsample.xml** is then used like an ordinary data file: >>> u.shape (3, 16, 32) -1.9 Grids -^^^^^^^^^ +Grids +^^^^^^^^ A latitude-longitude grid represents the coordinate information associated with a variable. A grid encapsulates: @@ -463,8 +461,8 @@ CDMS supports two types of nonrectangular grid: However, it is more difficult to determine adjacency relationships between grid points. -1.9.1 Example: a curvilinear grid -''''''''''''''''''''''''''''''''' +Example: a curvilinear grid +''''''''''''''''''''''''''' In this example, variable sample is defined on a 128x192 curvilinear grid. Note that: @@ -537,8 +535,8 @@ grid. Note that: Figure1: Curvilinear Grid -1.9.2 Example: a generic grid -''''''''''''''''''''''''''''' +Example: a generic grid +''''''''''''''''''''''' In this example variable zs is defined on a generic grid. Figure 2 illustrates the grid, in this case a geodesic grid. @@ -600,8 +598,8 @@ grid to curvilinear representation: >>> genericgrid -1.10 Regridding -^^^^^^^^^^^^^^^ +Regridding +^^^^^^^^^^ Regridding is the process of mapping variables from one grid to another. CDMS supports two forms of regridding. Which one you use depends on the @@ -614,8 +612,8 @@ class of grids being transformed: - To interpolate from any lat-lon grid, rectangular or non-rectangular, use the SCRIP regridder. -1.10.1 CDMS Regridder -''''''''''''''''''''' +CDMS Regridder +'''''''''''''' The built-in CDMS regridder is used to transform data from one rectangular grid to another. For example, to regrid variable ``u`` (from @@ -648,8 +646,8 @@ To regrid a variable ``uold`` to the same grid as variable ``vnew``: >>> u63.shape (1, 2, 181, 360) -1.10.2 SCRIP Regridder -'''''''''''''''''''''' +SCRIP Regridder +''''''''''''''' To interpolate between any lat-lon grid types, the SCRIP regridder may be used. The SCRIP package was developed at [Los Alamos National @@ -697,8 +695,8 @@ as necessary. Regridding is discussed in `Chapter 4 `__. -1.11 Time types -^^^^^^^^^^^^^^^ +Time types +^^^^^^^^^^ CDMS provides extensive support for time values in the cdtime module. cdtime also defines a set of calendars , specifying the number of days @@ -777,8 +775,8 @@ or string representations can be used: Time types are described in Chapter 3. -1.12 Plotting data -^^^^^^^^^^^^^^^^^^ +Plotting data +^^^^^^^^^^^^^ Data read via the CDMS Python interface can be plotted using the vcs module. This module, part of the Ultrascale Visualization Climate Data @@ -818,8 +816,8 @@ The plot routine has a number of options for producing different types of plots, such as isofill and x-y plots. See `Chapter 5 `__ for details. -1.13 Databases -^^^^^^^^^^^^^^ +Databases +^^^^^^^^^ Datasets can be aggregated together into hierarchical collections, called databases . In typical usage, a program: diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 253c8098..17424069 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1,8 +1,8 @@ -CHAPTER 2 CDMS Python Application Programming Interface -------------------------------------------------------- +CDMS Python Application Programming Interface +--------------------------------------------- -2.1 Overview -^^^^^^^^^^^^ +Overview +^^^^^^^^ .. testsetup:: * @@ -65,8 +65,8 @@ Table 2.1 Python types used in CDMS | Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | +--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -2.2 A first example -^^^^^^^^^^^^^^^^^^^ +A first example +^^^^^^^^^^^^^^^ The following Python script reads January and July monthly temperature data from an input dataset, averages over time, and writes the results @@ -460,8 +460,8 @@ Table 2.3 Class Tags +--------------+---------------------+ -2.4 CdmsObj -^^^^^^^^^^^ +CdmsObj +^^^^^^^ A CdmsObj is the base class for all CDMS database objects. At the application level, CdmsObj objects are never created and used directly. @@ -522,8 +522,8 @@ Table 2.5 Getting and setting attributes +--------------------------------------+--------------------------------------+ -2.5 CoordinateAxis -^^^^^^^^^^^^^^^^^^ +CoordinateAxis +^^^^^^^^^^^^^^ A CoordinateAxis is a variable that represents coordinate information. It may be contained in a file or dataset, or may be transient @@ -734,8 +734,8 @@ equivalent to the two contiguous index intervals ``2 <= n < 0`` and -2.6 CdmsFile -^^^^^^^^^^^^ +CdmsFile +^^^^^^^^ A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` interface. netCDF files are accessible in read-write mode. All other formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. @@ -1084,8 +1084,8 @@ Table 2.15 CDMS Datatypes +-----------------+-----------------------------------+ -2.7 Database -^^^^^^^^^^^^ +Database +^^^^^^^^ A Database is a collection of datasets and other CDMS objects. It consists of a hierarchical collection of objects, with the database being at the root, or top of the hierarchy. A database is used to: @@ -1678,8 +1678,8 @@ database -2.8 Dataset -^^^^^^^^^^^ +Dataset +^^^^^^^ A Dataset is a virtual file. It consists of a metafile, in CDML/XML representation, and one or more data files. @@ -1888,8 +1888,8 @@ Table 2.25 Dataset Methods +--------------------------+--------------------------+--------------------------+ -2.9 MV module -^^^^^^^^^^^^^ +MV module +^^^^^^^^^ The fundamental CDMS data object is the variable. A variable is comprised of: @@ -2056,8 +2056,8 @@ Table 2.27 MV functions +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -2.10 HorizontalGrid -^^^^^^^^^^^^^^^^^^^ +HorizontalGrid +^^^^^^^^^^^^^^ A HorizontalGrid represents a latitude-longitude coordinate system. In addition, it optionally describes how lat-lon space is partitioned into @@ -2479,8 +2479,8 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid +--------------------------+--------------------------+--------------------------+ -2.11 Variable -^^^^^^^^^^^^^ +Variable +^^^^^^^^ A Variable is a multidimensional data object, consisting of: @@ -3148,7 +3148,8 @@ Table 2.35 Variable Methods | | | identifier. | +--------------------------+--------------------------+--------------------------+ -**Example:** Get a region of data. +Example Get a region of data. +***************************** Variable ta is a function of (time, latitude, longitude). Read data corresponding to all times, latitudes -45.0 up to but not @@ -3570,12 +3571,12 @@ remove the singleton level dimension from the result array. -2.12 Examples -^^^^^^^^^^^^^ +Examples +^^^^^^^^ -2.12.1 Example 1 -^^^^^^^^^^^^^^^^ +Example 1 +********* In this example, two datasets are opened, containing surface air temperature (‘tas’) and upper-air temperature (‘ta’) respectively. @@ -3675,8 +3676,8 @@ results are written to a netCDF file. For brevity, the functions -2.12.2 Example 2 -^^^^^^^^^^^^^^^^ +Example 2 +********* In the next example, the pointwise variance of a variable over time is calculated, for all times in a dataset. The name of the dataset and diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 18a9b365..c59615f8 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -1,8 +1,8 @@ -CHAPTER 3 cdtime Module ------------------------ +Module: cdtime +-------------- -3.1 Time types -^^^^^^^^^^^^^^ +Time types +^^^^^^^^^^ .. testsetup:: * import requests @@ -44,8 +44,8 @@ The ``cdtime`` module contains functions for converting between these forms, based on the common calendars used in climate simulation. Basic arithmetic and comparison operators are also available. -3.2 Calendars -^^^^^^^^^^^^^ +Calendars +^^^^^^^^^ A calendar specifies the number of days in each month, for a given year. cdtime supports these calendars: @@ -70,8 +70,8 @@ changed with the command: ``cdtime.DefaultCalendar = newCalendar`` -3.3 Time Constructors -^^^^^^^^^^^^^^^^^^^^^ +Time Constructors +^^^^^^^^^^^^^^^^^ The following table describes the methods for creating time types. @@ -94,8 +94,8 @@ The following table describes the methods for creating time types. ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" -3.4 Relative Time -^^^^^^^^^^^^^^^^^ +Relative Time +^^^^^^^^^^^^^ A relative time type has two members, value and units. Both can be set. @@ -110,8 +110,8 @@ Table 3.2 Relative Time Members | String | units | Relative units, of the form “unit(s) since basetime | +----------+---------+-------------------------------------------------------+ -3.5 Component Time -^^^^^^^^^^^^^^^^^^ +Component Time +^^^^^^^^^^^^^^ A component time type has six members, all of which are settable. @@ -126,8 +126,8 @@ A component time type has six members, all of which are settable. "Integer", "minute", "Minute, in the range 0 .. 59" "Float", "second", "Seconds, in the range 0.0 .. 60.0" -3.6 Time Methods -^^^^^^^^^^^^^^^^ +Time Methods +^^^^^^^^^^^^ The following methods apply both to relative and component times. @@ -151,8 +151,8 @@ The following methods apply both to relative and component times. "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." -3.7 Examples -^^^^^^^^^^^^ +Examples +^^^^^^^^ .. doctest:: >>> from cdtime import * diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 011d345a..71914fc0 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -1,8 +1,8 @@ -CHAPTER 4 Regridding Data -------------------------- +Regridding Data +--------------- -4.1 Overview -^^^^^^^^^^^^ +Overview +^^^^^^^^ CDMS provides several methods for interpolating gridded data: @@ -12,8 +12,8 @@ CDMS provides several methods for interpolating gridded data: - from one vertical (lat/level) cross-section to another vertical cross-section. -4.1.1 CDMS horizontal regridr -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +CDMS horizontal regrider +^^^^^^^^^^^^^^^^^^^^^^^^ .. testsetup:: * import requests @@ -107,8 +107,8 @@ Notes **Line #11** Reads all data for variable cltf, and calls the regridder function on that data, resulting in a transient variable cltnew. -4.1.2 SCRIP horizontal regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +SCRIP horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^^ To interpolate between grids where one or both grids is non-rectangular, CDMS provides an interface to the SCRIP regridder package developed at @@ -240,8 +240,8 @@ has shape (12, 64, 128), then the input grid must have shape (64,128). Similarly if the variable had a generic grid with shape (8092,), the last dimension of the variable would have length 8092. -4.1.3 Pressure-level regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Pressure-level regridder +^^^^^^^^^^^^^^^^^^^^^^^^ To regrid a variable which is a function of latitude, longitude, pressure level, and (optionally) time to a new set of pressure levels, @@ -262,8 +262,8 @@ returns a new variable ``d`` regridded to that dimension. >>> result.shape (11, 1, 73, 144) -4.1.4 Cross-section regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Cross-section regridder +^^^^^^^^^^^^^^^^^^^^^^^ To regrid a variable which is a function of latitude, height, and (optionally) time to a new latitude/height cross-section, use the @@ -290,15 +290,15 @@ regridded to those axes. (2, 10, 144) -4.2 regrid module -^^^^^^^^^^^^^^^^^ +regrid module +^^^^^^^^^^^^^ The ``regrid`` module implements the CDMS regridding functionality as well as the SCRIP interface. Although this module is not strictly a part of CDMS, it is designed to work with CDMS objects. -4.2.1 CDMS horizontal regridder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +CDMS horizontal regridder +^^^^^^^^^^^^^^^^^^^^^^^^^ .. doctest:: @@ -317,8 +317,8 @@ Table 4.1 CDMS Regridder Constructor "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." -4.2.2 SCRIP Regridder -^^^^^^^^^^^^^^^^^^^^^ +SCRIP Regridder +^^^^^^^^^^^^^^^ SCRIP regridder functions are created with the ``regrid.readRegridder`` function: @@ -341,8 +341,8 @@ Table 4.2 SCRIP Regridder Constructor "", "" "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." -4.3 Regridder Functions -^^^^^^^^^^^^^^^^^^^^^^^ +Regridder Functions +^^^^^^^^^^^^^^^^^^^ It is only necessary to specify the map method if it is not defined in the file. @@ -352,8 +352,8 @@ convexity, and ‘repaired’ if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees. -4.3.1 CDMS regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +CDMS regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^ A CDMS regridder function is an instance of the CDMS ``Regridder`` class. The function is associated with rectangular input and output @@ -424,8 +424,8 @@ Table 4.3 CDMS Regridder function , , "``dataArray`` is the result data array." , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." -4.3.2 SCRIP Regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +SCRIP Regridder functions +^^^^^^^^^^^^^^^^^^^^^^^^^ A SCRIP regridder function is an instance of the ScripRegridder class. Such a function is created by calling the regrid.readRegridder method. @@ -640,8 +640,8 @@ of the result. | 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | +--------+----------------------------------------------------------------------------------------------------------+ -4.4.2 SCRIP regridder -~~~~~~~~~~~~~~~~~~~~~ +SCRIP regridder +~~~~~~~~~~~~~~~ **Example:** diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 0da06c4f..7fb28a3c 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -1,8 +1,8 @@ -CHAPTER 5 Plotting CDMS data in Python --------------------------------------- +Plotting CDMS data in Python +---------------------------- -5.1 Overview -~~~~~~~~~~~~ +Overview +~~~~~~~~ Data read via the CDMS Python interface can be plotted using the ``vcs`` module. This module, part of the Ultrascale Visualization Climate Data @@ -13,15 +13,15 @@ visualization program. Examples of plotting data accessed from CDMS are given below, as well as documentation for the plot routine keywords. -5.2 Examples -~~~~~~~~~~~~ +Examples +~~~~~~~~ In the following examples, it is assumed that variable ``psl`` is dimensioned (time, latitude, longitude). ``psl`` is contained in the dataset named ``'sample.xml'``. -5.2.1 Example: plotting a gridded variable -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +plotting a gridded variable +^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. testsetup:: * import requests @@ -69,8 +69,8 @@ What if the units are not explicitly defined for ``clt``, or a different description is desired? ``plot`` has a number of other keywords which fill in the extra plot information. -5.2.2 Example: using aplot keywords. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +using aplot keywords. +^^^^^^^^^^^^^^^^^^^^^ .. doctest:: @@ -86,8 +86,8 @@ fill in the extra plot information. **Note:** Keyword arguments can be listed in any order. -5.2.3 Example: plotting a time-latitude slice -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +plotting a time-latitude slice +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``, this example selects and plots a time-latitude slice: @@ -109,8 +109,8 @@ this example selects and plots a time-latitude slice: "4", "``samp`` is a slice of ``clt``, at index ``0`` of the last dimension. Since ``samp`` was obtained from the slice operator, it is a transient variable, which includes the latitude and time information." "6", "The ``name`` keyword defines the identifier, default is the name found in the file." -5.2.4 Example: plotting subsetted data -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +plotting subsetted data +^^^^^^^^^^^^^^^^^^^^^^^ Calling the variable ``clt`` as a function reads a subset of the variable. The result variable ``samp`` can be plotted directly: @@ -127,8 +127,8 @@ variable. The result variable ``samp`` can be plotted directly: >>> f.close() -5.3 ``plot`` method -~~~~~~~~~~~~~~~~~~~ +``plot`` method +~~~~~~~~~~~~~~~ The ``plot`` method is documented in the UV-CDAT Reference Manual. This section augments the documentation with a description of the optional diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 98fe67d5..c29835e8 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -1,8 +1,8 @@ -CHAPTER 6 Climate Data Markup Language (CDML) ---------------------------------------------- +Climate Data Markup Language (CDML) +----------------------------------- -6.1 Introduction -~~~~~~~~~~~~~~~~ +Introduction +~~~~~~~~~~~~ The Climate Data Markup Language (CDML) is the markup language used to represent metadata in CDMS. CDML is based on the W3C XML standard @@ -21,8 +21,8 @@ future. CDML files have the file extension .xml or .cdml. -6.2 Elements -~~~~~~~~~~~~ +Elements +~~~~~~~~ A CDML document consists of a nested collection of elements. An element is a description of the metadata associated with a CDMS object. The form @@ -71,8 +71,8 @@ Table 6.1 CDML Tags | variable | Variable | +------------+---------------------------------------+ -6.3 Special Characters -~~~~~~~~~~~~~~~~~~~~~~ +Special Characters +~~~~~~~~~~~~~~~~~~ XML reserves certain characters for markup. If they appear as content, they must be encoded to avoid confusion with markup: @@ -102,8 +102,8 @@ would appear in an attribute string as: **comment = "Certain "special characters", such as <, >, and ', must be encoded."** -6.4 Identifiers -~~~~~~~~~~~~~~~ +Identifiers +~~~~~~~~~~~ In CDMS, all objects in a dataset have a unique string identifier. The id attribute holds the value of this identifier. If the variable, axis, @@ -118,16 +118,16 @@ case), an underscore (_), or a colon (:). Characters after the first must be alphanumeric, an underscore, or colon. There is no restriction on the length of an identifier. -6.5 CF Metadata Standard -~~~~~~~~~~~~~~~~~~~~~~~~ +CF Metadata Standard +~~~~~~~~~~~~~~~~~~~~ `The CF metadata standard `__ defines a set of conventions for usage of netCDF. This standard is supported by CDML. The document defines names and usage for metadata attributes. CF supersedes the GDT 1.3 standard. -6.6 CDML Syntax -~~~~~~~~~~~~~~~ +CDML Syntax +~~~~~~~~~~~ The following notation is used in this section: @@ -150,8 +150,8 @@ Version 1.0. ``prolog ::= `` -6.6.1 Dataset Element -^^^^^^^^^^^^^^^^^^^^^ +Dataset Element +^^^^^^^^^^^^^^^ A dataset element describes a single dataset. The content is a list of elements corresponding to the axes, grids, and variables contained in @@ -219,8 +219,8 @@ into files. The format is: The pathname is appended to the value of the directory attribute, to obtain an absolute pathname. -6.6.2 Axis Element -^^^^^^^^^^^^^^^^^^ +Axis Element +^^^^^^^^^^^^ An axis element describes a single coordinate axis. The content can be a blank-separated list of axis values or a linear element. A linear @@ -278,8 +278,8 @@ Table 6.4 "``units``", "Y", "Y", "Y", "Units of a physical quantity" "``weights``", "N", "N", "N", "Name of the weights array" -6.6.3 partition attribute -^^^^^^^^^^^^^^^^^^^^^^^^^ +Partition attribute +^^^^^^^^^^^^^^^^^^^ For an axis in a dataset, the .partition attribute describes how an axis @@ -304,8 +304,8 @@ Note that the end index of the second interval is strictly less than the start index of the following interval. This indicates that data for that period is missing. -6.6.4 Grid Element -^^^^^^^^^^^^^^^^^^ +Grid Element +^^^^^^^^^^^^ A grid element describes a horizontal, latitude-longitude grid which is rectilinear in topology, @@ -341,8 +341,8 @@ Table 6.5 RectGrid Attributes -6.6.5 Variable Element -^^^^^^^^^^^^^^^^^^^^^^ +Variable Element +^^^^^^^^^^^^^^^^ A variable element describes a data variable. The domain of the variable is an ordered list of domain elements naming the axes on which the @@ -1700,8 +1700,8 @@ The datatype is one of: **Char**, **Short**, **Long**, **Float**, **datatype=**"``attribute-datatype``"**>** ``attribute-value`` **** -6.7 A Sample CDML Document -~~~~~~~~~~~~~~~~~~~~~~~~~~ +A Sample CDML Document +~~~~~~~~~~~~~~~~~~~~~~ Dataset "sample" has two variables, and six axes. diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index ca533760..c2a3bb25 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -1,11 +1,11 @@ -CHAPTER 7 CDMS Utilities ------------------------- +CDMS Utilities +-------------- -7.1 ``cdscan``: Importing datasets into CDMS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +cdscan: Importing datasets into CDMS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -7.1.1 Overview -^^^^^^^^^^^^^^ +Overview +^^^^^^^^ A dataset is a partitioned collection of files. To create a dataset, the files must be scanned to produce a text representation of the dataset. @@ -40,8 +40,8 @@ partitioned: - Files may be in any of the self-describing formats supported by CDMS, including netCDF, HDF, GrADS/GRIB, and DRS. -7.1.2 ``cdscan`` Syntax -^^^^^^^^^^^^^^^^^^^^^^^ +Syntax +^^^^^^ The syntax of the ``cdscan`` command is @@ -125,14 +125,14 @@ Table 7.1 cdscan command options - The ``[--time-linear]`` option should be used with caution, as it is applied to all the time dimensions found. -7.1.3 Examples -^^^^^^^^^^^^^^ +Examples +^^^^^^^^ - cdscan -c noleap -d test -x test.xml [uv]\*.nc - cdscan -d pcmdi\_6h -i 0.25 -r 'days since 1979-1-1' *6h*.ctl -7.1.4 File Formats -^^^^^^^^^^^^^^^^^^ +File Formats +^^^^^^^^^^^^ Data may be represented in a variety of self-describing binary file formats, including @@ -143,8 +143,8 @@ formats, including non-comment line of the control file must be a dset specification. - DRS, the PCMDI legacy format. -7.1.5 Name Aliasing -^^^^^^^^^^^^^^^^^^^ +Name Aliasing +^^^^^^^^^^^^^ A problem can occur if variables in different files are defined on different grids. What if the axis names are the same? CDMS requires that diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 70e4c29e..bca05b9b 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -38,11 +38,11 @@ FIGURE 1. CDMS Classes APPENDIX B ---------- -Version Notes +Release Notes ~~~~~~~~~~~~~ -B.1 Version 4.0 -^^^^^^^^^^^^^^^ +Release 4.0 +^^^^^^^^^^^ CDMS version 4.0 adds support for nonrectangular grids: @@ -56,8 +56,8 @@ CDMS version 4.0 adds support for nonrectangular grids: - The getMesh and clone methods were added for grids. - An interface to the SCRIP package was added. -B.2 Version 3.0 Overview -^^^^^^^^^^^^^^^^^^^^^^^^ +Release 3.0 Overview +^^^^^^^^^^^^^^^^^^^^ CDMS version 3.0 is a significant enhancement of previous versions. The major changes were: @@ -85,11 +85,11 @@ major changes were: can be built and installed separately. This significantly enhances the portability of the code. -B.3 V3.0 Details -^^^^^^^^^^^^^^^^ +Details +******* -B.3.1 AbstractVariable -'''''''''''''''''''''' +AbstractVariable +'''''''''''''''' - Functions getDomain, getSlice, rank, regrid, setMissing, size, subRegion, and subSlice were added. @@ -107,8 +107,8 @@ B.3.1 AbstractVariable - AbstractVariable implements arithmetic functions, astype. - The write function was added. -B.3.2 AbstractAxis -'''''''''''''''''' +AbstractAxis +'''''''''''' - The functions asComponentTime, asRelativeTime, clone, getAxisIds, getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were @@ -119,65 +119,65 @@ B.3.2 AbstractAxis closed. The intersection options 'n','e','b',and 's' were added to the interval indicator - see mapIntervalExt. -B.3.3 AbstractDatabase -'''''''''''''''''''''' +AbstractDatabase +'''''''''''''''' - The function open is synonymous with openDataset. -B.3.4 Dataset -''''''''''''' +Dataset +''''''' - The function open is synonymous with openDataset. -B.3.5 cdms module -''''''''''''''''' +cdms module +''''''''''' - The functions asVariable, isVariable, and createVariable were added. - The function setAutoReshapeMode was removed. It is replaced by the squeeze option for all I/O functions. -B.3.6 CdmsFile -'''''''''''''' +CdmsFile +'''''''' - The function createVariable has a keyword fill\_value. The datatype may be a Numeric/MA typecode. - The function write was added. -B.3.7 CDMSError -''''''''''''''' +CDMSError +''''''''' - All errors are an instance of the class CDMSError. -B.3.8 AbstractRectGrid -'''''''''''''''''''''' +AbstractRectGrid +'''''''''''''''' - The function createGaussianGrid was added. -B.3.9 InternalAttributes -'''''''''''''''''''''''' +InternalAttributes +'''''''''''''''''' - The class InternalAttributes was added. It has methods add\_internal\_attribute, is\_internal\_attribute, and replace\_external\_attributes. -B.3.10 TransientVariable -'''''''''''''''''''''''' +TransientVariable +''''''''''''''''' - The class TransientVariable was added. It inherits from both AbstractVariable and MA. - The cdms module function createVariable returns a transient variable. - This class does not implement the functions getPaths or getTemplate. -B.3.11 MV -''''''''' +MV +'' - The MV submodule of cdms was added. APPENDIX C ---------- -``cu`` Module -~~~~~~~~~~~~~ +Module `cu` +~~~~~~~~~~~ The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 it is emulated in the ``cdms`` module. It is maintained for backward @@ -186,8 +186,8 @@ compatibility. The ``cu`` classes are ``Slab``, corresponding to ``TransientVariable`` in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. -C.1 Slab -~~~~~~~~ +Slab +~~~~ Table C.1 Slab Methods ^^^^^^^^^^^^^^^^^^^^^^ @@ -207,8 +207,8 @@ Table C.1 Slab Methods -C.2 cuDataset -~~~~~~~~~~~~~ +cuDataset +~~~~~~~~~ Table C.2 cuDataset Methods ^^^^^^^^^^^^^^^^^^^^^^^^^^^ From bbafa043fb9f3c0e2efc344ac9f9a158d32d9086 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 19 Dec 2017 18:06:55 -0800 Subject: [PATCH 034/239] work on tables and setup --- docs/source/conf.py | 1 + docs/source/index.rst | 1 + docs/source/manual/cdms_1.rst | 21 +- docs/source/manual/cdms_2.rst | 1281 ++++++++++----------------------- 4 files changed, 403 insertions(+), 901 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index b6ecab49..5a850b61 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -152,6 +152,7 @@ #html_theme = 'pyramid' #html_theme = 'epub' html_theme = 'haiku' +#html_theme = "sphinx_rtd_theme" #html_theme = 'classic' # Theme options are theme-specific and customize the look and feel of a theme diff --git a/docs/source/index.rst b/docs/source/index.rst index bf9642cb..54125890 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,6 +6,7 @@ CDMS documentation ================== + **Version :** |release| **Table of content:** diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 74707b8d..bd75f724 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -4,14 +4,14 @@ Introduction Overview ^^^^^^^^ -The Climate Data Management System is an object-oriented data management +The Community Data Management System is an object-oriented data management system, specialized for organizing multidimensional, gridded data used in climate analysis and simulation. CDMS is implemented as part of the Ultrascale Visualization Climate Data Analysis Tool (UV-CDAT), which uses the Python language. The examples in this chapter assume some familiarity with the language and the Python -Numeric module (http://www.numpy.org). A number of excellent tutorials +Numpy module (http://www.numpy.org). A number of excellent tutorials on Python are available in books or on the Internet. For example, see the `Python Foundation's homepage `__. @@ -28,8 +28,14 @@ the eastward and northward components of wind speed, respectively, and both variables are functions of time, latitude, and longitude, then the velocity for time 0 (first index) can be calculated as +.. highlight:: python + .. doctest:: + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> f1=cdms2.open("clt.nc") + >>> u = f1('u') + >>> v = f1('v') >>> from cdms2 import MV >>> vel = MV.sqrt(u[0]**2 + v[0]**2) @@ -44,7 +50,7 @@ This illustrates several points: longitude. - Variables can be used in computation. ``**`` is the Python exponentiation operator. -- Arithmetic functions are defined in the ``cdms.MV`` module. +- Arithmetic functions are defined in the ``cdms2.MV2`` module. - Operations on variables carry along the corresponding metadata where applicable. In the above example, ``vel`` has the same latitude and longitude coordinates as ``u`` and ``v``, and the time coordinate is @@ -88,6 +94,7 @@ from file sample.nc into variable u: .. doctest:: + >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" >>> f = cdms2.open('clt.nc') >>> u = f('u') @@ -104,7 +111,7 @@ To read ``u`` at time 1.: .. doctest:: - >>> u1 = f('u',time=1.) + >>> u1 = f('u',time=1.) A variable can be written to a file with the write function: @@ -127,13 +134,13 @@ Often in climate applications an axis is a one-dimensional variable whose values are floating-point and strictly monotonic. In some cases an axis can be multidimensional (see `Grids <#1.9>`__). If an axis is associated with one of the canonical types latitude, longitude, level, -or time, then the axis is called tep emporal . +or time, then the axis is called temporal . The shape and physical ordering of a variable is represented by the variables domain , an ordered tuple of one-dimensional axes. In the previous example, the domain of the variable u is the tuple (time, latitude, longitude). This indicates the order of the dimensions, with -the slowest- varying dimension listed first (time). The domain may be +the slowest-varying dimension listed first (time). The domain may be accessed with the ``getAxisList()`` method: .. doctest:: @@ -256,7 +263,7 @@ shape of the data array. A mask value of one indicates that the corresponding data array element is missing or invalid. Arithmetic operations in CDMS take missing data into account. The same -is true of the functions defined in the cdms.MV module. For example: +is true of the functions defined in the cdms2.MV2 module. For example: .. doctest:: diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 17424069..c2decb9b 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -4,6 +4,9 @@ CDMS Python Application Programming Interface Overview ^^^^^^^^ +.. highlight:: python + :linenothreshold: 3 + .. testsetup:: * import requests @@ -41,29 +44,19 @@ for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: -Table 2.1 Python types used in CDMS - -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Description | -+==============+=======================================================================================================================================================================================================+ -| Array | Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Comptime | Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Dictionary | An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Float | Floating-point value. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Integer | Integer value. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| List | An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| None | No value returned. | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Reltime | Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Tuple | An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')`` | -+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Python types used in CDMS + :header: "Type", "Description" + :widths: 10, 80 + + "Array", "Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules." + "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" + "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" + "Float", "Floating-point value." + "Integer", "Integer value." + "List", "An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']``" + "None", "No value returned." + "Reltime", "Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime" + "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``" A first example ^^^^^^^^^^^^^^^ @@ -97,31 +90,21 @@ latitude, longitude). >>> out.close() -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| 2,3 | Makes the CDMS and MV modules available. MV defines arithmetic functions. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 4 | Opens a netCDF file read-only. The result jones is a dataset object. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 5 | Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 6 | Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 7 | Reads all July data into a masked array julys. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 8 | Calculate the average January value for each grid zone. Any missing data is handled automatically. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 9,10 | Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 14 | Create a new netCDF output file named ‘janjuly.nc’ to hold the results. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 15 | Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 17 | Set the global attribute ‘comment’. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 18 | Close the output file. | -+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: + :header: "Line", "Notes" + :widths: 10, 80 + + "2,3", "Makes the CDMS and MV modules available. MV defines arithmetic functions." + "4", "Opens a netCDF file read-only. The result jones is a dataset object." + "5", "Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data." + "6", "Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array." + "7", "Reads all July data into a masked array julys." + "8", "Calculate the average January value for each grid zone. Any missing data is handled automatically." + "9,10", "Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file." + "14", "Create a new netCDF output file named ‘janjuly.nc’ to hold the results." + "15", "Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." + "17", "Set the global attribute ‘comment’." + "18", "Close the output file." 2.3 cdms module @@ -129,335 +112,112 @@ latitude, longitude). The cdms module is the Python interface to CDMS. The objects and methods in this chapter are made accessible with the command: -.. raw:: html - -
- -:: +.. doctest:: - import cdms2 + import cdms2 -.. raw:: html - -
The functions described in this section are not associated with a class. Rather, they are called as module functions, e.g., -.. raw:: html - -
- -:: +.. doctest:: file = cdms2.open('sample.nc') -.. raw:: html - -
- - -Table 2.2 cdms module functions - -+-------------+-------------------------------------------------------------------------+ -| Type | Definition | -+=============+=========================================================================+ -| ``Variable``| ``asVariable(s)``: Transform ``s`` | -| | into a transient variable. ``s`` is | -| | a masked array, Numeric array, or | -| | Variable. If ``s`` is already a | -| | transient variable, ``s`` is | -| | returned. See also: ``isVariable``. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createAxis(data, bounds=None)``: | -| | Create a one-dimensional coordinate | -| | Axis, which is not associated with a | -| | file or dataset. This is useful for | -| | creating a grid which is not | -| | contained in a file or dataset. | -| | ``data`` is a one-dimensional, | -| | monotonic Numeric array. ``bounds`` | -| | is an array of shape | -| | ``(len(data),2)``, such that for all | -| | ``i``, ``data[i]`` is in the range | -| | ``[bounds[i,0],bounds[i,1] ]``. If | -| | ``bounds`` is not specified, the | -| | default boundaries are generated at | -| | the midpoints between the | -| | consecutive data values, provided | -| | that the autobounds mode is 'on' | -| | (the default). See | -| | ``setAutoBounds``. Also see: | -| | ``CdmsFile.createAxis`` | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createEqualAreaAxis(nlat)``: | -| | Create an equal-area latitude axis. | -| | The latitude values range from north | -| | to south, and for all axis values | -| | ``x[i]``, ``sin(x[i])sin(x[i+1])`` | -| | is constant. ``nlat`` is the axis | -| | length. The axis is not associated | -| | with a file or dataset. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createGaussianAxis(nlat)``: Create | -| | a Gaussian latitude axis. Axis | -| | values range from north to south. | -| | ``nlat`` is the axis length. The | -| | axis is not associated with a file | -| | or dataset. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGaussianGrid(nlats, xorigin= | -| | 0.0, order="yx")``: | -| | Create a Gaussian grid, with shape | -| | ``(nlats, 2*nlats)``. ``nlats`` is | -| | the number of latitudes. ``xorigin`` | -| | is the origin of the longitude axis. | -| | ``order`` is either "yx" (lat-lon, | -| | default) or "xy" (lon-lat) | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, | -| | order="yx", mask=None)``: | -| | Create a generic grid, that is, a | -| | grid which is not typed as Gaussian, | -| | uniform, or equal-area. The grid is | -| | not associated with a file or | -| | dataset. ``latArray`` is a NumPy | -| | array of latitude values. | -| | ``lonArray`` is a NumPy array of | -| | longitude values. ``latBounds`` is a | -| | NumPy array having shape | -| | ``(len(latArray),2)``, of latitude | -| | boundaries. ``lonBounds`` is a NumPy | -| | array having shape | -| | ``(len(lonArray),2)``, of longitude | -| | boundaries. ``order`` is a | -| | ``string`` specifying the order of | -| | the axes, either "yx" for (latitude, | -| | longitude), or "xy" for the reverse. | -| | ``mask`` (optional) is an | -| | ``integer``-valued NumPy mask array, | -| | having the same shape and ordering | -| | as the grid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createGlobalMeanGrid(grid)``: | -| | Generate a grid for calculating the | -| | global mean via a regridding | -| | operation. The return grid is a | -| | single zone covering the range of | -| | the input grid. ``grid`` is a | -| | RectGrid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createRectGrid(lat, lon, order, ty | -| | pe="generic", mask=None)``: | -| | Create a rectilinear grid, not | -| | associated with a file or dataset. | -| | This might be used as the target | -| | grid for a regridding operation. | -| | ``lat`` is a latitude axis, created | -| | by ``cdms.createAxis``. ``lon`` is a | -| | longitude axis, created by | -| | ``cdms.createAxis``. ``order`` is a | -| | string with value "yx" (the first | -| | grid dimension is latitude) or "xy" | -| | (the first grid dimension is | -| | longitude). ``type`` is one of | -| | 'gaussian','uniform','equalarea',or | -| | 'generic'. If specified, ``mask`` is | -| | a two-dimensional, logical Numeric | -| | array (all values are zero or one) | -| | with the same shape as the grid. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createUniformGrid(startLat, nlat, | -| | deltaLat, start-Lon, nlon, deltaLon, | -| | order="yx", mask=None)``: | -| | Create a uniform rectilinear grid. | -| | The grid is not associated with a | -| | file or dataset. The grid boundaries | -| | are at the midpoints of the axis | -| | values. ``startLat`` is the starting | -| | latitude value. ``nlat`` is the | -| | number of latitudes. If ``nlat`` is | -| | 1, the grid latitude boundaries will | -| | be ``startLat`` +/- ``deltaLat/2``. | -| | ``deltaLat`` is the increment | -| | between latitudes. ``startLon`` is | -| | the starting longitude value. | -| | ``nlon`` is the number of | -| | longitudes. If ``nlon`` is 1, the | -| | grid longitude boundaries will be | -| | ``startLon`` +/- ``deltaLon/2``. | -| | ``deltaLon`` is the increment | -| | between longitudes. ``order`` is a | -| | string with value "yx" (the first | -| | grid dimension is latitude) or "xy" | -| | (the first grid dimension is | -| | longitude). If specified, ``mask`` | -| | is a two-dimensional, logical | -| | Numeric array (all values are zero | -| | or one) with the same shape as the | -| | grid. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createUniformLatitudeAxis(startLat | -| | , nlat, deltaLat)``: | -| | Create a uniform latitude axis. The | -| | axis boundaries are at the midpoints | -| | of the axis values. The axis is | -| | designated as a circular latitude | -| | axis. ``startLat`` is the starting | -| | latitude value. ``nlat`` is the | -| | number of latitudes. ``deltaLat`` is | -| | the increment between latitudes. | -+-------------+-------------------------------------------------------------------------+ -| ``RectGrid``| ``createZonalGrid(grid)``: Create a | -| | zonal grid. The output grid has the | -| | same latitude as the input grid, and | -| | a single longitude. This may be used | -| | to calculate zonal averages via a | -| | regridding operation. ``grid`` is a | -| | RectGrid. | -+-------------+-------------------------------------------------------------------------+ -| ``Axis`` | ``createUniformLongitudeAxis(startLo | -| | n, nlon, delta-Lon)``: | -| | Create a uniform longitude axis. The | -| | axis boundaries are at the midpoints | -| | of the axis values. The axis is | -| | designated as a circular longitude | -| | axis. ``startLon`` is the starting | -| | longitude value. ``nlon`` is the | -| | number of longitudes. ``deltaLon`` | -| | is the increment between longitudes. | -+-------------+-------------------------------------------------------------------------+ -| ``Variable``| ``createVariable(array, typecode=Non | -| | e, copy=0, savespace=0, mask=None, f | -| | ill_value=None, grid=None, axes=None | -| | , attributes=None, id=None)``: | -| | This function is documented in Table | -| | 2.34 on page 90. | -+-------------+-------------------------------------------------------------------------+ -| ``Integer`` | ``getAutoBounds()``: Get the current | -| | autobounds mode. Returns 0, 1, or 2. | -| | See ``setAutoBounds``. | -+-------------+-------------------------------------------------------------------------+ -| ``Integer`` | ``isVariable(s)``: Return ``1`` if | -| | ``s`` is a variable, ``0`` | -| | otherwise. See also: ``asVariable``. | -+-------------+-------------------------------------------------------------------------+ -| ``Dataset`` | ``open(url,mode='r')``: Open or | -| | create a ``Dataset`` or | -| | ``CdmsFile``. ``url`` is a Uniform | -| | Resource Locator, referring to a | -| | cdunif or XML file. If the URL has | -| | the extension '.xml' or '.cdml', a | -| | ``Dataset`` is returned, otherwise a | -| | ``CdmsFile`` is returned. If the URL | -| | protocol is 'http', the file must be | -| | a '.xml' or '.cdml' file, and the | -| | mode must be 'r'. If the protocol is | -| | 'file' or is omitted, a local file | -| | or dataset is opened. ``mode`` is | -| | the open mode. See Table 2.24 on | -| | page 70. | -| | **Example**: Open an existing | -| | dataset: | -| | ``f = cdms.open("sampleset.xml")`` | -| | | -| | **Example**: Create a netCDF file: | -| | ``f = cdms.open("newfile.nc",'w')`` | -+-------------+-------------------------------------------------------------------------+ -| ``List`` | ``order2index (axes, orderstring)``: | -| | Find the index permutation of axes | -| | to match order. Return a list of | -| | indices. ``axes`` is a list of axis | -| | objects. ``orderstring`` is defined | -| | as in ``orderparse``. | -+-------------+-------------------------------------------------------------------------+ -| ``List`` | ``orderparse(orderstring)``: Parse | -| | an order string. Returns a list of | -| | axes specifiers. ``orderstring`` | -| | consists of: | -| | | -| | - Letters t, x, y, z meaning time, | -| | longitude, latitude, level | -| | - Numbers 0-9 representing position | -| | in axes | -| | - Dash (-) meaning insert the next | -| | available axis here. | -| | - The ellipsis ... meaning fill | -| | these positions with any | -| | remaining axes. | -| | - (name) meaning an axis whose id | -| | is name | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``setAutoBounds(mode)``: Set | -| | autobounds mode. In some | -| | circumstances CDMS can generate | -| | boundaries for 1-D axes and | -| | rectilinear grids, when the bounds | -| | are not explicitly defined. The | -| | autobounds mode determines how this | -| | is done: If ``mode`` is ``'grid'`` | -| | or ``2`` (the default), the | -| | ``getBounds`` method will | -| | automatically generate boundary | -| | information for an axis or grid if | -| | the axis is designated as a latitude | -| | or longitude axis, and the | -| | boundaries are not explicitly | -| | defined. If ``mode`` is ``'on'`` or | -| | ``1``, the ``getBounds`` method will | -| | automatically generate boundary | -| | information for an axis or grid, if | -| | the boundaries are not explicitly | -| | defined. If ``mode`` is ``'off'`` or | -| | ``0``, and no boundary data is | -| | explicitly defined, the bounds will | -| | NOT be generated; the ``getBounds`` | -| | method will return ``None`` for the | -| | boundaries. Note: In versions of | -| | CDMS prior to V4.0, the default | -| | ``mode`` was ``'on'``. | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``setClassifyGrids(mode)``: Set the | -| | grid classification mode. This | -| | affects how grid type is determined, | -| | for the purpose of generating grid | -| | boundaries. If ``mode`` is ``'on'`` | -| | (the default), grid type is | -| | determined by a grid classification | -| | method, regardless of the value of | -| | ``grid.get-Type()``. If ``mode`` is | -| | ``'off'``, the value of | -| | ``grid.getType()`` determines the | -| | grid type | -+-------------+-------------------------------------------------------------------------+ -| ``None`` | ``writeScripGrid(path, grid, gridTit | -| | le=None)``: | -| | Write a grid to a SCRIP grid file. | -| | ``path`` is a string, the path of | -| | the SCRIP file to be created. | -| | ``grid`` is a CDMS grid object. It | -| | may be rectangular. ``gridTitle`` is | -| | a string ID for the grid. | -+-------------+-------------------------------------------------------------------------+ +.. csv-table:: cdms module funtions + :header: "Type", "Definition" + :widths: 10, 80 + + "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numeric array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." + "``Axis``", "``createAxis(data, bounds=None)``:" + , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." + , " * ``data`` is a one-dimensional, monotonic Numeric array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." + , " * See ``setAutoBounds``." + , " * Also see: ``CdmsFile.createAxis``" + "``Axis``", "``createEqualAreaAxis(nlat)``:" + , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + "``Axis``", "``createGaussianAxis(nlat)``:" + , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" + , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" + "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values." + , " * ``lonArray`` is a NumPy array of longitude values. " + , " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. " + , " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. " + , " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." + , " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." + + "``RectGrid``", "``createGlobalMeanGrid(grid)``:" + , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." + + "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" + , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation." + , " * ``lat`` is a latitude axis, created by ``cdms.createAxis``." + , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." + , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." + , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." + , " * If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." + + "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" + , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." + , " * ``startLat`` is the starting latitude value." + , " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``." + , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." + , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." + , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." + , " * If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." + "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" + , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." + , " * ``startLat`` is the starting latitude value." + , " * ``nlat`` is the number of latitudes." + , " * ``deltaLat`` is the increment between latitudes." + "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." + "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" + , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis." + , " * ``startLon`` is the starting longitude value." + , " * ``nlon`` is the number of longitudes." + , " * ``deltaLon`` is the increment between longitudes." + "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" + "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." + , " * See ``setAutoBounds``." + "``Integer``", "``isVariable(s)``: " + , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." + , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See Table 2.24" + , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" + , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + "``List``", "``order2index (axes, orderstring)``:" + , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." + "``List``", "``orderparse(orderstring)``:" + , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:" + + , " * Letters t, x, y, z meaning time, longitude, latitude, level" + , " * Numbers 0-9 representing position in axes" + , " * Dash (-) meaning insert the next available axis here." + , " * The ellipsis ... meaning fill these positions with any remaining axes." + , " * (name) meaning an axis whose id is name" + "``None``", "``setAutoBounds(mode)``:" + , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + "``None``", "``setClassifyGrids(mode)``:" + , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." + "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" + , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." Table 2.3 Class Tags -+--------------+---------------------+ -| Tag | Class | -+==============+=====================+ -| ‘axis’ | Axis | -+--------------+---------------------+ -| ‘database’ | Database | -+--------------+---------------------+ -| ‘dataset’ | Dataset, CdmsFile | -+--------------+---------------------+ -| ‘grid’ | RectGrid | -+--------------+---------------------+ -| ‘variable’ | Variable | -+--------------+---------------------+ -| ‘xlink’ | Xlink | -+--------------+---------------------+ +.. csv-table:: Class Tags + :header: "Tag", "Class" + :widths: 20, 20 + + "‘axis’", "Axis" + "‘database’", "Database" + "‘dataset’", "Dataset, CdmsFile " + "‘grid’", "RectGrid" + "‘variable’", "Variable" + "‘xlink’", "Xlink" CdmsObj @@ -477,49 +237,29 @@ external attributes are written, but not the internal attributes. **Example**: get a list of all external attributes of obj. -.. raw:: html - -
- -:: +.. doctest:: extatts = obj.attributes.keys() -.. raw:: html - -
-Table 2.4 Attributes common to all CDMS objects +.. csv-table:: Attributes common to all CDMS objects + :header: "Type", "Name", "Definition" + :widths: 20, 20, 50 -+--------------+--------------+--------------------------------------------------+ -| Type | Name | Definition | -+==============+==============+==================================================+ -| Dictionary | attributes | External attribute dictionary for this object. | -+--------------+--------------+--------------------------------------------------+ + "Dictionary", "attributes", "External attribute dictionary for this object." Table 2.5 Getting and setting attributes -+--------------------------------------+--------------------------------------+ -| Type | Definition | -+======================================+======================================+ -| various | ``value = obj.attname`` | -| | Get an internal or external | -| | attribute value. If the attribute is | -| | external, it is read from the | -| | database. If the attribute is not | -| | already in the database, it is | -| | created as an external attribute. | -| | Internal attributes cannot be | -| | created, only referenced. | -+--------------------------------------+--------------------------------------+ -| various | ``obj.attname = value`` | -| | Set an internal or external | -| | attribute value. If the attribute is | -| | external, it is written to the | -| | database. | -+--------------------------------------+--------------------------------------+ +.. csv-table:: Getting and setting attributes + :header: "Type", "Definition" + :widths: 20, 80 + + "various", "``value = obj.attname``" + , "Get an internal or external attribute value. If the attribute is external, it is read from the database. If the attribute is not already in the database, it is created as an external attribute. Internal attributes cannot be created, only referenced." + "various", "``obj.attname = value``" + , "Set an internal or external attribute value. If the attribute is external, it is written to the database." CoordinateAxis @@ -537,177 +277,128 @@ types. Table 2.10 on page 48 specifies methods that are unique to 1D Axis objects. -Table 2.6 CoordinateAxis types - -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Definition | -+======================+=====================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``CoordinateAxis`` | A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis`` | A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis2D`` | A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``AuxAxis1D`` | A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``. | -+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.7 CoordinateAxis Internal Attributes - -+------------------+------------------+--------------------------------------------+ -| Type | Name | Definition | -+==================+==================+============================================+ -| ``Dictionary`` | ``attributes`` | External attribute dictionary. | -+------------------+------------------+--------------------------------------------+ -| ``String`` | ``id`` | CoordinateAxis identifer. | -+------------------+------------------+--------------------------------------------+ -| ``Dataset`` | ``parent`` | The dataset which contains the variable. | -+------------------+------------------+--------------------------------------------+ -| ``Tuple`` | ``shape`` | The length of each axis. | -+------------------+------------------+--------------------------------------------+ - - -Table 2.8 Axis Constructors - -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+=================================================================+==========================================================================================================================================================================================================================================================================================================================================================================================+ -| ``cdms.createAxis(data, bounds=None)`` | Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Dataset.createAxis(name,ar)`` | Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented. ) | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``CdmsFile.createAxis(name,ar,unlimited=0)`` | Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|   | A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|   | B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited`` | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createEqualAreaAxis(nlat)`` | See Table 2.2 on page 33. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createGaussianAxis(nlat)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` | See Table 2.2 on page 18. | -+-----------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.9 CoordinateAxis Methods - -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============+====================================================================+================================================================================================================================================================================================================================================================================+ -| ``Array`` | ``array = axis[i:j]`` | Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``axis[i:j] = array`` | Write a slice of data to the external file. Dataset axes are read-only. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``assignValue(array)`` | Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Axis`` | ``clone(copyData=1)`` | Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLatitude(persistent=0)`` | Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLevel(persistent=0)`` | Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateLongitude(persistent=0, modulo=360.0)`` | Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateTime(persistent=0, calendar = cdtime.MixedCalendar)`` | Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Array`` | ``getBounds()`` | Get the associated boundary array. The shape of the return array depends on the type of axis: | -|   |   | * ``Axis``: ``(n,2)`` | -|   |   | * ``Axis2D``: ``(i,j,4)`` | -|   |   | * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. | -|   |   | If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``getCalendar()`` | Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: | -|   |   | * ``cdtime.GregorianCalendar``: the standard Gregorian calendar | -|   |   | * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar | -|   |   | * ``cdtime.JulianCalendar``: years divisible by 4 are leap years | -|   |   | * ``cdtime.NoLeapCalendar``: a year is 365 days | -|   |   | * ``cdtime.Calendar360``: a year is 360 days | -|   |   | * ``None``: no calendar can be identified | -|   |   | Note: If the axis is not a time axis, the global, file-related calendar is returned. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Array`` | ``getValue()`` | Get the entire axis vector. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLatitude()`` | Returns true iff the axis is a latitude axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLevel()`` | Returns true iff the axis is a level axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLongitude()`` | Returns true iff the axis is a longitude axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isTime()`` | Returns true iff the axis is a time axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``len(axis)`` | The length of the axis if one-dimensional. If multidimensional, the length of the first dimension. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``size()`` | The number of elements in the axis. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``String`` | ``typecode()`` | The ``Numeric`` datatype identifier. | -+---------------+--------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.10 Axis Methods, additional to CoordinateAxis - -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============================+===============================================+==========================================================================================================================================================================================================================================================================================================================+ -| ``List`` of component times | ``asComponentTime(calendar=None)`` | ``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``List`` of relative times | ``asRelativeTime()`` | ``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``None`` | ``designateCircular(modulo, persistent=0)`` | Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isCircular()`` | Returns ``True`` if the axis has circular topology. An axis is defined as circular if: | -|   |   | * ``axis.topology == 'circular'``, or | -|   |   | * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0 | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Integer`` | ``isLinear()`` | Returns ``True`` if the axis has a linear representation. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``Tuple`` | ``mapInterval(interval)`` | Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``(i,j,k)`` | ``mapIntervalExt(interval)`` | Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: | -|   |   | * ``(x,y)`` | -|   |   | * ``(x,y,indicator)`` | -|   |   | * ``(x,y,indicator,cycle)`` | -|   |   | * ``None or ':'`` | -|   |   | * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: | -|   |   | * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis| -|   |   | * ``'n'`` - select node values which are contained in the interval | -|   |   | * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval | -|   |   | * ``'e'`` - same as n, but include an extra node on either side | -|   |   | * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval | -|   |   | * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. | -|   |   | * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. | -|   |   | * An interval of ``None`` or ``':'`` returns the full index interval of the axis. | -|   |   | * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. | -|   |   | * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` | -|   |   | * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. | -|   |   | * otherwise the interval wraps around the axis endpoint. | -|   |   | * see also: ``mapinterval``, ``variable.subregion()`` | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``transientaxis`` | ``subaxis(i,j,k=1)`` | create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute. | -+-------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -table 2.11 axis slice operators - -+---------------+-----------------------------------------------------------------------------+ -| slice | definition | -+===============+=============================================================================+ -| ``[i]`` | the ``ith`` element, starting with index ``0`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j]`` | the ``ith`` element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:]`` | the ``ith`` element through and including the end | -+---------------+-----------------------------------------------------------------------------+ -| ``[:j]`` | the beginning element through, but not including, element ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[:]`` | the entire array | -+---------------+-----------------------------------------------------------------------------+ -| ``[i:j:k]`` | every ``kth`` element, starting at ``i``, through but not including ``j`` | -+---------------+-----------------------------------------------------------------------------+ -| ``[-i]`` | the ``ith`` element from the end. ``-1`` is the last element. | -+---------------+-----------------------------------------------------------------------------+ + +.. csv-table:: CoordinateAxis types + :header: "Type", "Definition" + :widths: 20, 80 + + "``CoordinateAxis``", "A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``." + "``Axis``", "A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``." + "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." + "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." + + + +.. csv-table:: CoordinateAxis Internal Attributes + :header: "Type", "Name", "Definition" + :widths: 20, 20, 80 + + "``Dictionary``", "``attributes``", "External attribute dictionary." + "``String``", "``id``", "CoordinateAxis identifer." + "``Dataset``", "``parent``", "The dataset which contains the variable." + "``Tuple``", "``shape``", "The length of each axis." + + +.. csv-table:: Axis Constructors + :header: "Constructor", "Description" + :widths: 20, 80 + + "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33." + "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" + , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" + , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited``" + , "``cdms.createEqualAreaAxis(nlat)``" + , "* See Table 2.2 on page 33." + , "``cdms.createGaussianAxis(nlat)``" + , "* See Table 2.2 on page 18." + , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" + , "* See Table 2.2 on page 18." + , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" + , "* See Table 2.2 on page 18." + + +.. csv-table:: CoordinateAxis Methods + :header: "Type", "Method", "Definition" + :widths: 20, 20, 80 + + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators." + "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." + "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis." + "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." + "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." + "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis:" + ,,"* ``Axis``: ``(n,2)``" + ,,"* ``Axis2D``: ``(i,j,4)``" + ,,"* ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell." + ,,"If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are:" + ,,"* ``cdtime.GregorianCalendar``: the standard Gregorian calendar" + ,,"* ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar" + ,,"* ``cdtime.JulianCalendar``: years divisible by 4 are leap years" + ,,"* ``cdtime.NoLeapCalendar``: a year is 365 days" + ,,"* ``cdtime.Calendar360``: a year is 360 days" + ,,"* ``None``: no calendar can be identified" + ,," **Note** If the axis is not a time axis, the global, file-related calendar is returned." + "``Array``", "``getValue()``", "Get the entire axis vector." + "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." + "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." + "``Integer``", "``isLongitude()``", "Returns true iff the axis is a longitude axis." + "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." + "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." + "``Integer``", "``size()``", "The number of elements in the axis." + "``String``", "``typecode()``", "The ``Numeric`` datatype identifier." + + + +.. csv-table:: Axis Methods, additional to CoordinateAxis + :header: "Type", "Method", "Definition" + :widths: 20, 20, 80 + + "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." + "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." + "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if:" + ,," * ``axis.topology == 'circular'``, or" + ,," * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." + "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." + "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:" + ,,"* ``(x,y)``" + ,,"* ``(x,y,indicator)``" + ,,"* ``(x,y,indicator,cycle)``" + ,,"* ``None or ':'``" + ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" + ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" + ,,"* ``'n'`` - select node values which are contained in the interval" + ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" + ,,"* ``'e'`` - same as n, but include an extra node on either side" + ,,"* ``'s'`` - select axis elements for which the cell boundary is a subset of the interval" + ,,"* The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected." + ,,"* If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``." + ,,"* An interval of ``None`` or ``':'`` returns the full index interval of the axis." + ,,"* The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty." + ,,"* for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``" + ,,"* if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint." + ,,"* otherwise the interval wraps around the axis endpoint." + ,,"* see also: ``mapinterval``, ``variable.subregion()``" + "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." + + +.. csv-table:: axis slice operators + :header: "Slice", "Definition" + :widths: 20, 80 + + "``[i]``", "the ``ith`` element, starting with index ``0``" + "``[i:j]``", "the ``ith`` element through, but not including, element ``j``" + "``[i:]``", "the ``ith`` element through and including the end" + "``[:j]``", "the beginning element through, but not including, element ``j``" + "``[:]``", "the entire array" + "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" + "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." **example:** @@ -718,20 +409,13 @@ wraps around, since ``-2 < 0``, and has a stride of ``1``. this is equivalent to the two contiguous index intervals ``2 <= n < 0`` and ``0 <= n < 3`` -.. raw:: html - -
- -:: +.. doctest:: >>> axis.isCircular() 1 >>> axis.mapIntervalExt((-5.0,5.0,'co')) (-2,3,1) -.. raw:: html - -
CdmsFile @@ -744,325 +428,134 @@ As of CDMS V3, the legacy cuDataset interface is also supported by Cdms-Files. See “cu Module” on page 180. -Table 2.12 CdmsFile Internal Attributes - -+------------------+------------------+---------------------------------------+ -| Type | Name | Definition | -+==================+==================+=======================================+ -| ``Dictionary`` | ``attributes`` | Global, external file attributes | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``axes`` | Axis objects contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``grids`` | Grids contained in the file. | -+------------------+------------------+---------------------------------------+ -| ``String`` | ``id`` | File pathname. | -+------------------+------------------+---------------------------------------+ -| ``Dictionary`` | ``variables`` | Variables contained in the file. | -+------------------+------------------+---------------------------------------+ - -Table 2.13 CdmsFile Constructors - -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+==========================================+==================================================================================================================================================================================+ -| ``fileobj = cdms.open(path, mode)`` | Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70. | -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``fileobj = cdms.createDataset(path)`` | Create the file specified by path, a string. | -+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Table 2.14 CdmsFile Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| ``Transient-Variable`` | ``fileobj(varname, selec | Calling a ``CdmsFile`` | -| | tor)`` | object as a function | -| | | reads the region of data | -| | | specified by the | -| | | ``selector``. The result | -| | | is a transient variable, | -| | | unless ``raw = 1`` is | -| | | specified. See | -| | | "Selectors" on page 103. | -| | | | -| | | **Example:** The | -| | | following reads data for | -| | | variable 'prc', year | -| | | 1980: | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('test. | -| | | nc') | -| | | x = f('prc', time=(' | -| | | 1980-1','1981-1')) | -+--------------------------+--------------------------+--------------------------+ -| ``Variable``, ``Axis``, | ``fileobj['id']`` | Get the persistent | -| or ``Grid`` | | variable, axis or grid | -| | | object having the string | -| | | identifier. This does | -| | | not read the data for a | -| | | variable. | -| | | | -| | | **Example:** The | -| | | following gets the | -| | | persistent variable | -| | | ``v``, equivalent to | -| | | ``v = f.variables['prc'] | -| | | ``. | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('sampl | -| | | e.nc') | -| | | v = f['prc'] | -| | | | -| | | **Example:** The | -| | | following gets the axis | -| | | named time, equivalent | -| | | to | -| | | ``t = f.axes['time']``. | -| | | | -| | | ``t = f['time']`` | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``close()`` | Close the file. | -+--------------------------+--------------------------+--------------------------+ -| ``Axis`` | ``copyAxis(axis, newname | Copy ``axis`` values and | -| | =None)`` | attributes to a new axis | -| | | in the file. The | -| | | returned object is | -| | | persistent: it can be | -| | | used to write axis data | -| | | to or read axis data | -| | | from the file. If an | -| | | axis already exists in | -| | | the file, having the | -| | | same name and coordinate | -| | | values, it is returned. | -| | | It is an error if an | -| | | axis of the same name | -| | | exists, but with | -| | | different coordinate | -| | | values. ``axis`` is the | -| | | axis object to be | -| | | copied. ``newname``, if | -| | | specified, is the string | -| | | identifier of the new | -| | | axis object. If not | -| | | specified, the | -| | | identifier of the input | -| | | axis is used. | -+--------------------------+--------------------------+--------------------------+ -| ``Grid`` | ``copyGrid(grid, newname | Copy grid values and | -| | =None)`` | attributes to a new grid | -| | | in the file. The | -| | | returned grid is | -| | | persistent. If a grid | -| | | already exists in the | -| | | file, having the same | -| | | name and axes, it is | -| | | returned. An error is | -| | | raised if a grid of the | -| | | same name exists, having | -| | | different axes. ``grid`` | -| | | is the grid object to be | -| | | copied. ``newname``, if | -| | | specified is the string | -| | | identifier of the new | -| | | grid object. If | -| | | unspecified, the | -| | | identifier of the input | -| | | grid is used. | -+--------------------------+--------------------------+--------------------------+ -| ``Axis`` | ``createAxis(id, ar, unl | Create a new ``Axis``. | -| | imited=0)`` | This is a persistent | -| | | object which can be used | -| | | to read or write axis | -| | | data to the file. ``id`` | -| | | is an alphanumeric | -| | | string identifier, | -| | | containing no blanks. | -| | | ``ar`` is the | -| | | one-dimensional axis | -| | | array. Set ``unlimited`` | -| | | to ``cdms.Unlimited`` to | -| | | indicate that the axis | -| | | is extensible. | -+--------------------------+--------------------------+--------------------------+ -| ``RectGrid`` | ``createRectGrid(id, lat | Create a ``RectGrid`` in | -| | , lon, order, type="gene | the file. This is not a | -| | ric", mask=None)`` | persistent object: the | -| | | order, type, and mask | -| | | are not written to the | -| | | file. However, the grid | -| | | may be used for | -| | | regridding operations. | -| | | ``lat`` is a latitude | -| | | axis in the file. | -| | | ``lon`` is a longitude | -| | | axis in the file. | -| | | ``order`` is a string | -| | | with value ``"yx"`` (the | -| | | first grid dimension is | -| | | latitude) or ``"xy"`` | -| | | (the first grid | -| | | dimension is longitude). | -| | | ``type`` is one of | -| | | ``'gaussian'``,\ ``'unif | -| | | orm'``,\ ``'equalarea'`` | -| | | , | -| | | or ``'generic'``. If | -| | | specified, ``mask`` is a | -| | | two-dimensional, logical | -| | | Numeric array (all | -| | | values are zero or one) | -| | | with the same shape as | -| | | the grid. | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | ``createVariable(String | Create a new Variable. | -| | id, String datatype,List | This is a persistent | -| | axes, fill_value=None)`` | object which can be used | -| | | to read or write | -| | | variable data to the | -| | | file. ``id`` is a String | -| | | name which is unique | -| | | with respect to all | -| | | other objects in the | -| | | file. ``datatype`` is an | -| | | ``MA`` typecode, e.g., | -| | | ``MA.Float``, | -| | | ``MA.Int``. ``axes`` is | -| | | a list of Axis and/or | -| | | Grid objects. | -| | | ``fill_value`` is the | -| | | missing value | -| | | (optional). | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | ``createVariableCopy(var | Create a new | -| | , newname=None)`` | ``Variable``, with the | -| | | same name, axes, and | -| | | attributes as the input | -| | | variable. An error is | -| | | raised if a variable of | -| | | the same name exists in | -| | | the file. ``var`` is the | -| | | ``Variable`` to be | -| | | copied. ``newname``, if | -| | | specified is the name of | -| | | the new variable. If | -| | | unspecified, the | -| | | returned variable has | -| | | the same name as | -| | | ``var``. | -| | | | -| | | **Note:** Unlike | -| | | copyAxis, the actual | -| | | data is not copied to | -| | | the new variable. | -+--------------------------+--------------------------+--------------------------+ -| ``CurveGrid`` or | ``readScripGrid(self, wh | Read a curvilinear or | -| ``Generic-Grid`` | ichGrid='destination', c | generic grid from a | -| | heck-Grid=1)`` | SCRIP netCDF file. The | -| | | file can be a SCRIP grid | -| | | file or remapping file. | -| | | If a mapping file, | -| | | ``whichGrid`` chooses | -| | | the grid to read, either | -| | | ``"source"`` or | -| | | ``"destination"``. If | -| | | ``checkGrid`` is ``1`` | -| | | (default), the grid | -| | | cells are checked for | -| | | convexity, and | -| | | 'repaired' if necessary. | -| | | Grid cells may appear to | -| | | be nonconvex if they | -| | | cross a ``0 / 2pi`` | -| | | boundary. The repair | -| | | consists of shifting the | -| | | cell vertices to the | -| | | same side modulo 360 | -| | | degrees. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``sync()`` | Writes any pending | -| | | changes to the file. | -+--------------------------+--------------------------+--------------------------+ -| ``Variable`` | :: | Write a variable or | -| | | array to the file. The | -| | write(var, attribute | return value is the | -| | s=None, axes=None, extbo | associated file | -| | unds=None, id=None, exte | variable. | -| | nd=None, fill_value=None | | -| | , index=None, typecode=N | If the variable does not | -| | one) | exist in the file, it is | -| | | first defined and all | -| | | attributes written, then | -| | | the data is written. By | -| | | default, the time | -| | | dimension of the | -| | | variable is defined as | -| | | the unlimited dimension | -| | | of the file. If the data | -| | | is already defined, then | -| | | data is extended or | -| | | overwritten depending on | -| | | the value of keywords | -| | | ``extend`` and | -| | | ``index``, and the | -| | | unlimited dimension | -| | | values associated with | -| | | ``var``. | -| | | | -| | | ``var`` is a Variable, | -| | | masked array, or Numeric | -| | | array. ``attributes`` is | -| | | the attribute dictionary | -| | | for the variable. The | -| | | default is | -| | | ``var.attributes``. | -| | | ``axes`` is the list of | -| | | file axes comprising the | -| | | domain of the variable. | -| | | The default is to copy | -| | | ``var.getAxisList()``. | -| | | ``extbounds`` is the | -| | | unlimited dimension | -| | | bounds. Defaults to | -| | | ``var.getAxis(0).getBoun | -| | | ds()``. | -| | | ``id`` is the variable | -| | | name in the file. | -| | | Default is ``var.id``. | -| | | ``extend = 1`` causes | -| | | the first dimension to | -| | | be unlimited: | -| | | iteratively writeable. | -| | | The default is ``None``, | -| | | in which case the first | -| | | dimension is extensible | -| | | if it is ``time.Set`` to | -| | | ``0`` to turn off this | -| | | behaviour. | -| | | ``fill_value`` is the | -| | | missing value flag. | -| | | ``index`` is the | -| | | extended dimension index | -| | | to write to. The default | -| | | index is determined by | -| | | lookup relative to the | -| | | existing extended | -| | | dimension. | -| | | | -| | | **Note:** data can also | -| | | be written by setting a | -| | | slice of a file | -| | | variable, and attributes | -| | | can be written by | -| | | setting an attribute of | -| | | a file variable. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: CdmsFile Internal Attributes + :header: "Type", "Name", "Definition" + :widths: 20, 20, 80 + + "``Dictionary``", "``attributes``", "Global, external file attributes" + "``Dictionary``", "``axes``", "Axis objects contained in the file." + "``Dictionary``", "``grids``", "Grids contained in the file." + "``String``", "``id``", "File pathname." + "``Dictionary``", "``variables``", "Variables contained in the file." + + + +.. csv-table:: CdmsFile Constructors + :header: "Constructor", "Description" + :widths: 20, 80 + + "Constructor", "Description" + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70." + "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." + + +.. csv-table:: CdmsFile Methods + :header: "Type", "Method", "Definition" + :widths: 20, 20, 80 + + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" + ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors' on page 103." + ,, " **Example:** The following reads data for variable 'prc', year 1980:" + ,, " * >>> f = cdms.open('test.nc')" + ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." + ,, " **Example:** The following gets the persistent variable" + ,, " * ``v``, equivalent to" + ,, " * ``v = f.variables['prc']``." + ,, " * f = cdms.open('sample.nc')" + ,, " * v = f['prc']" + ,, " **Example:** The following gets the axis named time, equivalent to" + ,, " * ``t = f.axes['time']``." + ,, " * ``t = f['time']``" + "``None``", "``close()``", "Close the file." + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + "``Axis``", "``createAxis(id, ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid, String datatype, Listaxes, fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MA`` typecode, e.g., ``MA.Float``, ``MA.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." + ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self, whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + +# +--------------------------+--------------------------+--------------------------+ +# | ``None`` | ``sync()`` | Writes any pending | +# | | | changes to the file. | +# +--------------------------+--------------------------+--------------------------+ +# | ``Variable`` | :: | Write a variable or | +# | | | array to the file. The | +# | | write(var, attribute | return value is the | +# | | s=None, axes=None, extbo | associated file | +# | | unds=None, id=None, exte | variable. | +# | | nd=None, fill_value=None | | +# | | , index=None, typecode=N | If the variable does not | +# | | one) | exist in the file, it is | +# | | | first defined and all | +# | | | attributes written, then | +# | | | the data is written. By | +# | | | default, the time | +# | | | dimension of the | +# | | | variable is defined as | +# | | | the unlimited dimension | +# | | | of the file. If the data | +# | | | is already defined, then | +# | | | data is extended or | +# | | | overwritten depending on | +# | | | the value of keywords | +# | | | ``extend`` and | +# | | | ``index``, and the | +# | | | unlimited dimension | +# | | | values associated with | +# | | | ``var``. | +# | | | | +# | | | ``var`` is a Variable, | +# | | | masked array, or Numeric | +# | | | array. ``attributes`` is | +# | | | the attribute dictionary | +# | | | for the variable. The | +# | | | default is | +# | | | ``var.attributes``. | +# | | | ``axes`` is the list of | +# | | | file axes comprising the | +# | | | domain of the variable. | +# | | | The default is to copy | +# | | | ``var.getAxisList()``. | +# | | | ``extbounds`` is the | +# | | | unlimited dimension | +# | | | bounds. Defaults to | +# | | | ``var.getAxis(0).getBoun | +# | | | ds()``. | +# | | | ``id`` is the variable | +# | | | name in the file. | +# | | | Default is ``var.id``. | +# | | | ``extend = 1`` causes | +# | | | the first dimension to | +# | | | be unlimited: | +# | | | iteratively writeable. | +# | | | The default is ``None``, | +# | | | in which case the first | +# | | | dimension is extensible | +# | | | if it is ``time.Set`` to | +# | | | ``0`` to turn off this | +# | | | behaviour. | +# | | | ``fill_value`` is the | +# | | | missing value flag. | +# | | | ``index`` is the | +# | | | extended dimension index | +# | | | to write to. The default | +# | | | index is determined by | +# | | | lookup relative to the | +# | | | existing extended | +# | | | dimension. | +# | | | | +# | | | **Note:** data can also | +# | | | be written by setting a | +# | | | slice of a file | +# | | | variable, and attributes | +# | | | can be written by | +# | | | setting an attribute of | +# | | | a file variable. | +# +--------------------------+--------------------------+--------------------------+ Table 2.15 CDMS Datatypes From 3ec8781cbf3679f3f62b3415636e8b03552cc681 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 20 Dec 2017 10:48:15 -0800 Subject: [PATCH 035/239] try to force jquery 3.1 --- docs/source/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 5a850b61..915470d9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -28,6 +28,9 @@ sys.path.insert(0,"/software/anaconda2/envs/dev/lib/python2.7/site-packages") print os.path.join(sys.prefix,"lib","python2.7","site-packages") +def setup(app): + app.add_javascript('jquery.js') + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. From 7eca24823b5b9139b0c477f1de7ccbcacc8e59fc Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 20 Dec 2017 11:31:31 -0800 Subject: [PATCH 036/239] just copy js script in _static --- docs/source/conf.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 915470d9..a5ae037c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -28,8 +28,6 @@ sys.path.insert(0,"/software/anaconda2/envs/dev/lib/python2.7/site-packages") print os.path.join(sys.prefix,"lib","python2.7","site-packages") -def setup(app): - app.add_javascript('jquery.js') # -- General configuration ------------------------------------------------ @@ -60,6 +58,15 @@ def setup(app): 'sphinx.ext.napoleon' ] +jscopybutton_path = "copybutton.js" + +try: + from easydev.copybutton import get_copybutton_path + from easydev.copybutton import copy_javascript_into_static_path + copy_javascript_into_static_path("_static", get_copybutton_path()) +except Exception: + print("could not copy the copybutton javascript") + napoleon_google_docstring = True napoleon_numpy_docstring = True napoleon_include_private_with_doc = False From 95b3029fc0035e93de4237d3be00b5d1ee082f88 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 20 Dec 2017 11:37:11 -0800 Subject: [PATCH 037/239] add highlight python --- docs/source/manual/cdms_3.rst | 3 +++ docs/source/manual/cdms_4.rst | 3 +++ docs/source/manual/cdms_5.rst | 3 +++ 3 files changed, 9 insertions(+) diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index c59615f8..5ac605ef 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -3,6 +3,9 @@ Module: cdtime Time types ^^^^^^^^^^ +.. highlight:: python + :linenothreshold: 3 + .. testsetup:: * import requests diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 71914fc0..2d760269 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -14,6 +14,9 @@ CDMS provides several methods for interpolating gridded data: CDMS horizontal regrider ^^^^^^^^^^^^^^^^^^^^^^^^ +.. highlight:: python + :linenothreshold: 3 + .. testsetup:: * import requests diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 7fb28a3c..78fe175c 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -22,6 +22,9 @@ dataset named ``'sample.xml'``. plotting a gridded variable ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. highlight:: python + :linenothreshold: 3 + .. testsetup:: * import requests From a1f80cb788531436bb579058c65a5e6cc50bd624 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 9 Jan 2018 14:47:57 -0800 Subject: [PATCH 038/239] add sample dataset page --- docs/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/index.rst b/docs/source/index.rst index 54125890..3cbec1f9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -22,6 +22,7 @@ CDMS documentation manual/cdms_6 manual/cdms_7 manual/cdms_appendix + manual/sample_data # AbstractAxis # AbstractVariable From f6335ee9af740901baff9ad0d3197f7b9756c50f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 9 Jan 2018 14:50:24 -0800 Subject: [PATCH 039/239] add sample dataset page --- docs/source/manual/sample_data.rst | 125 +++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 docs/source/manual/sample_data.rst diff --git a/docs/source/manual/sample_data.rst b/docs/source/manual/sample_data.rst new file mode 100644 index 00000000..649b0c14 --- /dev/null +++ b/docs/source/manual/sample_data.rst @@ -0,0 +1,125 @@ +CDMS Sample Dataset +------------------- + +* http://uvcdat.llnl.gov/cdat/sample_data/161122_RobertPincus_multiple_input4MIPs_radiation_RFMIP_UColorado-RFMIP-20161122_none.nc +* http://uvcdat.llnl.gov/cdat/sample_data/20160520.A_WCYCL1850.ne30_oEC.edison.alpha6_01_ANN_climo_Q.nc +* http://uvcdat.llnl.gov/cdat/sample_data/area_weights.nc +* http://uvcdat.llnl.gov/cdat/sample_data/BlueMarble.ppm +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.001 +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.002 +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.003 +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.004 +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.005 +* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_CONC.D1.001 +* http://uvcdat.llnl.gov/cdat/sample_data/cdtest10.xml +* http://uvcdat.llnl.gov/cdat/sample_data/cdtest13.xml +* http://uvcdat.llnl.gov/cdat/sample_data/cdtest14.xml +* http://uvcdat.llnl.gov/cdat/sample_data/clt2.nc +* http://uvcdat.llnl.gov/cdat/sample_data/clt.nc +* http://uvcdat.llnl.gov/cdat/sample_data/dar.meteo.mod.cam3.era.v31.h0.l3.nrstpt.cp.2000070100.2000080100.tau.12.36.nc +* http://uvcdat.llnl.gov/cdat/sample_data/dvtest1.dat +* http://uvcdat.llnl.gov/cdat/sample_data/dvtest1.dic +* http://uvcdat.llnl.gov/cdat/sample_data/era15_tas_sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/era40_sst_sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/era40_tas_sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/genutil_statistics.nc +* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.ctl +* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.gmp +* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.grb +* http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.ctl +* http://uvcdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.data +* http://uvcdat.llnl.gov/cdat/sample_data/GPCP_ANN_climo.nc +* http://uvcdat.llnl.gov/cdat/sample_data/gpcp_cdr_v23rB1_y2016_m08.nc +* http://uvcdat.llnl.gov/cdat/sample_data/GRIDCRO2D_D1.001 +* http://uvcdat.llnl.gov/cdat/sample_data/hadcrut2_sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/junk.nc +* http://uvcdat.llnl.gov/cdat/sample_data/MERRA_ANN_climo_SHUM.nc +* http://uvcdat.llnl.gov/cdat/sample_data/meshfill.nc +* http://uvcdat.llnl.gov/cdat/sample_data/model_ANN_climo.nc +* http://uvcdat.llnl.gov/cdat/sample_data/navy_land.nc +* http://uvcdat.llnl.gov/cdat/sample_data/netcdf4_compressed_example.nc +* http://uvcdat.llnl.gov/cdat/sample_data/obs_timeseries.nc +* http://uvcdat.llnl.gov/cdat/sample_data/prcp_1951.nc +* http://uvcdat.llnl.gov/cdat/sample_data/psl_6h.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.0E.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.180E.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.180W.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.60E.nc +* http://uvcdat.llnl.gov/cdat/sample_data/readonly.nc +* http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc +* http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc +* http://uvcdat.llnl.gov/cdat/sample_data/rlut_CERES_000001-000012_ac.nc +* http://uvcdat.llnl.gov/cdat/sample_data/rmp_C02562_to_T42_conserv.nc +* http://uvcdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc +* http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc +* http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sampleCurveGrid4.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sampleGenGrid3.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sample.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sample_polar.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sftbyrgn.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_10x10.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_ccsr.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_dnm.nc +* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_visus.nc +* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_ACCESS1-0_historical_r1i1p1_185001-185412_2timesteps.nc +* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_GISS-E2-R_historicalNat_r5i1p1_185001-187512_2timesteps.nc +* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_HadGEM2-CC_historical_r1i1p1_185912-186911_2timesteps.nc +* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_MPI-ESM-LR_1pctCO2_r1i1p1_185001-185912_2timesteps.nc +* http://uvcdat.llnl.gov/cdat/sample_data/stereographic.nc +* http://uvcdat.llnl.gov/cdat/sample_data/swan.four.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dat +* http://uvcdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dic +* http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_6h.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1979.01-1979.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1980.01-1980.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1981.01-1981.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1982.01-1982.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1983.01-1983.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1984.01-1984.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a.xml +* http://uvcdat.llnl.gov/cdat/sample_data/tas_cru_1979.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1979.01-1979.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1980.01-1980.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1981.01-1981.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1982.01-1982.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1983.01-1983.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1984.01-1984.12.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a.xml +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ecm_1979.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_gavg_rnl_ecm.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_GFDL-ESM2G_Amon_historical_r1i1p1_198501-200512-clim.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_mo_clim.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_mo.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tas_ukmo_con.nc +* http://uvcdat.llnl.gov/cdat/sample_data/taylor.nc +* http://uvcdat.llnl.gov/cdat/sample_data/tdata.hdf +* http://uvcdat.llnl.gov/cdat/sample_data/test.2.bin +* http://uvcdat.llnl.gov/cdat/sample_data/test_anim.nc +* http://uvcdat.llnl.gov/cdat/sample_data/test.bin +* http://uvcdat.llnl.gov/cdat/sample_data/test.cdms +* http://uvcdat.llnl.gov/cdat/sample_data/test_col.asc +* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.ctl +* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.grib2 +* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.idx +* http://uvcdat.llnl.gov/cdat/sample_data/test_mesa_leak.nc +* http://uvcdat.llnl.gov/cdat/sample_data/testpp.pp +* http://uvcdat.llnl.gov/cdat/sample_data/test.xml +* http://uvcdat.llnl.gov/cdat/sample_data/thermo.nc +* http://uvcdat.llnl.gov/cdat/sample_data/th_yr.nc +* http://uvcdat.llnl.gov/cdat/sample_data/ts_da.nc +* http://uvcdat.llnl.gov/cdat/sample_data/u_2000.nc +* http://uvcdat.llnl.gov/cdat/sample_data/u_2001.nc +* http://uvcdat.llnl.gov/cdat/sample_data/u_2002.nc +* http://uvcdat.llnl.gov/cdat/sample_data/v_2000.nc +* http://uvcdat.llnl.gov/cdat/sample_data/v_2001.nc +* http://uvcdat.llnl.gov/cdat/sample_data/v_2002.nc +* http://uvcdat.llnl.gov/cdat/sample_data/vertical.nc +* http://uvcdat.llnl.gov/cdat/sample_data/vmro3_input4MIPs_ozone_DAMIP_CCMI-hist-stratO3-1-0_gr_185001_nco.nc +* http://uvcdat.llnl.gov/cdat/sample_data/wk_data.nc +* http://uvcdat.llnl.gov/cdat/sample_data/wk_results.nc +* http://uvcdat.llnl.gov/cdat/sample_data/wspd.coads.nc +* http://uvcdat.llnl.gov/cdat/sample_data/wspd.nc +* http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc From 58915de31152ef7e0b23d992ab74241b96cf3110 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 10 Jan 2018 16:46:21 -0800 Subject: [PATCH 040/239] work on tables for cdms_2.rst --- docs/source/manual/cdms_1.rst | 6 +- docs/source/manual/cdms_2.rst | 529 +++++++-------------------- docs/source/manual/cdms_4.rst | 20 +- docs/source/manual/cdms_5.rst | 6 +- docs/source/manual/cdms_appendix.rst | 14 +- 5 files changed, 146 insertions(+), 429 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index bd75f724..cebb795b 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -44,7 +44,7 @@ This illustrates several points: - Square brackets represent the slice operator. Indexing starts at 0, so ``u[0]`` selects from variable ``u`` for the first timepoint. The result of this slice operation is another variable. The slice - operator can be multidimensional, and follows the syntax of Numeric + operator can be multidimensional, and follows the syntax of Numpy Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data for the first ten timepoints, at all latitudes, for the second longitude. @@ -228,7 +228,7 @@ attributes, which are accessed using the Python dot notation: >>> print u.units m/s -Attribute values can be strings, scalars, or 1-D Numeric arrays. +Attribute values can be strings, scalars, or 1-D Numpy arrays. When a variable is written to a file, not all the attributes are written. Some attributes, called internal attributes, are used for @@ -298,7 +298,7 @@ variables ``missing_value`` attribute. The data and ``missing_value`` attribute are then written to the file. Masking is covered in `Section 2.9 `__. See also the -documentation of the Python Numeric and MA modules, on which ``cdms.MV`` +documentation of the Python Numpy and MA modules, on which ``cdms.MV`` is based, at `http://www.numpy.org/ `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index c2decb9b..fa011af5 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -48,7 +48,7 @@ return an instance of a CDMS class, or one of the Python types: :header: "Type", "Description" :widths: 10, 80 - "Array", "Numeric or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numeric and MA modules." + "Array", "Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules." "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" "Float", "Floating-point value." @@ -128,10 +128,10 @@ Rather, they are called as module functions, e.g., :header: "Type", "Definition" :widths: 10, 80 - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numeric array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." + "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." - , " * ``data`` is a one-dimensional, monotonic Numeric array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." + , " * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." , " * See ``setAutoBounds``." , " * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" @@ -157,7 +157,7 @@ Rather, they are called as module functions, e.g., , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." - , " * If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." + , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." @@ -166,7 +166,7 @@ Rather, they are called as module functions, e.g., , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." - , " * If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." + , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." , " * ``startLat`` is the starting latitude value." @@ -324,7 +324,7 @@ Axis objects. "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." - "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numeric array, of the same dimensionality as the axis." + "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." @@ -350,7 +350,7 @@ Axis objects. "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." "``Integer``", "``size()``", "The number of elements in the axis." - "``String``", "``typecode()``", "The ``Numeric`` datatype identifier." + "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." @@ -472,109 +472,35 @@ Cdms-Files. See “cu Module” on page 180. "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." "``Axis``", "``createAxis(id, ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numeric array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid, String datatype, Listaxes, fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MA`` typecode, e.g., ``MA.Float``, ``MA.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." + "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid, String datatype, Listaxes, fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self, whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." - -# +--------------------------+--------------------------+--------------------------+ -# | ``None`` | ``sync()`` | Writes any pending | -# | | | changes to the file. | -# +--------------------------+--------------------------+--------------------------+ -# | ``Variable`` | :: | Write a variable or | -# | | | array to the file. The | -# | | write(var, attribute | return value is the | -# | | s=None, axes=None, extbo | associated file | -# | | unds=None, id=None, exte | variable. | -# | | nd=None, fill_value=None | | -# | | , index=None, typecode=N | If the variable does not | -# | | one) | exist in the file, it is | -# | | | first defined and all | -# | | | attributes written, then | -# | | | the data is written. By | -# | | | default, the time | -# | | | dimension of the | -# | | | variable is defined as | -# | | | the unlimited dimension | -# | | | of the file. If the data | -# | | | is already defined, then | -# | | | data is extended or | -# | | | overwritten depending on | -# | | | the value of keywords | -# | | | ``extend`` and | -# | | | ``index``, and the | -# | | | unlimited dimension | -# | | | values associated with | -# | | | ``var``. | -# | | | | -# | | | ``var`` is a Variable, | -# | | | masked array, or Numeric | -# | | | array. ``attributes`` is | -# | | | the attribute dictionary | -# | | | for the variable. The | -# | | | default is | -# | | | ``var.attributes``. | -# | | | ``axes`` is the list of | -# | | | file axes comprising the | -# | | | domain of the variable. | -# | | | The default is to copy | -# | | | ``var.getAxisList()``. | -# | | | ``extbounds`` is the | -# | | | unlimited dimension | -# | | | bounds. Defaults to | -# | | | ``var.getAxis(0).getBoun | -# | | | ds()``. | -# | | | ``id`` is the variable | -# | | | name in the file. | -# | | | Default is ``var.id``. | -# | | | ``extend = 1`` causes | -# | | | the first dimension to | -# | | | be unlimited: | -# | | | iteratively writeable. | -# | | | The default is ``None``, | -# | | | in which case the first | -# | | | dimension is extensible | -# | | | if it is ``time.Set`` to | -# | | | ``0`` to turn off this | -# | | | behaviour. | -# | | | ``fill_value`` is the | -# | | | missing value flag. | -# | | | ``index`` is the | -# | | | extended dimension index | -# | | | to write to. The default | -# | | | index is determined by | -# | | | lookup relative to the | -# | | | existing extended | -# | | | dimension. | -# | | | | -# | | | **Note:** data can also | -# | | | be written by setting a | -# | | | slice of a file | -# | | | variable, and attributes | -# | | | can be written by | -# | | | setting an attribute of | -# | | | a file variable. | -# +--------------------------+--------------------------+--------------------------+ - - -Table 2.15 CDMS Datatypes - -+-----------------+-----------------------------------+ -| CDMS Datatype | Definition | -+=================+===================================+ -| ``CdChar`` | character | -+-----------------+-----------------------------------+ -| ``CdDouble`` | double-precision floating-point | -+-----------------+-----------------------------------+ -| ``CdFloat`` | floating-point | -+-----------------+-----------------------------------+ -| ``CdInt`` | integer | -+-----------------+-----------------------------------+ -| ``CdLong`` | long integer | -+-----------------+-----------------------------------+ -| ``CdShort`` | short integer | -+-----------------+-----------------------------------+ + "``None``", "``sync()``", "Writes any pending changes to the file." + "``Variable``", "``write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." + ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." + ,,"* ``var`` is a Variable, masked array, or Numpy array." + ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." + ,,"* ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``." + ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." + ,,"* ``id`` is the variable name in the file. Default is ``var.id``." + ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." + ,," * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." + ,,"* ``fill_value`` is the missing value flag." + ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." + ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." + +.. csv-table:: CDMS Datatypes + :header: "CDMS Datatype", "Definition" + :widths: 20, 30 + + "``CdChar``", "character" + "``CdDouble``", "double-precision floating-point" + "``CdFloat``", "floating-point" + "``CdInt``", "integer" + "``CdLong``", "long integer" + "``CdShort``", "short integer" Database @@ -654,155 +580,67 @@ To access a database: ``db.close()`` -Table 2.16 Database Internal Attributes - -+------------------+------------------+----------------------------------------+ -| Type | Name | Summary | -+==================+==================+========================================+ -| ``Dictionary`` | ``attributes`` | Database attribute dictionary | -+------------------+------------------+----------------------------------------+ -| ``LDAP`` | ``db`` | (LDAP only) LDAP database object | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``netloc`` | Hostname, for server-based databases | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``path`` | path name | -+------------------+------------------+----------------------------------------+ -| ``String`` | ``uri`` | Uniform Resource Identifier | -+------------------+------------------+----------------------------------------+ +.. csv-table:: Database Internal Attributes + :header: "Type", "Name", "Summary" + :widths: 20, 20, 80 + "``Dictionary``", "``attributes``", "Database attribute dictionary" + "``LDAP``", "``db``", "(LDAP only) LDAP database object" + "``String``", "``netloc``", "Hostname, for server-based databases" + "``String``", "``path``", "path name" + "``String``", "``uri``", "Uniform Resource Identifier" -Table 2.17 Database Constructors +------------ -+---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+=========================================================+==============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``db = cdms.connect(uri=None, user="", password="")`` | Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection | -+---------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Database Constructors + :header: "Constructor", "Description" + :widths: 30, 80 + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." + ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." + ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" -Table 2.18 Database Methods +------------ -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| None | ``close()`` | Close a database | -| | | connection. | -+--------------------------+--------------------------+--------------------------+ -| List | ``listDatasets()`` | Return a list of the | -| | | dataset IDs in this | -| | | database. A dataset ID | -| | | can be passed to the | -| | | ``open`` command. | -+--------------------------+--------------------------+--------------------------+ -| Dataset | ``open(dsetid, mode='r') | Open a dataset. | -| | `` | | -| | | ``dsetid`` is the string | -| | | dataset identifier | -| | | | -| | | ``mode`` is the open | -| | | mode, 'r' - read-only, | -| | | 'r+' - read-write, 'w' - | -| | | create. | -| | | | -| | | ``openDataset`` is a | -| | | synonym for ``open``. | -+--------------------------+--------------------------+--------------------------+ -| SearchResult | :: | Search a CDMS database. | -| | | | -| | searchFilter(filter= | ``filter`` is the string | -| | None, tag=None, relbase= | search filter. Simple | -| | None, scope=Subtree, att | filters have the form | -| | names=None, timeout=None | "tag = value". Simple | -| | ) | filters can be combined | -| | | using logical operators | -| | | '&', '\|', '!' in prefix | -| | | notation. | -| | | | -| | | **Example:** | -| | | | -| | | The filter | -| | | ``'(&(objec)(id=cli))'`` | -| | | finds all variables | -| | | named "cli". | -| | | | -| | | A formal definition of | -| | | search filters is | -| | | provided in the | -| | | following section. | -| | | | -| | | ``tag`` restricts the | -| | | search to objects with | -| | | that tag ("dataset" \| | -| | | "variable" \| "database" | -| | | \| "axis" \| "grid"). | -| | | | -| | | ``relbase`` is the | -| | | relative name of the | -| | | base object of the | -| | | search. The search is | -| | | restricted to the base | -| | | object and all objects | -| | | below it in the | -| | | hierarchy. | -| | | | -| | | **Example:** | -| | | | -| | | To search only dataset | -| | | 'ncep\_reanalysis\_mo', | -| | | specify: | -| | | | -| | | ``relbase="dataset=ncep_ | -| | | reanalysis_mo" `` | -| | | | -| | | To search only variable | -| | | 'ua' in | -| | | 'ncep\_reanalysis\_mo', | -| | | use: | -| | | | -| | | ``relbase="variable=ua,d | -| | | ataset=ncep_reanalysis_m | -| | | o"`` | -| | | | -| | | If no base is specified, | -| | | the entire database is | -| | | searched. See the | -| | | ``scope`` argument also. | -| | | | -| | | ``scope`` is the search | -| | | scope (**Subtree** \| | -| | | **Onelevel** \| | -| | | **Base**). | -| | | | -| | | - **Subtree** searches | -| | | the base object and | -| | | its descendants. | -| | | - **Onelevel** searches | -| | | the base object and | -| | | its immediate | -| | | descendants. | -| | | - **Base**\ searches | -| | | the base object | -| | | alone. | -| | | | -| | | The default is | -| | | **Subtree**. | -| | | | -| | | ``attnames``: list of | -| | | attribute names. | -| | | Restricts the attributes | -| | | returned. If ``None``, | -| | | all attributes are | -| | | returned. Attributes | -| | | 'id' and 'objectclass' | -| | | are always included in | -| | | the list. | -| | | | -| | | ``timeout``: integer | -| | | number of seconds before | -| | | timeout. The default is | -| | | no timeout. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: Database Methods + :header: "Type", "Method", "Definition" + :widths: 20, 30, 80 + + "None", "``close()``", "Close a database" + "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." + "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." + , "* ``dsetid``"," is the string dataset identifier" + , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." + , "* ``openDataset``", "is a synonym for ``open``." + "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." + ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." + ,, + ,," **Example:**" + ,," * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'." + ,," - A formal definition of search filters is provided in the following section." + ,," - ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." + ,," - ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." + ,, + ,," **Example:**" + ,," * To search only dataset 'ncep_reanalysis_mo', specify:" + ,," - ``relbase='dataset=ncep_reanalysis_mo'``" + ,," * To search only variable 'ua' in 'ncep_reanalysis_mo', use:" + ,," - ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``" + ,, + ,,"If no base is specified, the entire database is searched. See the ``scope`` argument also." + ,,"``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**)." + ,," * **Subtree** searches the base object and its descendants." + ,," * **Onelevel** searches the base object and its immediate descendants." + ,," * **Base**\ searches the base object alone." + ,," * The default is **Subtree**." + ,,"``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." + ,,"``timeout``: integer number of seconds before timeout. The default is no timeout." + + +------------ +.. highlight:: python + :linenothreshold: 0 2.7.2 Searching a database @@ -815,44 +653,23 @@ to those objects having an attribute which matches the filter. Simple filters have the form (tag = value), where value can contain wildcards. For example: -.. raw:: html +:: -
- -:: - - (id = ncep*) - (project = AMIP2) - -.. raw:: html - -
+ (id = ncep*) + (project = AMIP2) -+--------------------------------------------------------------------+------------------------+ -| Simple filters can be combined with the logical operators ‘&’, ‘ | ’, ‘!’. For example, | -+--------------------------------------------------------------------+------------------------+ - -.. raw:: html - -
+**Note** Simple filters can be combined with the logical operators '&', '|', '!'. For example, :: - (&(id = bmrc*)(project = AMIP2)) + (&(id = bmrc*)(project = AMIP2)) -.. raw:: html - -
matches all objects with id starting with bmrc, and a project attribute with value ‘AMIP2’. Formally, search filters are strings defined as follows: -.. raw:: html - -
- :: filter ::= "(" filtercomp ")" @@ -873,9 +690,6 @@ Formally, search filters are strings defined as follows: tag ::= string attribute name value ::= string attribute value, may include '*' as a wild card -.. raw:: html - -
Attribute names are defined in the chapter on “Climate Data Markup Language (CDML)” on page 149. In addition, some special attributes are @@ -903,28 +717,16 @@ several ways: - The search can be restricted to the result of a previous search. - A search result is accessed sequentially within a for loop: -.. raw:: html - -
- :: result = db.searchFilter('(&(category=obs*)(id=ncep*))') for entry in result: print entry.name -.. raw:: html - -
- Search results can be narrowed using ``searchPredicate``. In the following example, the result of one search is itself searched for all variables defined on a 94x192 grid: -.. raw:: html - -
- :: >>> result = db.searchFilter('parentid=ncep*',tag="variable") @@ -946,9 +748,6 @@ variables defined on a 94x192 grid: o=LLNL, c=US -.. raw:: html - -
Table 2.19 SearchResult Methods @@ -1003,93 +802,48 @@ To access data via CDMS: In the next example, a portion of variable ‘ua’ is read from dataset ‘ncep\_reanalysis\_mo’: -.. raw:: html - -
- :: dset = db.open('ncep_reanalysis_mo') ua = dset.variables['ua'] data = ua[0,0] -.. raw:: html - -
- 2.7.4 Examples of database searches In the following examples, db is the database opened with -.. raw:: html - -
- :: db = cdms.connect() -.. raw:: html - -
- This defaults to the database defined in environment variable ``CDMSROOT``. **Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: -.. raw:: html - -
- :: - for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", - tag = "variable"): + for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): print entry.name -.. raw:: html - -
**Example:** Find all axes with bounds defined: -.. raw:: html - -
- :: for entry in db.searchFilter(filter="bounds=*",tag="axis"): print entry.name -.. raw:: html - -
**Example:** Locate all GDT datasets: -.. raw:: html - -
- :: - for entry in - db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): print entry.name -.. raw:: html - -
- -**Example:** Find all variables with missing time values, in observed -datasets: - -.. raw:: html - -
+**Example:** Find all variables with missing time values, in observed datasets: :: @@ -1101,63 +855,30 @@ datasets: for entry in result.searchPredicate(missingTime): print entry.name -.. raw:: html - -
- **Example:** Find all CMIP2 datasets having a variable with id “hfss”: -.. raw:: html - -
- :: for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): print entry.getObject().parent.id -.. raw:: html - -
- **Example:** Find all observed variables on 73x144 grids: -.. raw:: html - -
- :: result = db.searchFilter(category='obs*') for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): print entry.name -.. raw:: html - -
- **Example:** Find all observed variables with more than 1000 timepoints: -.. raw:: html - -
- :: result = db.searchFilter(category='obs*') for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): print entry.name, len(entry.getObject().getTime()) -.. raw:: html - -
- -**Example:** Find the total number of each type of object in the -database - -.. raw:: html - -
+**Example:** Find the total number of each type of object in the database :: @@ -1166,10 +887,6 @@ database print len(db.searchFilter(tag="variable")),"variables" print len(db.searchFilter(tag="axis")),"axes" -.. raw:: html - -
- Dataset ^^^^^^^ @@ -1318,7 +1035,7 @@ Table 2.25 Dataset Methods | | | | | | | If specified, ``mask`` | | | | is a two-dimensional, | -| | | logical Numeric array | +| | | logical Numpy array | | | | (all values are zero or | | | | one) with the same shape | | | | as the grid. | @@ -1387,15 +1104,15 @@ MV module The fundamental CDMS data object is the variable. A variable is comprised of: -- a masked data array, as defined in the NumPy MA module. +- a masked data array, as defined in the NumPy MV2 module. - a domain: an ordered list of axes and/or grids. - an attribute dictionary. -The MV module is a work-alike replacement for the MA module, that +The MV module is a work-alike replacement for the MV2 module, that carries along the domain and attribute information where appropriate. MV -provides the same set of functions as MA. However, MV functions generate +provides the same set of functions as MV2. However, MV functions generate transient variables as results. Often this simplifies scripts that -perform computation. MA is part of the Python Numeric package, +perform computation. MV2 is part of the Python Numpy package, documented at http://www.numpy.org. MV can be imported with the command: @@ -1449,12 +1166,12 @@ attribute, it can also be set like any attribute: -For completeness MV provides access to all the MA functions. The +For completeness MV provides access to all the MV2 functions. The functions not listed in the following tables are identical to the -corresponding MA function: ``allclose``, ``allequal``, +corresponding MV2 function: ``allclose``, ``allequal``, ``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, ``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, -``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMA``, +``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMV2``, ``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, ``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, ``putmask``, ``rank``, ``ravel``, ``set_fill_value``, @@ -1467,9 +1184,9 @@ Table 2.26 Variable Constructors in module MV +--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Constructor | Description | +====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MA.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | +| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | +--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MA.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | +| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | +--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | +--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -1493,7 +1210,7 @@ Table 2.27 MV functions +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Function | Description | +=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+ -| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numeric array of indices for sorting along a given axis. | +| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numpy array of indices for sorting along a given axis. | +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``asarray(data, typecode=None)`` | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function. | +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -1541,7 +1258,7 @@ Table 2.27 MV functions +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``sum(a, axis=0, fill_value=0)`` | Sum of elements along a certain axis using ``fill_value`` for missing. | +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numeric manual. | +| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numpy manual. | +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``transpose(ar, axes=None)`` | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes. | +---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -1639,7 +1356,7 @@ Table 2.31 HorizontalGrid Methods | | | ``(latitudeArray, longit | | | | udeArray)``, | | | | where latitudeArray is a | -| | | Numeric array of | +| | | Numpy array of | | | | latitude bounds, and | | | | similarly for | | | | longitudeArray.The shape | @@ -1709,7 +1426,7 @@ Table 2.31 HorizontalGrid Methods | Axis | ``getMask()`` | Get the mask array of | | | | this grid, if | | | | any.Returns a 2-D | -| | | Numeric array, having | +| | | Numpy array, having | | | | the same shape as the | | | | grid. If the mask is not | | | | explicitly defined, the | @@ -1760,7 +1477,7 @@ Table 2.31 HorizontalGrid Methods | | | the grid, but no I/O is | | | | generated. ``mask`` is a | | | | two-dimensional, | -| | | Boolean-valued Numeric | +| | | Boolean-valued Numpy | | | | array, having the same | | | | shape as the grid. | +--------------------------+--------------------------+--------------------------+ @@ -2027,8 +1744,8 @@ Table 2.34 Variable Constructors +--------------------------------------+--------------------------------------+ | ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | | String datatype, List axesOr- | ``id`` is the name of the variable. | -| Grids)`` | ``datatype`` is the MA or Numeric | -| | typecode, for example, MA.Float. | +| Grids)`` | ``datatype`` is the MV2 or Numpy | +| | typecode, for example, MV2.Float. | | | ``axesOrGrids`` is a list of Axis | | | and/or Grid objects, on which the | | | variable is defined. Specifying a | @@ -2045,8 +1762,8 @@ Table 2.34 Variable Constructors | :: | Create a transient variable, not | | | associated with a file or dataset. | | cdms.createVariable(array, typec | ``array`` is the data values: a | -| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numeric | -| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MA | +| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numpy | +| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MV2 | | s=None,attributes=None, id=None) | typecode of the array. Defaults to | | | the typecode of array. ``copy`` is | | | an integer flag: if 1, the variable | @@ -2054,14 +1771,14 @@ Table 2.34 Variable Constructors | | if 0 the variable data is shared | | | with array. ``savespace`` is an | | | integer flag: if set to 1, internal | -| | Numeric operations will attempt to | +| | Numpy operations will attempt to | | | avoid silent upcasting. ``mask`` is | | | an array of integers with value 0 or | | | 1, having the same shape as array. | | | array elements with a corresponding | | | mask value of 1 are considered | | | invalid, and are not used for | -| | subsequent Numeric operations. The | +| | subsequent Numpy operations. The | | | default mask is obtained from array | | | if present, otherwise is None. | | | ``fill_value`` is the missing value | @@ -2133,8 +1850,8 @@ Table 2.35 Variable Methods +--------------------------+--------------------------+--------------------------+ | Variable | ``astype(typecode)`` | Cast the variable to a | | | | new datatype. Typecodes | -| | | are as for MV, MA, and | -| | | Numeric modules. | +| | | are as for MV, MV2, and | +| | | Numpy modules. | +--------------------------+--------------------------+--------------------------+ | Variable | ``clone(copyData=1)`` | Return a copy of a | | | | transient variable. | @@ -2450,7 +2167,7 @@ Table 2.35 Variable Methods | | | of array match the input | | | | grid. | | | | | -| | | ``mask`` is a Numeric | +| | | ``mask`` is a Numpy | | | | array, of datatype | | | | Integer or Float, | | | | consisting of ones and | @@ -2569,7 +2286,7 @@ Table 2.35 Variable Methods | | | axes and attributes | | | | corresponding to2,3 the | | | | region read. If raw=1, | -| | | an MA masked array is | +| | | an MV2 masked array is | | | | returned, equivalent to | | | | the transient variable | | | | without the axis and | @@ -2637,7 +2354,7 @@ Table 2.35 Variable Methods | | | dimension, as in normal | | | | Python indexing. | +--------------------------+--------------------------+--------------------------+ -| String | ``typecode()`` | The Numeric datatype | +| String | ``typecode()`` | The Numpy datatype | | | | identifier. | +--------------------------+--------------------------+--------------------------+ @@ -2856,7 +2573,7 @@ Table 2.38 Selector keywords +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ | ``order`` | Reorder the result. | Order string, e.g., “tzyx” | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``raw`` | Return a masked array (MA.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | +| ``raw`` | Return a masked array (MV2.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ | ``required`` | Require that the axis IDs be present. | List of axis identifiers. | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 2d760269..fe880a17 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -61,10 +61,10 @@ variable regridded to the target grid: A somewhat more efficient method is to create a regridder function. This has the advantage that the mapping is created only once and can be used for multiple arrays. Also, this method can be used with data in the form -of an MA.MaskedArray. The steps in this process are: +of an MV2.MaskedArray. The steps in this process are: #. Given an input grid and output grid, generate a regridder function. -#. Call the regridder function on a Numeric array, resulting in an array +#. Call the regridder function on a Numpy array, resulting in an array defined on the output grid. The regridder function can be called with any array or variable defined on the input grid. @@ -416,12 +416,12 @@ Table 4.3 CDMS Regridder function :widths: 40, 40, 80 "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." - , , "``array`` is a Variable, masked array, or Numeric array of rank 2, 3, or 4." + , , "``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4." , , , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" - , , "- ``mask`` is a Numeric array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MA module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." + , , "- ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." , , "``dataArray`` is the result data array." @@ -474,21 +474,21 @@ Table 4.4 SCRIP Regridder functions +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Return Type | Method | Description | +===============================+============================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| Array or Transient-Variable | [conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)`` | Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. | +| Array or Transient-Variable | [conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)`` | Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Array or Transient-Variable | [bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)`` |

Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.

\ ``array`` is a Variable, MaskedArray, or Numeric array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.

\ ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.

gradientLon: df/dj. Same shape as ``array``.

\ ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.

| +| Array or Transient-Variable | [bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)`` |

Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.

\ ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.

\ ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.

gradientLon: df/dj. Same shape as ``array``.

\ ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.

| +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numeric array | ``getDestinationArea()`` [conservative regridders only] | Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid. | +| Numpy array | ``getDestinationArea()`` [conservative regridders only] | Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numeric array | ``getDestinationFraction()`` | Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid. | +| Numpy array | ``getDestinationFraction()`` | Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | CurveGrid or Generic-Grid | ``getInputGrid()`` | Return the input grid, or None if no input grid is associated with the regridder. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | CurveGrid or Generic-Grid | ``getOutputGrid()`` | Return the output grid. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numeric array | ``getSourceArea()`` [conservative regridders only] | Return the area of the source (input) grid cell. The array is 1- D, with length equal to the number of cells in the input grid. | +| Numpy array | ``getSourceArea()`` [conservative regridders only] | Return the area of the source (input) grid cell. The array is 1- D, with length equal to the number of cells in the input grid. | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numeric array | ``getSourceFraction()`` | Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid | +| Numpy array | ``getSourceFraction()`` | Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid | +-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 4.4 Examples diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 78fe175c..17050141 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -143,7 +143,7 @@ where: - canvas is a VCS Canvas object, created with the vcs.init method. -- array is a variable, masked array, or Numeric array having between +- array is a variable, masked array, or Numpy array having between two and five dimensions. The last dimensions of the array is termed the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', and 'w'. For example, if array is three-dimensional, the axes are @@ -196,9 +196,9 @@ where: ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" "``units``", "string", "Data units. Defaults to ``variable.units``" "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." - "``xarray`` (``[y|z|t|w]array``)", "1-D Numeric array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to xaxis[:\] (y|z|t|waxis[:])" + "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to xaxis[:\] (y|z|t|waxis[:])" "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" - "``xbounds`` (``ybounds``)", "2-D Numeric array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." + "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the x-axis (y-axis). Defaults to 0, with the following exceptions:" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index bca05b9b..d56ad2c4 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -62,9 +62,9 @@ Release 3.0 Overview CDMS version 3.0 is a significant enhancement of previous versions. The major changes were: -- UV-CDAT/CDMS was integrated with the Numerical Python masked array - class MA.MaskedVariable. The MV submodule was added as a wrapper - around MA. +- UV-CDAT/CDMS was integrated with the Numpyal Python masked array + class MV2.MaskedVariable. The MV submodule was added as a wrapper + around MV. - Methods that read data, such as subRegion, subSlice, and the slice operations, return instances of class TransientVariable. The plot and regrid modules were modified to handle masked array input. The @@ -81,7 +81,7 @@ major changes were: allows CDMS classes to be subclassed more readily. - The class Variable was renamed DatasetVariable. - The cu module was emulated in cdms. cu and cdms methods can be mixed. -- The code was modularized, so that Python, CDMS, and Numerical Python +- The code was modularized, so that Python, CDMS, and Numpyal Python can be built and installed separately. This significantly enhances the portability of the code. @@ -94,7 +94,7 @@ AbstractVariable - Functions getDomain, getSlice, rank, regrid, setMissing, size, subRegion, and subSlice were added. - The functions getRegion, getSlice, getValue, and the slice operators - all return an instance of MA, a masked array. Singleton dimensions + all return an instance of MV, a masked array. Singleton dimensions are squeezed. - The functions subRegion and subSlice return an instance of TransientVariable. Singleton dimensions are not squeezed. @@ -140,7 +140,7 @@ CdmsFile '''''''' - The function createVariable has a keyword fill\_value. The datatype - may be a Numeric/MA typecode. + may be a Numpy/MV typecode. - The function write was added. CDMSError @@ -164,7 +164,7 @@ TransientVariable ''''''''''''''''' - The class TransientVariable was added. It inherits from both - AbstractVariable and MA. + AbstractVariable and MV. - The cdms module function createVariable returns a transient variable. - This class does not implement the functions getPaths or getTemplate. From 89c45b99489bd26ccab0a876d039dc8c8e393b58 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 16 Jan 2018 18:12:51 -0800 Subject: [PATCH 041/239] continue cdms2 documentations --- docs/source/manual/cdms_2.rst | 1710 +++++++-------------------------- 1 file changed, 337 insertions(+), 1373 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index fa011af5..80329b1f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -371,7 +371,7 @@ Axis objects. ,,"* ``(x,y,indicator)``" ,,"* ``(x,y,indicator,cycle)``" ,,"* ``None or ':'``" - ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" + ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:" ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" ,,"* ``'n'`` - select node values which are contained in the interval" ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" @@ -752,15 +752,14 @@ variables defined on a 94x192 grid: Table 2.19 SearchResult Methods -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+================+============================================+==================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ResultEntry | ``[i]`` | Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):`` | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Integer | ``len()`` | Number of entries in the result. | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| SearchResult | ``searchPredicate(predicate, tag=None)`` | Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag. **Note**: In the current implementation, ``searchPredicate``\ is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches. | -+----------------+--------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: SearchResult Methods + :header: "Type", "Method", "Definition" + :widths: 20, 30, 80 + + "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):``" + "Integer", "``len()``", "Number of entries in the result." + "SearchResult", " ``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." + ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -773,22 +772,22 @@ with the ``getObject`` method. Table 2.20 ResultEntry Attributes -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ -| Type | Name | Description | -+==============+==================+=======================================================================================================================+ -| String | ``name`` | The name of this entry in the database. | -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ -| Dictionary | ``attributes`` | The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key | -+--------------+------------------+-----------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: ResultEntry Attributes + :header: "Type", "Method", "Definition" + :widths: 20, 30, 80 + + "String", "``name``", "The name of this entry in the database." + "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" Table 2.21 ResultEntry Methods -+---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Type | Method | Definition | -+===============+===================+======================================================================================================================================================================================================================================================================================+ -| ``CdmsObj`` | ``getObject()`` | Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. | -+---------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: ResultEntry Methods + :header: "Type", "Method", "Definition" + :widths: 20, 30, 80 + + "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry." + ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." 2.7.3 Accessing data @@ -800,7 +799,7 @@ To access data via CDMS: #. Reference the portion of the variable to be read. In the next example, a portion of variable ‘ua’ is read from dataset -‘ncep\_reanalysis\_mo’: +‘ncep_reanalysis_mo’: :: @@ -899,203 +898,76 @@ See “cu Module” on page 180. Table 2.22 Dataset Internal Attributes -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Type | Name | Description | -+==============+==================+==========================================================================================================+ -| Dictionary | ``attributes`` | Dataset external attributes. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``axes`` | Axes contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``datapath`` | Path of data files, relative to the parent database. If no parent, the datapath is absolute. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``grids`` | Grids contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``mode`` | Open mode. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Database | ``parent`` | Database which contains this dataset. If the dataset is not part of a database, the value is ``None``. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| String | ``uri`` | Uniform Resource Identifier of this dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``variables`` | Variables contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ -| Dictionary | ``xlinks`` | External links contained in the dataset. | -+--------------+------------------+----------------------------------------------------------------------------------------------------------+ +.. csv-table:: Dataset Internal Attributes + :header: "Type", "Name", "Description" + :widths: 20, 30, 80 + "Dictionary", "``attributes``", "Dataset external attributes." + "Dictionary", "``axes``", "Axes contained in the dataset." + "String", "``datapath``", "Path of data files, relative to the parent database. If no parent, the datapath is absolute." + "Dictionary", "``grids``", "Grids contained in the dataset." + "String", "``mode``", "Open mode." + "Database", "``parent``", "Database which contains this dataset. If the dataset is not part of a database, the value is ``None``." + "String", "``uri``", "Uniform Resource Identifier of this dataset." + "Dictionary", "``variables``", "Variables contained in the dataset." + "Dictionary", "``xlinks``", "External links contained in the dataset." Table 2.23 Dataset Constructors -+-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+===========================================================+===================================================================================================================================================================================================================+ -| ``datasetobj = cdms.open(String uri, String mode='r')`` | Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open`` | -+-----------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Dataset Internal Attributes + :header: "Constructor", "Description" + :widths: 50, 80 + + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open``" Table 2.24 Open Modes -+--------+-----------------------------------------------------------------------+ -| Mode | Definition | -+========+=======================================================================+ -| ‘r’ | read-only | -+--------+-----------------------------------------------------------------------+ -| ‘r+’ | read-write | -+--------+-----------------------------------------------------------------------+ -| ‘a’ | read-write. Open the file if it exists, otherwise create a new file | -+--------+-----------------------------------------------------------------------+ -| ‘w’ | Create a new file, read-write | -+--------+-----------------------------------------------------------------------+ +.. csv-table:: Open Modes + :header: "Mode", "Definition" + :widths: 50, 80 + + "‘r’", " read-only" + "‘r+’", "read-write" + "‘a’", "read-write. Open the file if it exists, otherwise create a new file" + "‘w’", " Create a new file, read-write" Table 2.25 Dataset Methods -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| Transient-Variable | ``datasetobj(varname, se | Calling a Dataset object | -| | lector)`` | as a function reads the | -| | | region of data defined | -| | | by the selector. The | -| | | result is a transient | -| | | variable, unless | -| | | ``raw = 1`` is | -| | | specified. See | -| | | "Selectors" on page 103. | -| | | **Example:** The | -| | | following reads data for | -| | | variable 'prc', year | -| | | 1980: | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('test. | -| | | xml') | -| | | x = f('prc', time=(' | -| | | 1980-1','1981-1')) | -+--------------------------+--------------------------+--------------------------+ -| Variable, Axis, or Grid | ``datasetobj['id']`` | The square bracket | -| | | operator applied to a | -| | | dataset gets the | -| | | persistent variable, | -| | | axis or grid object | -| | | having the string | -| | | identifier. This does | -| | | not read the data for a | -| | | variable. Returns | -| | | ``None`` if not found. | -| | | | -| | | **Example:** | -| | | | -| | | :: | -| | | | -| | | f = cdms.open('sampl | -| | | e.xml') | -| | | v = f['prc'] | -| | | | -| | | gets the persistent | -| | | variable v, equivalent | -| | | to | -| | | ``v = f.variab | -| | | les['prc']``. | -| | | | -| | | **Example:** | -| | | | -| | | | ``t = f['time']`` | -| | | | gets the axis named | -| | | 'time', equivalent to | -| | | ``t = f.axes['time']`` | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``close()`` | Close the dataset. | -+--------------------------+--------------------------+--------------------------+ -| ``RectGrid`` | ``createRectGrid(id, lat | Create a RectGrid in the | -| | , lon, order, type="gene | dataset. This is not a | -| | ric", mask=Non | persistent object: the | -| | e)`` | order, type, and mask | -| | | are not written to the | -| | | dataset. However, the | -| | | grid may be used for | -| | | regridding operations. | -| | | | -| | | ``lat`` is a latitude | -| | | axis in the dataset. | -| | | | -| | | ``lon`` is a longitude | -| | | axis in the dataset. | -| | | | -| | | ``order`` is a string | -| | | with value "yx" (the | -| | | first grid dimension is | -| | | latitude) or "xy" (the | -| | | first grid dimension is | -| | | longitude). | -| | | | -| | | ``type`` is one of | -| | | 'gaussian','uniform','eq | -| | | ualarea',or | -| | | 'generic' | -| | | | -| | | If specified, ``mask`` | -| | | is a two-dimensional, | -| | | logical Numpy array | -| | | (all values are zero or | -| | | one) with the same shape | -| | | as the grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(id)`` | Get an axis object from | -| | | the file or dataset. | -| | | | -| | | ``id`` is the string | -| | | axis identifier. | -+--------------------------+--------------------------+--------------------------+ -| Grid | ``getGrid(id)`` | Get a grid object from a | -| | | file or dataset. | -| | | | -| | | ``id`` is the string | -| | | grid identifier. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getPaths()`` | Get a sorted list of | -| | | pathnames of datafiles | -| | | which comprise the | -| | | dataset. This does not | -| | | include the XML metafile | -| | | path, which is stored in | -| | | the .uri attribute. | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``getVariable(id)`` | Get a variable object | -| | | from a file or dataset. | -| | | | -| | | ``id`` is the string | -| | | variable identifier. | -+--------------------------+--------------------------+--------------------------+ -| CurveGrid or GenericGrid | ``readScripGrid(self, wh | Read a curvilinear or | -| | ichGrid='destination', c | generic grid from a | -| | heck-or Generic-Grid=1)` | SCRIP dataset. The | -| | ` | dataset can be a SCRIP | -| | | grid file or remapping | -| | | file. | -| | | | -| | | If a mapping file, | -| | | ``whichGrid`` chooses | -| | | the grid to read, either | -| | | ``"source"`` or | -| | | ``"destination"``. | -| | | | -| | | If ``checkGrid`` is 1 | -| | | (default), the grid | -| | | cells are checked for | -| | | convexity, and | -| | | 'repaired' if necessary. | -| | | Grid cells may appear to | -| | | be nonconvex if they | -| | | cross a ``0 / 2pi`` | -| | | boundary. The repair | -| | | consists of shifting the | -| | | cell vertices to the | -| | | same side modulo 360 | -| | | degrees. | -+--------------------------+--------------------------+--------------------------+ -| None | ``sync()`` | Write any pending | -| | | changes to the dataset. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: Dataset Methods + :header: "Type", "Definition", "Description" + :widths: 30, 30, 80 + + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See "Selectors" on page 103." + ,, "**Example:** The following reads data for variable 'prc', year 1980:" + ,, " * f = cdms.open('test. xml')" + ,, " * x = f('prc', time=('1980-1','1981-1'))" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found." + ,, "**Example:**" + ,, " * f = cdms.open('sampl e.xml')" + ,, " * v = f['prc']" + ,, " * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``." + ,, "**Example:**" + ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" + "``None``", "``close()``", "Close the dataset." + "``RectGrid``", "``createRectGrid(id, lat, lon, order, type="generic", mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." + ,,"``lat`` is a latitude axis in the dataset." + ,,"``lon`` is a longitude axis in the dataset." + ,,"``order`` is a string with value "yx" (the first grid dimension is latitude) or "xy" (the first grid dimension is longitude)." + ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" + ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." + ,,"``id`` is the string axis identifier." + "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset." + ,,"``id`` is the string grid identifier." + "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." + "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." + ,,"``id`` is the string variable identifier." + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-or Generic-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." + ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``"source"`` or ``"destination"``." + ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "None", "``sync()``", "Write any pending changes to the dataset." MV module @@ -1117,35 +989,20 @@ documented at http://www.numpy.org. MV can be imported with the command: -.. raw:: html - -
- :: import MV -.. raw:: html - -
- The command -.. raw:: html - -
- :: from MV import * -.. raw:: html - -
allows use of MV commands without any prefix. -Table 2.26 on page 75 lists the constructors in MV. All functions return +Table 2.26 lists the constructors in MV. All functions return a transient variable. In most cases the keywords axes, attributes, and id are available. axes is a list of axis objects which specifies the domain of the variable. attributes is a dictionary. id is a special @@ -1154,18 +1011,10 @@ should not contain blanks or non-printing characters. It is used when the variable is plotted or written to a file. Since the id is just an attribute, it can also be set like any attribute: -.. raw:: html - -
- :: var.id = 'temperature' -.. raw:: html - -
- For completeness MV provides access to all the MV2 functions. The functions not listed in the following tables are identical to the corresponding MV2 function: ``allclose``, ``allequal``, @@ -1181,25 +1030,18 @@ http://numpy.sourceforge.net for a description of these functions. Table 2.26 Variable Constructors in module MV -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Constructor | Description | -+====================================================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`` | Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange`` | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`` | Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`` | Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | return an array of all ones of the given length or shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``reshape(a, newshape, axes=none, attributes=none, id=none)`` | copy of a with a new shape. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``resize(a, new_shape, axes=none, attributes=none, id=none)`` | return a new array with the specified shape. the original arrays total size can be any size. | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`` | an array of all zeros of the given length or shape | -+--------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Variable Constructors in module MV + :header: "Constructor", "Description" + :widths: 30, 80 + + "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange``" + "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." + "``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." + "``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead." + "``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." + "``reshape(a, newshape, axes=none, attributes=none, id=none)``", "copy of a with a new shape." + "``resize(a, new_shape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size". + "``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "an array of all zeros of the given length or shape" The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. @@ -1207,63 +1049,37 @@ exception of argsort, all functions return a transient variable. Table 2.27 MV functions -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Function | Description | -+=====================================================================+======================================================================================================================================================================================================================================================================================================================================================================+ -| ``argsort(x, axis=-1, fill_value=None)`` | Return a Numpy array of indices for sorting along a given axis. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``asarray(data, typecode=None)`` | Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``average(a, axis=0, weights=None)`` | Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``choose(condition, t)`` | Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``concatenate(arrays, axis=0, axisid=None, axisattributes=None)`` | Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``count(a, axis=None)`` | Count of the non-masked elements in ``a``, or along a certain axis. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``isMaskedVariable(x)`` | Return true if ``x`` is an instance of a variable. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_equal(x, value)`` | ``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_greater(x, value)`` | ``x`` masked where ``x > value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_greater_equal(x, value)`` | ``x`` masked where ``x >= value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_less(x, value)`` | ``x`` masked where ``x < value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_less_equal(x, value)`` | ``x`` masked where ``x ≤ value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_not_equal(x, value)`` | ``x`` masked where ``x != value`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_outside(x, v1, v2)`` | ``x`` with mask of all values of ``x`` that are outside ``[v1,v2]`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``masked_where(condition, x, copy=1)`` | Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``maximum(a, b=None)`` | Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``minimum(a, b=None)`` | Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``outerproduct(a, b)`` | Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``power(a, b)`` | ``a**b`` | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``product(a, axis=0, fill_value=1)`` | Product of elements along axis using ``fill_value`` for missing elements. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``repeat(ar, repeats, axis=0)`` | Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``set_default_fill_value(value_type, value)`` | Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sort(ar, axis=-1)`` | Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sum(a, axis=0, fill_value=0)`` | Sum of elements along a certain axis using ``fill_value`` for missing. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``take(a, indices, axis=0)`` | Return a selection of items from ``a``. See the documentation in the Numpy manual. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``transpose(ar, axes=None)`` | Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes. | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``where(condition, x, y)`` | ``x`` where ``condition`` is true, ``y`` otherwise | -+---------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: MV functions + :header: "Function", "Description" + :widths: 30, 80 + + "``argsort(x, axis=-1, fill_value=None)``", "Return a Numpy array of indices for sorting along a given axis." + "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function." + "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." | + "``choose(condition, t)``", "Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked." + "``concatenate(arrays, axis=0, axisid=None, axisattributes=None)``", "Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array." + "``count(a, axis=None)``", "Count of the non-masked elements in ``a``, or along a certain axis." + "``isMaskedVariable(x)``", "Return true if ``x`` is an instance of a variable." + "``masked_equal(x, value)``", "``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead." + "``masked_greater(x, value)``", "``x`` masked where ``x > value``" + "``masked_greater_equal(x, value)``", "``x`` masked where ``x >= value``" + "``masked_less(x, value)``", "``x`` masked where ``x < value``" + "``masked_less_equal(x, value)``", "``x`` masked where ``x ≤ value``" + "``masked_not_equal(x, value)``", "``x`` masked where ``x != value``" + "``masked_outside(x, v1, v2)``", "``x`` with mask of all values of ``x`` that are outside ``[v1,v2]``" + "``masked_where(condition, x, copy=1)``", "Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``." + "``maximum(a, b=None)``", "Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked." + "``minimum(a, b=None)``", "Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked." + "``outerproduct(a, b)``", "Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked." + "``power(a, b)``", "``a**b``" + "``product(a, axis=0, fill_value=1)``", "Product of elements along axis using ``fill_value`` for missing elements." + "``repeat(ar, repeats, axis=0)``", "Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element." + "``set_default_fill_value(value_type, value)``", "Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array." + "``sort(ar, axis=-1)``", "Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values." + "``sum(a, axis=0, fill_value=0)``", "Sum of elements along a certain axis using ``fill_value`` for missing." + "``take(a, indices, axis=0)``", "Return a selection of items from ``a``. See the documentation in the Numpy manual." + "``transpose(ar, axes=None)``", "Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes." + "``where(condition, x, y)``", "``x`` where ``condition`` is true, ``y`` otherwise" HorizontalGrid @@ -1283,410 +1099,109 @@ CDMS supports several types of HorizontalGrids: Table 2.28 -+-------------------+----------------------------------------------------------------------------------+ -| Grid Type | Definition | -+===================+==================================================================================+ -| ``RectGrid`` | Associated latitude an longitude are 1-D axes, with strictly monotonic values. | -+-------------------+----------------------------------------------------------------------------------+ -| ``CurveGrid`` | Latitude and longitude are 2-D coordinate axes (Axis2D). | -+-------------------+----------------------------------------------------------------------------------+ -| ``GenericGrid`` | Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D) | -+-------------------+----------------------------------------------------------------------------------+ +.. csv-table:: Grids + :header: "Grid Type", "Definition" + :widths: 30, 80 + + "``RectGrid``", "Associated latitude an longitude are 1-D axes, with strictly monotonic values." + "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" Table 2.29 HorizontalGrid Internal Attribute -+-----------------------+------------------+------------------------------------------------+ -| Type | Name | Definition | -+=======================+==================+================================================+ -| Dictionary | ``attributes`` | External attribute dictionary. | -+-----------------------+------------------+------------------------------------------------+ -| String | ``id`` | The grid identifier. | -+-----------------------+------------------+------------------------------------------------+ -| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the grid. | -+-----------------------+------------------+------------------------------------------------+ -| Tuple | ``shape`` | The shape of the grid, a 2-tuple | -+-----------------------+------------------+------------------------------------------------+ +.. csv-table:: HorizontalGrid Internal Attribute + :header: "Type", "Name", "Definition" + :widths: 30, 30, 80 -Table 2.31 on page 82 describes the methods that apply to all types of -HorizontalGrids. Table 2.32 on page 86 describes the additional methods -that are unique to RectGrids. + "Dictionary","``attributes``", "External attribute dictionary." + "String", "``id``", "The grid identifier." + "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." + "Tuple", "``shape``", "The shape of the grid, a 2-tuple" Table 2.30 RectGrid Constructors -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| Constructor | Description | -+=========================================================================================================+==================================================================================+ -| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | Create a grid not associated with a file or dataset. See Table 2.2 on page 33. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``CdmsFile.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a file. See Table 2.14 on page 53. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``Dataset.createRectGrid(id, lat, lon, order, type="generic", mask=None)`` | Create a grid associated with a dataset. See Table 2.25 on page 71. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGaussianGrid(nlats, xorigin=0.0, order="yx")`` | See Table 2.2 on page 33. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createGlobalMeanGrid(grid)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createRectGrid(lat, lon, order, type="generic", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None)`` | See Table 2.2 on page 18. | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ -| ``cdms.createZonalGrid(grid)`` | See Table 2.2 on page 18 | -+---------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------+ +.. csv-table:: RectGrid Constructors + :header: "Constructor", "Description" + :widths: 30, 80 + + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See Table 2.2" + "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" + "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" + "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See Table 2.2" + "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See Table 2.2" + "``cdms.createGlobalMeanGrid(grid)``", "See Table 2.2." + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "See Table 2.2" + "``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None)``", "See Table 2.2" + "``cdms.createZonalGrid(grid)``", " See Table 2.2" Table 2.31 HorizontalGrid Methods -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Description | -+==========================+==========================+==========================+ -| Horizontal-Grid | ``clone()`` | Return a transient copy | -| | | of the grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(Integer n)`` | Get the n-th axis.n is | -| | | either 0 or 1. | -+--------------------------+--------------------------+--------------------------+ -| Tuple | ``getBounds()`` | Get the grid boundary | -| | | arrays. | -| | | | -| | | Returns a tuple | -| | | ``(latitudeArray, longit | -| | | udeArray)``, | -| | | where latitudeArray is a | -| | | Numpy array of | -| | | latitude bounds, and | -| | | similarly for | -| | | longitudeArray.The shape | -| | | of latitudeArray and | -| | | longitudeArray depend on | -| | | the type of grid: | -| | | | -| | | - for rectangular grids | -| | | with shape (nlat, | -| | | nlon), the boundary | -| | | arrays have shape | -| | | (nlat,2) and | -| | | (nlon,2). | -| | | - for curvilinear grids | -| | | with shape (nx, ny), | -| | | the boundary arrays | -| | | each have shape (nx, | -| | | ny, 4). | -| | | - for generic grids | -| | | with shape (ncell,), | -| | | the boundary arrays | -| | | each have shape | -| | | (ncell, nvert) where | -| | | nvert is the maximum | -| | | number of vertices | -| | | per cell. | -| | | | -| | | For rectilinear grids: | -| | | If no boundary arrays | -| | | are explicitly defined | -| | | (in the file or | -| | | dataset), the result | -| | | depends on the auto- | -| | | Bounds mode (see | -| | | ``cdms.setAutoBounds``) | -| | | and the grid | -| | | classification mode (see | -| | | ``cdms.setClassifyGrids` | -| | | `). | -| | | By default, autoBounds | -| | | mode is enabled, in | -| | | which case the boundary | -| | | arrays are generated | -| | | based on the type of | -| | | grid. If disabled, the | -| | | return value is | -| | | (None,None).For | -| | | rectilinear grids: The | -| | | grid classification mode | -| | | specifies how the grid | -| | | type is to be | -| | | determined. By default, | -| | | the grid type (Gaussian, | -| | | uniform, etc.) is | -| | | determined by calling | -| | | grid.classifyInFamily. | -| | | If the mode is 'off' | -| | | grid.getType is used | -| | | instead. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLatitude()`` | Get the latitude axis of | -| | | this grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLongitude()`` | Get the latitude axis of | -| | | this grid. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getMask()`` | Get the mask array of | -| | | this grid, if | -| | | any.Returns a 2-D | -| | | Numpy array, having | -| | | the same shape as the | -| | | grid. If the mask is not | -| | | explicitly defined, the | -| | | return value is | -| | | ``None``. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getMesh(self, transpos | Generate a mesh array | -| | e=None)`` | for the meshfill | -| | | graphics method.If | -| | | transpose is defined to | -| | | a tuple, say (1,0), | -| | | first transpose | -| | | latbounds and lonbounds | -| | | according to the tuple, | -| | | in this case (1,0,2). | -+--------------------------+--------------------------+--------------------------+ -| None | ``setBounds(latBounds, l | Set the grid | -| | onBounds, persistent=0)` | boundaries.\ ``latBounds | -| | ` | `` | -| | | is a NumPy array of | -| | | shape (n,2), such that | -| | | the boundaries of the | -| | | kth axis value are | -| | | ``[latBounds[k,0],latBou | -| | | nds[k,1] ]``. | -| | | ``lonBounds`` is defined | -| | | similarly for the | -| | | longitude array. | -| | | **Note:** By default, | -| | | the boundaries are not | -| | | written to the file or | -| | | dataset containing the | -| | | grid (if any). This | -| | | allows bounds to be set | -| | | on read-only files, for | -| | | regridding. If the | -| | | optional argument | -| | | ``persistent`` is set to | -| | | 1, the boundary array is | -| | | written to the file. | -+--------------------------+--------------------------+--------------------------+ -| None | ``setMask(mask, persiste | Set the grid mask. If | -| | nt=0)`` | ``persistent == 1``, the | -| | | mask values are written | -| | | to the associated file, | -| | | if any. Otherwise, the | -| | | mask is associated with | -| | | the grid, but no I/O is | -| | | generated. ``mask`` is a | -| | | two-dimensional, | -| | | Boolean-valued Numpy | -| | | array, having the same | -| | | shape as the grid. | -+--------------------------+--------------------------+--------------------------+ -| Horizontal-Grid | ``subGridRegion(latInter | Create a new grid | -| | val, lonInterval)`` | corresponding to the | -| | | coordinate region | -| | | defined by | -| | | ``latInterval, lonInterv | -| | | al.`` | -| | | | -| | | ``latInterval`` and | -| | | ``lonInterval`` are the | -| | | coordinate intervals for | -| | | latitude and longitude, | -| | | respectively. | -| | | | -| | | Each interval is a tuple | -| | | having one of the forms: | -| | | | -| | | - ``(x,y)`` | -| | | - ``(x,y,indicator)`` | -| | | - ``(x,y,indicator,cycl | -| | | e)`` | -| | | - ``None`` | -| | | | -| | | where ``x`` and ``y`` | -| | | are coordinates | -| | | indicating the interval | -| | | ``[x,y)``, and: | -| | | | -| | | ``indicator`` is a | -| | | two-character string, | -| | | where the first | -| | | character is 'c' if the | -| | | interval is closed on | -| | | the left, 'o' if open, | -| | | and the second character | -| | | has the same meaning for | -| | | the right-hand point. | -| | | (Default: 'co'). | -| | | | -| | | If ``cycle`` is | -| | | specified, the axis is | -| | | treated as circular with | -| | | the given cycle value. | -| | | By default, if | -| | | ``grid.isCircular()`` is | -| | | true, the axis is | -| | | treated as circular with | -| | | a default value of | -| | | 360.0. | -| | | | -| | | An interval of ``None`` | -| | | returns the full index | -| | | interval of the axis. | -| | | | -| | | If a mask is defined, | -| | | the subgrid also has a | -| | | mask corresponding to | -| | | the index ranges.Note: | -| | | The result grid is not | -| | | associated with any file | -| | | or dataset. | -+--------------------------+--------------------------+--------------------------+ -| Transient-CurveGrid | ``toCurveGrid(gridid=Non | Convert to a curvilinear | -| | e)`` | grid. If the grid is | -| | | already curvilinear, a | -| | | copy of the grid object | -| | | is returned. ``gridid`` | -| | | is the string identifier | -| | | of the resulting | -| | | curvilinear grid object. | -| | | If unspecified, the grid | -| | | ID is copied. **Note:** | -| | | This method does not | -| | | apply to generic grids. | -+--------------------------+--------------------------+--------------------------+ -| Transient-GenericGrid | ``toGenericGrid(gridid=N | Convert to a generic | -| | one)`` | grid. If the grid is | -| | | already generic, a copy | -| | | of the grid is returned. | -| | | ``gridid`` is the string | -| | | identifier of the | -| | | resulting curvilinear | -| | | grid object. If | -| | | unspecified, the grid ID | -| | | is copied. | -+--------------------------+--------------------------+--------------------------+ - - -Table 2.32 RectGrid Methods, additional to HorizontalGrid - Methods - -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Description | -+==========================+==========================+==========================+ -| String | ``getOrder()`` | Get the grid ordering, | -| | | either "yx" if latitude | -| | | is the first axis, or | -| | | "xy" if longitude is the | -| | | first axis. | -+--------------------------+--------------------------+--------------------------+ -| String | ``getType()`` | Get the grid type, | -| | | either "gaussian", | -| | | "uniform", "equalarea", | -| | | or "generic". | -+--------------------------+--------------------------+--------------------------+ -| (Array,Array) | ``getWeights()`` | Get the normalized area | -| | | weight arrays, as a | -| | | tuple | -| | | ``(latWeights, lon | -| | | Weights)``. | -| | | It is assumed that the | -| | | latitude and longitude | -| | | axes are defined in | -| | | degrees. | -| | | | -| | | The latitude weights are | -| | | defined as: | -| | | | -| | | ``latWeights[i] = 0.5 * | -| | | abs(sin(latBounds[i+1]) | -| | | - sin(latBounds[i] | -| | | ))`` | -| | | | -| | | The longitude weights | -| | | are defined as: | -| | | | -| | | ``lonWeights[i] = abs(lo | -| | | nBounds[i+1] - lonBounds | -| | | [i])/360.0`` | -| | | | -| | | For a global grid, the | -| | | weight arrays are | -| | | normalized such that the | -| | | sum of the weights is | -| | | 1.0 | -| | | | -| | | **Example:** | -| | | | -| | | Generate the 2-D weights | -| | | array, such that | -| | | ``weights[i.j]`` is the | -| | | fractional area of grid | -| | | zone ``[i,j]``. | -| | | | -| | | :: | -| | | | -| | | from cdms import MV | -| | | latwts, lonwts = gri | -| | | d.getWeights() | -| | | weights = MV.outerpr | -| | | oduct(latwts, lonwts) | -| | | | -| | | Also see the function | -| | | ``area_weights`` in | -| | | module | -| | | ``pcmdi.weighting``. | -+--------------------------+--------------------------+--------------------------+ -| None | ``setType(gridtype)`` | Set the grid type. | -| | | ``gridtype`` is one of | -| | | "gaussian", "uniform", | -| | | "equalarea", or | -| | | "generic". | -+--------------------------+--------------------------+--------------------------+ -| RectGrid | ``subGrid((latStart,latS | Create a new grid, with | -| | top),(lonStart,lonStop)) | latitude index range | -| | `` | [latStart : latStop] and | -| | | longitude index range | -| | | [lonStart : lonStop]. | -| | | Either index range can | -| | | also be specified as | -| | | None, indicating that | -| | | the entire range of the | -| | | latitude or longitude is | -| | | used. | -| | | | -| | | **Example:** | -| | | | -| | | This creates newgrid | -| | | corresponding to all | -| | | latitudes and index | -| | | range [lonStart:lonStop] | -| | | of oldgrid. | -| | | | -| | | ``newgrid = oldgrid.subG | -| | | rid(None, (lonStart, lon | -| | | Stop))`` | -| | | | -| | | If a mask is defined, | -| | | the subgrid also has a | -| | | mask corresponding to | -| | | the index ranges. | -| | | | -| | | **Note:** The result | -| | | grid is not associated | -| | | with any file or | -| | | dataset. | -+--------------------------+--------------------------+--------------------------+ -| RectGrid | ``transpose()`` | Create a new grid, with | -| | | axis order reversed. The | -| | | grid mask is also | -| | | transposed. | -| | | | -| | | **Note:** The result | -| | | grid is not associated | -| | | with any file or | -| | | dataset. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: HorizontalGrid Methods + :header: "Type", "Method", "Description" + :widths: 30, 30, 80 + + "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." + "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." + "Tuple", "``getBounds()``", "Get the grid boundary arrays." + ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" + ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." + ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." + ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." + ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids` `)." + ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + "Axis", "``getLatitude()``", "Get the latitude axis of this grid." + "Axis", "``getLongitude()``", " Get the latitude axis of this grid." + "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." + "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." + "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." + ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." + "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.``" + ,,"``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively." + ,,"Each interval is a tuple having one of the forms:" + ,,"* ``(x,y)``" + ,,"* ``(x,y,indicator)``" + ,,"* ``(x,y,indicator,cycle)``" + ,,"* ``None``" + ,,"where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" + ,,"``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." + ,,"If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0." + ,,"An interval of ``None`` returns the full index interval of the axis." + ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + + +Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods + +.. csv-table:: RectGrid Methods, additional to HorizontalGrid Methods + :header: "Type", "Method", "Description" + :widths: 30, 30, 80 + + "String", "``getOrder()``", Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if longitude is the first axis. String ``getType()`` Get the grid type, either "gaussian", "uniform", "equalarea", or "generic". (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." + ,,"The latitude weights are defined as:" + ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" + ,," The longitude weights are defined as: + ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" + ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" + ,,"**Example:**" + ,,"Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``." + ,,"* from cdms import MV" + ,,"* latwts, lonwts = gri d.getWeights()" + ,,"* weights = MV.outerproduct(latwts, lonwts)" + ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." + ,,"" + "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of "gaussian", "uniform", "equalarea", or "generic"." + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." + ,,"**Example:**" + ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." + ,,"``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))``" + ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges." + ,,"**Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed." + ,,"**Note:** The result grid is not associated with any file or dataset." Variable @@ -1719,644 +1234,125 @@ variable. Table 2.33 Variable Internal Attributes -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Type | Name | Definition | -+=======================+======================+=============================================================================================================================+ -| Dictionary | ``attributes`` | External attribute dictionary. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| String | ``id`` | Variable identifier. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| String | ``name\_in\_file`` | The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Dataset or CdmsFile | ``parent`` | The dataset or file which contains the variable. | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ -| Tuple | ``shape`` | The length of each axis of the variable | -+-----------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Variable Internal Attributes + :header: "Type", "Name", "Definition" + :widths: 30, 30, 80 + + "Dictionary", "``attributes``", "External attribute dictionary." + "String", "``id``", "Variable identifier." + "String", "``name_in_file``", "The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased." + "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the variable." + "Tuple", "``shape``", "The length of each axis of the variable" Table 2.34 Variable Constructors -+--------------------------------------+--------------------------------------+ -| Constructor | Description | -+======================================+======================================+ -| ``Dataset.createVariable(String id, | Create a Variable in a Dataset. This | -| String datatype, List axes)`` | function is not yet implemented. | -+--------------------------------------+--------------------------------------+ -| ``CdmsFile.createVariable(String id, | Create a Variable in a CdmsFile. | -| String datatype, List axesOr- | ``id`` is the name of the variable. | -| Grids)`` | ``datatype`` is the MV2 or Numpy | -| | typecode, for example, MV2.Float. | -| | ``axesOrGrids`` is a list of Axis | -| | and/or Grid objects, on which the | -| | variable is defined. Specifying a | -| | rectilinear grid is equivalent to | -| | listing the grid latitude and | -| | longitude axes, in the order defined | -| | for the grid. \*\*Note:\*\* this | -| | argument can either be a list or a | -| | tuple. If the tuple form is used, | -| | and there is only one element, it | -| | must have a following comma, e.g.: | -| | ``(axisobj,)``. | -+--------------------------------------+--------------------------------------+ -| :: | Create a transient variable, not | -| | associated with a file or dataset. | -| cdms.createVariable(array, typec | ``array`` is the data values: a | -| ode=None, copy=0, savespace=0,mask=N | Variable, masked array, or Numpy | -| one, fill_value=None, grid=None, axe | array. ``typecode`` is the MV2 | -| s=None,attributes=None, id=None) | typecode of the array. Defaults to | -| | the typecode of array. ``copy`` is | -| | an integer flag: if 1, the variable | -| | is created with a copy of the array, | -| | if 0 the variable data is shared | -| | with array. ``savespace`` is an | -| | integer flag: if set to 1, internal | -| | Numpy operations will attempt to | -| | avoid silent upcasting. ``mask`` is | -| | an array of integers with value 0 or | -| | 1, having the same shape as array. | -| | array elements with a corresponding | -| | mask value of 1 are considered | -| | invalid, and are not used for | -| | subsequent Numpy operations. The | -| | default mask is obtained from array | -| | if present, otherwise is None. | -| | ``fill_value`` is the missing value | -| | flag. The default is obtained from | -| | array if possible, otherwise is set | -| | to 1.0e20 for floating point | -| | variables, 0 for integer-valued | -| | variables. ``grid`` is a rectilinear | -| | grid object. ``axes`` is a tuple of | -| | axis objects. By default the axes | -| | are obtained from array if present. | -| | Otherwise for a dimension of length | -| | n, the default axis has values [0., | -| | 1., ..., double(n)]. ``attributes`` | -| | is a dictionary of attribute values. | -| | The dictionary keys must be strings. | -| | By default the dictionary is | -| | obtained from array if present, | -| | otherwise is empty. ``id`` is the | -| | string identifier of the variable. | -| | By default the id is obtained from | -| | array if possible, otherwise is set | -| | to 'variable\_n' for some integer n. | -+--------------------------------------+--------------------------------------+ +.. csv-table:: Variable Constructgors + :header: "Constructor", "Description" + :widths: 30, 80 + + "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." + "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)", "Create a Variable in a CdmsFile." + ,,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None) ``", " Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer n." Table 2.35 Variable Methods -+--------------------------+--------------------------+--------------------------+ -| Type | Method | Definition | -+==========================+==========================+==========================+ -| Variable | ``tvar = var[ i:j, m:n]` | Read a slice of data | -| | ` | from the file or | -| | | dataset, resulting in a | -| | | transient variable. | -| | | Singleton dimensions are | -| | | 'squeezed' out. Data is | -| | | returned in the physical | -| | | ordering defined in the | -| | | dataset. The forms of | -| | | the slice operator are | -| | | listed in Table 2.36 on | -| | | page 102. | -+--------------------------+--------------------------+--------------------------+ -| None | ``var[ i:j, m:n] = array | Write a slice of data to | -| | `` | the external dataset. | -| | | The forms of the slice | -| | | operator are listed in | -| | | Table 2.21 on page 32. | -| | | (Variables in CdmsFiles | -| | | only) | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``tvar = var(selector)`` | Calling a variable as a | -| | | function reads the | -| | | region of data defined | -| | | by the selector. The | -| | | result is a transient | -| | | variable, unless raw=1 | -| | | keyword is specified. | -| | | See "Selectors" on page | -| | | 103. | -+--------------------------+--------------------------+--------------------------+ -| None | ``assignValue(Array ar)` | Write the entire data | -| | ` | array. Equivalent to | -| | | ``var[:] = ar``. | -| | | (Variables in CdmsFiles | -| | | only). | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``astype(typecode)`` | Cast the variable to a | -| | | new datatype. Typecodes | -| | | are as for MV, MV2, and | -| | | Numpy modules. | -+--------------------------+--------------------------+--------------------------+ -| Variable | ``clone(copyData=1)`` | Return a copy of a | -| | | transient variable. | -| | | | -| | | If copyData is 1 (the | -| | | default) the variable | -| | | data is copied as well. | -| | | If copyData is 0, the | -| | | result transient | -| | | variable shares the | -| | | original transient | -| | | variables data array. | -+--------------------------+--------------------------+--------------------------+ -| Transient Variable | :: | Return a lat/level | -| | | vertical cross-section | -| | crossSectionRegrid(n | regridded to a new set | -| | ewLevel, newLatitude, me | of latitudes newLatitude | -| | thod="log", missing=None | and levels newLevel. The | -| | , order=None) | variable should be a | -| | | function of latitude, | -| | | level, and (optionally) | -| | | time. | -| | | | -| | | ``newLevel`` is an axis | -| | | of the result pressure | -| | | levels. | -| | | | -| | | ``newLatitude`` is an | -| | | axis of the result | -| | | latitudes. | -| | | | -| | | ``method`` is optional, | -| | | either "log" to | -| | | interpolate in the log | -| | | of pressure (default), | -| | | or "linear" for linear | -| | | interpolation. | -| | | | -| | | ``missing`` is a missing | -| | | data value. The default | -| | | is ``var.getMissing()`` | -| | | | -| | | ``order`` is an order | -| | | string such as "tzy" or | -| | | "zy". The default is | -| | | ``var.getOrder()``. | -| | | | -| | | *See also:* ``regrid``, | -| | | ``pressureRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getAxis(n)`` | Get the n-th axis. | -| | | | -| | | ``n`` is an integer. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisIds()`` | Get a list of axis | -| | | identifiers. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``getAxisIndex(axis_spec | Return the index of the | -| | )`` | axis specificed by | -| | | axis\_spec. Return -1 if | -| | | no match. | -| | | | -| | | ``axis_spec`` is a | -| | | specification as defined | -| | | for getAxisList | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisList(axes=None, | Get an ordered list of | -| | omit=None, order=None)` | axis objects in the | -| | ` | domain of the variable. | -| | | | -| | | If ``axes`` is not | -| | | ``None``, include only | -| | | certain axes. Otherwise | -| | | axes is a list of | -| | | specifications as | -| | | described below. Axes | -| | | are returned in the | -| | | order specified unless | -| | | the order keyword is | -| | | given. | -| | | | -| | | If ``omit`` is not | -| | | ``None``, omit those | -| | | specified by an integer | -| | | dimension number. | -| | | Otherwise omit is a list | -| | | of specifications as | -| | | described below. | -| | | | -| | | ``order`` is an optional | -| | | string determining the | -| | | output order. | -| | | | -| | | Specifications for the | -| | | axes or omit keywords | -| | | are a list, each element | -| | | having one of the | -| | | following forms: | -| | | | -| | | - an integer dimension | -| | | index, starting at 0. | -| | | - a string representing | -| | | an axis id or one of | -| | | the strings 'time', | -| | | 'latitude', 'lat', | -| | | 'longitude', 'lon', | -| | | 'lev' or 'level'. | -| | | - a function that takes | -| | | an axis as an | -| | | argument and returns | -| | | a value. If the value | -| | | returned is true, the | -| | | axis matches. | -| | | - an axis object; will | -| | | match if it is the | -| | | same object as axis. | -| | | | -| | | ``order`` can be a | -| | | string containing the | -| | | characters t,x,y,z, or | -| | | -. If a dash ('-') is | -| | | given, any elements of | -| | | the result not chosen | -| | | otherwise are filled in | -| | | from left to right with | -| | | remaining candidates. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getAxisListIndex(axes= | Return a list of indices | -| | None, omit=None, order=N | of axis objects. | -| | one)`` | Arguments are as for | -| | | getAxisList. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getDomain()`` | Get the domain. Each | -| | | element of the list is | -| | | itself a tuple of the | -| | | form | -| | | ``(axis,start,length,tru | -| | | e_length)`` | -| | | where axis is an axis | -| | | object, start is the | -| | | start index of the | -| | | domain relative to the | -| | | axis object, length is | -| | | the length of the axis, | -| | | and true\_length is the | -| | | actual number of | -| | | (defined) points in the | -| | | domain. *See also:* | -| | | ``getAxisList``. | -+--------------------------+--------------------------+--------------------------+ -| Horizontal-Grid | ``getGrid()`` | Return the associated | -| | | grid, or ``None`` if the | -| | | variable is not gridded. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLatitude()`` | Get the latitude axis, | -| | | or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLevel()`` | Get the vertical level | -| | | axis, or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getLongitude()`` | Get the longitude axis, | -| | | or ``None`` if not | -| | | found. | -+--------------------------+--------------------------+--------------------------+ -| Various | ``getMissing()`` | Get the missing data | -| | | value, or ``None`` if | -| | | not found. | -+--------------------------+--------------------------+--------------------------+ -| String | ``getOrder()`` | Get the order string of | -| | | a spatio-temporal | -| | | variable. The order | -| | | string specifies the | -| | | physical ordering of the | -| | | data. It is a string of | -| | | characters with length | -| | | equal to the rank of the | -| | | variable, indicating the | -| | | order of the variable's | -| | | time, level, latitude, | -| | | and/or longitude axes. | -| | | Each character is one | -| | | of: | -| | | | -| | | - 't': time | -| | | - 'z': vertical level | -| | | - 'y': latitude | -| | | - 'x': longitude | -| | | - '-': the axis is not | -| | | spatio-temporal. | -| | | | -| | | **Example:** | -| | | | -| | | A variable with ordering | -| | | "tzyx" is 4-dimensional, | -| | | where the ordering of | -| | | axes is (time, level, | -| | | latitude, longitude). | -| | | | -| | | **Note:** The order | -| | | string is of the form | -| | | required for the order | -| | | argument of a regridder | -| | | function. | -+--------------------------+--------------------------+--------------------------+ -| List | ``getPaths(*intervals)`` | Get the file paths | -| | | associated with the | -| | | index region specified | -| | | by intervals. | -| | | | -| | | ``intervals`` is a list | -| | | of scalars, 2-tuples | -| | | representing [i,j), | -| | | slices, and/or Ellipses. | -| | | If no ``argument(s)`` | -| | | are present, all file | -| | | paths associated with | -| | | the variable are | -| | | returned. | -| | | | -| | | Returns a list of tuples | -| | | of the form | -| | | (path,slicetuple), where | -| | | path is the path of a | -| | | file, and slicetuple is | -| | | itself a tuple of | -| | | slices, of the same | -| | | length as the rank of | -| | | the variable, | -| | | representing the portion | -| | | of the variable in the | -| | | file corresponding to | -| | | intervals. | -| | | | -| | | **Note:** This function | -| | | is not defined for | -| | | transient variables. | -+--------------------------+--------------------------+--------------------------+ -| Axis | ``getTime()`` | Get the time axis, or | -| | | ``None`` if not found. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``len(var)`` | The length of the first | -| | | dimension of the | -| | | variable. If the | -| | | variable is | -| | | zero-dimensional | -| | | (scalar), a length of 0 | -| | | is returned. | -| | | | -| | | **Note:** ``size()`` | -| | | returns the total number | -| | | of elements. | -+--------------------------+--------------------------+--------------------------+ -| Transient Variable | ``pressureRegrid (newLev | Return the variable | -| | el, method="log", missin | regridded to a new set | -| | g=None, order=None | of pressure levels | -| | )`` | newLevel. The variable | -| | | must be a function of | -| | | latitude, longitude, | -| | | pressure level, and | -| | | (optionally) time. | -| | | | -| | | ``newLevel`` is an axis | -| | | of the result pressure | -| | | levels. | -| | | | -| | | ``method`` is optional, | -| | | either "log" to | -| | | interpolate in the log | -| | | of pressure (default), | -| | | or "linear" for linear | -| | | interpolation. | -| | | | -| | | ``missing`` is a missing | -| | | data value. The default | -| | | is ``var.getMissing()`` | -| | | | -| | | ``order`` is an order | -| | | string such as "tzyx" or | -| | | "zyx". The default is | -| | | ``var.getOrder()`` | -| | | | -| | | See also: ``regrid``, | -| | | ``crossSectionRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``rank()`` | The number of dimensions | -| | | of the variable. | -+--------------------------+--------------------------+--------------------------+ -| Transient | :: | Return the variable | -| | | regridded to the | -| | regrid (togrid, miss | horizontal grid togrid. | -| | ing=None, order=None, Va | | -| | riable mask=None) | ``missing`` is a Float | -| | | specifying the missing | -| | | data value. The default | -| | | is 1.0e20. | -| | | | -| | | ``order`` is a string | -| | | indicating the order of | -| | | dimensions of the array. | -| | | It has the form returned | -| | | from | -| | | ``variable.getOrder()``. | -| | | For example, the string | -| | | "tzyx" indicates that | -| | | the dimension order of | -| | | array is (time, level, | -| | | latitude, longitude). If | -| | | unspecified, the | -| | | function assumes that | -| | | the last two dimensions | -| | | of array match the input | -| | | grid. | -| | | | -| | | ``mask`` is a Numpy | -| | | array, of datatype | -| | | Integer or Float, | -| | | consisting of ones and | -| | | zeros. A value of 0 or | -| | | 0.0 indicates that the | -| | | corresponding data value | -| | | is to be ignored for | -| | | purposes of regridding. | -| | | If mask is | -| | | two-dimensional of the | -| | | same shape as the input | -| | | grid, it overrides the | -| | | mask of the input grid. | -| | | If the mask has more | -| | | than two dimensions, it | -| | | must have the same shape | -| | | as array. In this case, | -| | | the missing data value | -| | | is also ignored. Such an | -| | | n-dimensional mask is | -| | | useful if the pattern of | -| | | missing data varies with | -| | | level (e.g., ocean data) | -| | | or time. Note: If | -| | | neither missing or mask | -| | | is set, the default mask | -| | | is obtained from the | -| | | mask of the array if | -| | | any. | -| | | | -| | | See also: | -| | | ``crossSectionRegrid``, | -| | | ``pressureRegrid``. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setAxis(n, axis)`` | Set the n-th axis | -| | | (0-origin index) of to a | -| | | copy of axis. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setAxisList(axislist)` | Set all axes of the | -| | ` | variable. axislist is a | -| | | list of axis objects. | -+--------------------------+--------------------------+--------------------------+ -| ``None`` | ``setMissing(value)`` | Set the missing value. | -+--------------------------+--------------------------+--------------------------+ -| Integer | ``size()`` | Number of elements of | -| | | the variable. | -+--------------------------+--------------------------+--------------------------+ -| Variable | :: | Read a coordinate region | -| | | of data, returning a | -| | subRegion(*region, t | transient variable. A | -| | ime=None, level=None, la | region is a | -| | titude=None, longitude=N | hyperrectangle in | -| | one, squeeze=0, raw=0) | coordinate space. | -| | | | -| | | ``region`` is an | -| | | argument list, each item | -| | | of which specifies an | -| | | interval of a coordinate | -| | | axis. The intervals are | -| | | listed in the order of | -| | | the variable axes. If | -| | | trailing dimensions are | -| | | omitted, all values of | -| | | those dimensions are | -| | | retrieved. If an axis is | -| | | circular | -| | | (axis.isCircular() is | -| | | true) or cycle is | -| | | specified (see below), | -| | | then data will be read | -| | | with wraparound in that | -| | | dimension. Only one axis | -| | | may be read with | -| | | wraparound. A coordinate | -| | | interval has one of the | -| | | forms listed in Table | -| | | 2.37 on page 102. Also | -| | | see | -| | | ``axis.mapIntervalExt``. | -| | | | -| | | The optional keyword | -| | | arguments ``time``, | -| | | ``level``, ``latitude``, | -| | | and ``longitude`` may | -| | | also be used to specify | -| | | the dimension for which | -| | | the interval applies. | -| | | This is particularly | -| | | useful if the order of | -| | | dimensions is not known | -| | | in advance. An exception | -| | | is raised if a keyword | -| | | argument conflicts with | -| | | a positional region | -| | | argument. | -| | | | -| | | The optional keyword | -| | | argument ``squeeze`` | -| | | determines whether or | -| | | not the shape of the | -| | | returned array contains | -| | | dimensions whose length | -| | | is 1; by default this | -| | | argument is 0, and such | -| | | dimensions are not | -| | | 'squeezed out'. | -| | | | -| | | The optional keyword | -| | | argument ``raw`` | -| | | specifies whether the | -| | | return object is a | -| | | variable or a masked | -| | | array. By default, a | -| | | transient variable is | -| | | returned, having the | -| | | axes and attributes | -| | | corresponding to2,3 the | -| | | region read. If raw=1, | -| | | an MV2 masked array is | -| | | returned, equivalent to | -| | | the transient variable | -| | | without the axis and | -| | | attribute information. | -+--------------------------+--------------------------+--------------------------+ -| Variable | :: | Read a slice of data, | -| | | returning a transient | -| | subSlice(*specs, tim | variable. This is a | -| | e=None, level=None, lati | functional form of the | -| | tude=None, longitude=Non | slice operator [] with | -| | e, squeeze=0, raw=0) | the squeeze option | -| | | turned off. | -| | | | -| | | ``specs`` is an argument | -| | | list, each element of | -| | | which specifies a slice | -| | | of the corresponding | -| | | dimension. There can be | -| | | zero or more positional | -| | | arguments, each of the | -| | | form: | -| | | | -| | | - a single integer n, | -| | | meaning | -| | | ``slice(n, n+1)`` | -| | | - an instance of the | -| | | slice class | -| | | - a tuple, which will | -| | | be used as arguments | -| | | to create a slice | -| | | - ':', which means a | -| | | slice covering that | -| | | entire dimension | -| | | - Ellipsis (...), which | -| | | means to fill the | -| | | slice list with ':' | -| | | leaving only enough | -| | | room at the end for | -| | | the remaining | -| | | positional arguments | -| | | - a Python slice | -| | | object, of the form | -| | | ``slice(i,j,k)`` | -| | | | -| | | If there are fewer | -| | | slices than | -| | | corresponding | -| | | dimensions, all values | -| | | of the trailing | -| | | dimensions are read. | -| | | | -| | | The keyword arguments | -| | | are defined as in | -| | | subRegion. | -| | | | -| | | There must be no | -| | | conflict between the | -| | | positional arguments and | -| | | the keywords. | -| | | | -| | | In ``(a)-(c)`` and (f), | -| | | negative numbers are | -| | | treated as offsets from | -| | | the end of that | -| | | dimension, as in normal | -| | | Python indexing. | -+--------------------------+--------------------------+--------------------------+ -| String | ``typecode()`` | The Numpy datatype | -| | | identifier. | -+--------------------------+--------------------------+--------------------------+ +.. csv-table:: Variable Methods + :header: "Type", "Method", "Definition" + :widths: 30, 30, 80 + + "Variable", "``tvar = var[ i:j, m:n]``","Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" + "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)" + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See "Selectors"." + "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." + "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." + "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." + ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." + ,,"Transient Variable :: Return a lat/level vertical cross-section" + ,,"crossSectionRegrid(n regridded to a new set ewLevel, newLatitude, me of latitudes newLatitude thod="log", missing=None and levels newLevel. The , order=None) variable should be a function of latitude, level, and (optionally) time." + ,,"``newLevel`` is an axis of the result pressure levels." + ,,"``newLatitude`` is an axis of the result latitudes." + ,,"``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." + ,,"``missing`` is a missing data value. The default is ``var.getMissing()``" + ,,"``order`` is an order string such as "tzy" or "zy". The default is ``var.getOrder()``." + ,,"*See also:* ``regrid``, ``pressureRegrid``." + ,,"" + "Axis", "``getAxis(n)``", "Get the n-th axis." + ,,"``n`` is an integer." + "List", "``getAxisIds()``", "Get a list of axis identifiers." + "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." + ,,"``axis_spec`` is a specification as defined for getAxisList" + "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable." + ,,"If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." + ,,"If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." + ,,"``order`` is an optional string determining the output order." + ,,"Specifications for the axes or omit keywords are a list, each element having one of the following forms:" + ,,"* an integer dimension index, starting at 0." + ,,"* a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'." + ,,"* a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches." + ,,"* an axis object; will match if it is the same object as axis." + ,,"``order`` can be a string containing the characters t,x,y,z, or * ." + ,,"If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." + "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." + "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." + "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." + "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." + "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." + "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." + "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found." + ,, "String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" + ,, "* 't': time" + ,, "* 'z': vertical level" + ,, "* 'y': latitude" + ,, "* 'x': longitude" + ,, "* '-': the axis is not spatio-temporal." + ,, "" + ,, "**Example:**" + ,, "A variable with ordering "tzyx" is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." + ,, "**Note:** The order string is of the form required for the order argument of a regridder function." + "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." + ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." + ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." + ,, " **Note:** This function is not defined for transient variables." + "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." + "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." + ,,"**Note:** ``size()`` returns the total number of elements." + "Transient Variable", "``pressureRegrid (newLevel, method="log", missin=None, order=None)``", Return the variable el, method="log", missin regridded to a new set g=None, order=None of pressure levels)`` newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." + ,, "``newLevel`` is an axis of the result pressure levels." + ,, "``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." + ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" + ,, "``order`` is an order string such as "tzyx" or "zyx". The default is ``var.getOrder()``" + ,, "See also: ``regrid``, ``crossSectionRegrid``." + ,, "Integer ``rank()`` The number of dimensions of the variable." + ,, "Transient :: Return the variable regridded to the regrid (togrid, miss horizontal grid togrid. ing=None, order=None, Va riable mask=None) ``missing`` is a Float specifying the missing data value. The default is 1.0e20." + ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string "tzyx" indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." + ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." + ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." + "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." + "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." + "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." + "Variable", "subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)", Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." + ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37 on page 102. Also see ``axis.mapIntervalExt``." + ,," The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." + ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." + ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." + "Variable", "``subSlice(*specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." + ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" + ,,"* a single integer n, meaning ``slice(n, n+1)``" + ,,"* an instance of the slice class" + ,,"* a tuple, which will be used as arguments to create a slice" + ,,"* ':', which means a slice covering that entire dimension" + ,,"* Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments" + ,,"* a Python slice object, of the form ``slice(i,j,k)``" + ,,"If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read." + ,,"The keyword arguments are defined as in subRegion." + ,,"There must be no conflict between the positional arguments and the keywords." + ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." + ,,"String ``typecode()`` The Numpy datatype identifier." Example Get a region of data. ***************************** @@ -2365,72 +1361,40 @@ Variable ta is a function of (time, latitude, longitude). Read data corresponding to all times, latitudes -45.0 up to but not including+45.0, longitudes 0.0 through and including longitude 180.0: -.. raw:: html - -
- :: data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) -.. raw:: html - -
- or equivalently: -.. raw:: html - -
- :: data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, 180.0) -.. raw:: html - -
- Read all data for March, 1980: -.. raw:: html - -
- :: data = ta.subRegion(time=('1980-3','1980-4','co')) -.. raw:: html - -
- Table 2.36 Variable Slice Operators -+-------------------+---------------------------------------------------------------+ -| Operator | Description | -+===================+===============================================================+ -| ``[i]`` | The ith element, zero-origin indexing. | -+-------------------+---------------------------------------------------------------+ -| ``[i:j]`` | The ith element through, but not including, element j | -+-------------------+---------------------------------------------------------------+ -| ``[i:]`` | The ith element through the end | -+-------------------+---------------------------------------------------------------+ -| ``[:j]`` | The beginning element through, but not including, element j | -+-------------------+---------------------------------------------------------------+ -| ``[:]`` | The entire array | -+-------------------+---------------------------------------------------------------+ -| ``[i:j:k]`` | Every kth element | -+-------------------+---------------------------------------------------------------+ -| ``[i:j, m:n]`` | Multidimensional slice | -+-------------------+---------------------------------------------------------------+ -| ``[i, ..., m]`` | (Ellipsis) All dimensions between those specified. | -+-------------------+---------------------------------------------------------------+ -| ``[-1]`` | Negative indices ‘wrap around’. -1 is the last element | -+-------------------+---------------------------------------------------------------+ +.. csv-table:: Variable Slice Operators + :header: "Operator", "Description" + :widths: 30, 80 + + "``[i]``", "The ith element, zero-origin indexing." + "``[i:j]``", "The ith element through, but not including, element j" + "``[i:]``", "The ith element through the end" + "``[:j]``", "The beginning element through, but not including, element j" + "``[:]``", "The entire array" + "``[i:j:k]``", "Every kth element" + "``[i:j, m:n]``", "Multidimensional slice" + "``[i, ..., m]``", "(Ellipsis) All dimensions between those specified." + "``[-1]``", "Negative indices ‘wrap around’. -1 is the last element" From d4269cf311d9909c307291a60b563db17ab5ad2a Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 29 Jan 2018 09:44:32 -0800 Subject: [PATCH 042/239] update cdms2 tables --- docs/source/manual/cdms_2.rst | 180 ++++------------------------------ 1 file changed, 20 insertions(+), 160 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 80329b1f..49e833a8 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1398,29 +1398,22 @@ Table 2.36 Variable Slice Operators -Table 2.37 Index and Coordinate Intervals - -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| Interval Definition | Example Interval Definition | Example | -+========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ -| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | -| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | -| | | ``'1980-1-3'`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | -| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | -| | | ``slice(,,-1)`` reverses the direction of the axis. | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``':'`` | all axis values of one dimension |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``Ellipsis`` | all values of all intermediate axes |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +.. csv-table:: Index and Coordinate Intervals + :header: "Interval Definition", "Example Interval Definition", "Example" + :widths: 30, 30, 80 + + + "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "`180.0`" + ,,"`cdtime.reltime(48,'hour s since 1980-1')`" + ,,"``'1980-1-3'``" + "`(x,y)`", "indices i such that x ≤ axis[i] ≤ y", "`(-180,180)`" + "`(x,y,'co')`", "`x ≤ axis[i] < y`. The third item is defined as in mapInterval.", "`(-90,90,'cc')`" + "`(x,y,'co',cycle)`", "`x ≤ axis[i]< y`, with wraparound", "`( 180, 180, 'co', 360.0)`" + ,,"**Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which `axis.isCircular()` is true." + "`slice(i,j,k)`", "slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.", "`slice(1,10)`" + "`slice(,,-1)`", "reverses the direction of the axis.", + "`:`", "all axis values of one dimension", + "`Ellipsis`", "all values of all intermediate axes" @@ -1429,17 +1422,10 @@ Table 2.37 Index and Coordinate Intervals A selector is a specification of a region of data to be selected from a variable. For example, the statement -.. raw:: html - -
- :: x = v(time='1979-1-1', level=(1000.0,100.0)) -.. raw:: html - -
means ‘select the values of variable v for time ‘1979-1-1’ and levels 1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are @@ -1447,31 +1433,15 @@ generally used to represent regions of space and time. The form for using a selector is -.. raw:: html - -
- :: - result = v(s) -.. raw:: html - -
where v is a variable and s is the selector. An equivalent form is -.. raw:: html - -
- :: - result = f('varid', s) -.. raw:: html - -
where f is a file or dataset, and ‘varid’ is the string ID of a variable. @@ -1479,33 +1449,17 @@ variable. A selector consists of a list of selector components. For example, the selector -.. raw:: html - -
:: - time='1979-1-1', level=(1000.0,100.0) -.. raw:: html - -
- has two components: time=’1979-1-1’, and level=(1000.0,100.0). This illustrates that selector components can be defined with keywords, using the form: -.. raw:: html - -
- :: - keyword=value -.. raw:: html - -
Note that for the keywords time, level, latitude, and longitude, the selector can be used with any variable. If the corresponding axis is not @@ -1550,17 +1504,9 @@ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example: -.. raw:: html - -
- :: - x9 = hus(('1979-1-1','1979-2-1'),1000.0) -.. raw:: html - -
reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the @@ -1573,78 +1519,37 @@ be defined and reused, independent of a particular variable. Selectors are constructed using the cdms.selectors.Selector class. The constructor takes an argument list of selector components. For example: -.. raw:: html - -
- :: - from cdms.selectors import Selector sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) x1 = v1(sel) x2 = v2(sel) -.. raw:: html - -
- For convenience CDMS provides several predefined selectors, which can be used directly or can be combined into more complex selectors. The selectors time, level, latitude, longitude, and required are equivalent to their keyword counterparts. For example: -.. raw:: html - -
- :: - from cdms import time, level x = hus(time('1979-1-1','1979-2-1'), level(1000.)) -.. raw:: html - -
- and -.. raw:: html - -
- :: - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) -.. raw:: html - -
- are equivalent. Additionally, the predefined selectors -``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` -take arguments ``(startindex, stopindex[, stride])``: - -.. raw:: html - -
+`latitudeslice`, `longitudeslice`, `levelslice`, and `timeslice` +take arguments `(startindex, stopindex[, stride])`: :: - from cdms import timeslice, levelslice x = v(timeslice(0,2), levelslice(16,17)) -.. raw:: html - -
- Finally, a collection of selectors is defined in module cdutil.region: -.. raw:: html - -
- :: - from cdutil.region import * NH=NorthernHemisphere=domain(latitude=(0.,90.) SH=SouthernHemisphere=domain(latitude=(-90.,0.)) @@ -1652,17 +1557,9 @@ Finally, a collection of selectors is defined in module cdutil.region: NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) -.. raw:: html - -
- Selectors can be combined using the & operator, or by refining them in the call: -.. raw:: html - -
- :: from cdms.selectors import Selector @@ -1672,11 +1569,6 @@ the call: x1 = hus(sel3) x2 = hus(sel2, level=1000.0) -.. raw:: html - -
- - 2.11.2 Selector examples @@ -1688,10 +1580,6 @@ monthly starting at 1979-1-1. There are 17 levels, the last level being select the first two times and the last level. The last two examples remove the singleton level dimension from the result array. -.. raw:: html - -
- :: import cdms @@ -1739,10 +1627,6 @@ remove the singleton level dimension from the result array. f.close() -.. raw:: html - -
- Examples @@ -1763,11 +1647,7 @@ Data is extracted from both datasets for January of the first input year through December of the second input year. For each time and level, three quantities are calculated: slope, variance, and correlation. The results are written to a netCDF file. For brevity, the functions -``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. - -.. raw:: html - -
+`corrCoefSlope` and `removeSeasonalCycle` are omitted. :: @@ -1826,9 +1706,6 @@ results are written to a netCDF file. For brevity, the functions # Process Jan80 through Dec81 ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') -.. raw:: html - -
**Notes:** @@ -1858,10 +1735,6 @@ calculated, for all times in a dataset. The name of the dataset and variable are entered, then the variance is calculated and plotted via the vcs module. -.. raw:: html - -
- :: #!/usr/bin/env python @@ -1878,7 +1751,7 @@ the vcs module. def pause(): print Hit return to continue: , line = sys.stdin.readline() - +:: 1. # Calculate pointwise variance of variable over time # Returns the variance and the number of points # for which the data is defined, for each grid point @@ -1941,18 +1814,9 @@ the vcs module. pause() w.clear() -.. raw:: html - -
- The result of running this script is as follows: -.. raw:: html - -
- :: - % calcVar.py Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: @@ -1974,10 +1838,6 @@ The result of running this script is as follows: -.. raw:: html - -
- **Notes:** #. n = count(x, 0) returns the pointwise number of valid values, summing From 840253082b8d66a555be93d9338f9efa58daf017 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 29 Jan 2018 10:00:43 -0800 Subject: [PATCH 043/239] update sections --- docs/source/manual/cdms_2.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 49e833a8..671ab6b5 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1434,12 +1434,14 @@ generally used to represent regions of space and time. The form for using a selector is :: + result = v(s) where v is a variable and s is the selector. An equivalent form is :: + result = f('varid', s) @@ -1451,6 +1453,7 @@ selector :: + time='1979-1-1', level=(1000.0,100.0) has two components: time=’1979-1-1’, and level=(1000.0,100.0). This @@ -1458,6 +1461,7 @@ illustrates that selector components can be defined with keywords, using the form: :: + keyword=value @@ -1505,6 +1509,7 @@ component order corresponds to the axis order of a variable. For example: :: + x9 = hus(('1979-1-1','1979-2-1'),1000.0) @@ -1520,6 +1525,7 @@ are constructed using the cdms.selectors.Selector class. The constructor takes an argument list of selector components. For example: :: + from cdms.selectors import Selector sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) x1 = v1(sel) @@ -1531,12 +1537,14 @@ selectors time, level, latitude, longitude, and required are equivalent to their keyword counterparts. For example: :: + from cdms import time, level x = hus(time('1979-1-1','1979-2-1'), level(1000.)) and :: + x = hus(time=('1979-1-1','1979-2-1'), level=1000.) are equivalent. Additionally, the predefined selectors @@ -1544,12 +1552,14 @@ are equivalent. Additionally, the predefined selectors take arguments `(startindex, stopindex[, stride])`: :: + from cdms import timeslice, levelslice x = v(timeslice(0,2), levelslice(16,17)) Finally, a collection of selectors is defined in module cdutil.region: :: + from cdutil.region import * NH=NorthernHemisphere=domain(latitude=(0.,90.) SH=SouthernHemisphere=domain(latitude=(-90.,0.)) @@ -1752,6 +1762,7 @@ the vcs module. print Hit return to continue: , line = sys.stdin.readline() :: + 1. # Calculate pointwise variance of variable over time # Returns the variance and the number of points # for which the data is defined, for each grid point @@ -1817,6 +1828,7 @@ the vcs module. The result of running this script is as follows: :: + % calcVar.py Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: From 1ec5ef9d0d08ec02a357e2aa66b0e4bbcd46a196 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 29 Jan 2018 23:23:48 -0800 Subject: [PATCH 044/239] update table --- docs/source/manual/cdms_2.rst | 918 +++++++++++++++++----------------- 1 file changed, 459 insertions(+), 459 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 671ab6b5..bd93b9fc 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -50,13 +50,13 @@ return an instance of a CDMS class, or one of the Python types: "Array", "Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules." "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" - "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" + "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: `axes['time']`" "Float", "Floating-point value." "Integer", "Integer value." - "List", "An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']``" + "List", "An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., `[1, 2.0, 'x', 'y']`" "None", "No value returned." "Reltime", "Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime" - "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``" + "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., `(1, 2.0, 'x', 'y')`" A first example ^^^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ latitude, longitude). "8", "Calculate the average January value for each grid zone. Any missing data is handled automatically." "9,10", "Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file." "14", "Create a new netCDF output file named ‘janjuly.nc’ to hold the results." - "15", "Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." + "15", "Write the January average values to the output file. The variable will have id “tas\_jan” in the file. `write` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." "17", "Set the global attribute ‘comment’." "18", "Close the output file." @@ -128,82 +128,82 @@ Rather, they are called as module functions, e.g., :header: "Type", "Definition" :widths: 10, 80 - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." - "``Axis``", "``createAxis(data, bounds=None)``:" + "`Variable`", "`asVariable(s)`: Transform `s` into a transient variable. `s` is a masked array, Numpy array, or Variable. If `s` is already a transient variable, `s` is returned. See also: `isVariable`." + "`Axis`", "`createAxis(data, bounds=None)`:" , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." - , " * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." - , " * See ``setAutoBounds``." - , " * Also see: ``CdmsFile.createAxis``" - "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." - "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." - "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" - "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values." - , " * ``lonArray`` is a NumPy array of longitude values. " - , " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. " - , " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. " - , " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." - , " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." + , " * `data` is a one-dimensional, monotonic Numpy array. `bounds` is an array of shape `(len(data),2)`, such that for all `i`, `data[i]` is in the range `[bounds[i,0],bounds[i,1] ]`. If `bounds` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." + , " * See `setAutoBounds`." + , " * Also see: `CdmsFile.createAxis`" + "`Axis`", "`createEqualAreaAxis(nlat)`:" + , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values `x[i]`, `sin(x[i])sin(x[i+1])` is constant. `nlat` is the axis length. The axis is not associated with a file or dataset." + "`Axis`", "`createGaussianAxis(nlat)`:" + , "Create a Gaussian latitude axis. Axis values range from north to south. `nlat` is the axis length. The axis is not associated with a file or dataset." + "`RectGrid`", "`createGaussianGrid(nlats, xorigin=0.0, order='yx')`:" + , "Create a Gaussian grid, with shape `(nlats, 2*nlats)`. `nlats` is the number of latitudes. `xorigin` is the origin of the longitude axis. `order` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" + "`RectGrid`", "`createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)`:" + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. `latArray` is a NumPy array of latitude values." + , " * `lonArray` is a NumPy array of longitude values. " + , " * `latBounds` is a NumPy array having shape `(len(latArray),2)`, of latitude boundaries. " + , " * `lonBounds` is a NumPy array having shape `(len(lonArray),2)`, of longitude boundaries. " + , " * `order` is a `string` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." + , " * `mask` (optional) is an `integer`-valued NumPy mask array, having the same shape and ordering as the grid." - "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." + "`RectGrid`", "`createGlobalMeanGrid(grid)`:" + , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. `grid` is a RectGrid." - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" + "`RectGrid`", "`createRectGrid(lat, lon, order, type='generic', mask=None)`:" , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation." - , " * ``lat`` is a latitude axis, created by ``cdms.createAxis``." - , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." - , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + , " * `lat` is a latitude axis, created by `cdms.createAxis`." + , " * `lon` is a longitude axis, created by `cdms.createAxis`." + , " * `order` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." + , " * `type` is one of 'gaussian','uniform','equalarea',or 'generic'." + , " * If specified, `mask` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" + "`RectGrid`", "`createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)`:" , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``." - , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." - , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" + , " * `startLat` is the starting latitude value." + , " * `nlat` is the number of latitudes. If `nlat` is 1, the grid latitude boundaries will be `startLat` +/- `deltaLat/2`." + , " * `deltaLat` is the increment between latitudes. `startLon` is the starting longitude value." + , " * `nlon` is the number of longitudes. If `nlon` is 1, the grid longitude boundaries will be `startLon` +/- `deltaLon/2`." + , " * `deltaLon` is the increment between longitudes. `order` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." + , " * If specified, `mask` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "`Axis`", "`createUniformLatitudeAxis(startLat , nlat, deltaLat)`:" , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes." - , " * ``deltaLat`` is the increment between latitudes." - "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." - "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" + , " * `startLat` is the starting latitude value." + , " * `nlat` is the number of latitudes." + , " * `deltaLat` is the increment between latitudes." + "`RectGrid`"," `createZonalGrid(grid)`: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. `grid` is a RectGrid." + "`Axis`", "`createUniformLongitudeAxis(startLon, nlon, delta-Lon)`:" , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis." - , " * ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes." - , " * ``deltaLon`` is the increment between longitudes." - "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." - , " * See ``setAutoBounds``." - "``Integer``", "``isVariable(s)``: " - , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See Table 2.24" - , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" - , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" - "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." - "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:" + , " * `startLon` is the starting longitude value." + , " * `nlon` is the number of longitudes." + , " * `deltaLon` is the increment between longitudes." + "`Variable`", "`createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)`:" + "`Integer`", "`getAutoBounds()`: Get the current autobounds mode. Returns 0, 1, or 2." + , " * See `setAutoBounds`." + "`Integer`", "`isVariable(s)`: " + , " * Return `1` if `s` is a variable, `0` otherwise. See also: `asVariable`." + "`Dataset`", "`open(url,mode='r')`: Open or create a `Dataset` or `CdmsFile`." + , " * `url` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a `Dataset` is returned, otherwise a `CdmsFile` is returned." + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. `mode` is the open mode. See Table 2.24" + , " * **Example**: Open an existing dataset: `f = cdms.open('sampleset.xml')`" + , " * **Example**: Create a netCDF file: `f = cdms.open('newfile.nc','w')`" + "`List`", "`order2index (axes, orderstring)`:" + , "Find the index permutation of axes to match order. Return a list of indices. `axes` is a list of axis objects. `orderstring` is defined as in `orderparse`." + "`List`", "`orderparse(orderstring)`:" + , "Parse an order string. Returns a list of axes specifiers. `orderstring` consists of:" , " * Letters t, x, y, z meaning time, longitude, latitude, level" , " * Numbers 0-9 representing position in axes" , " * Dash (-) meaning insert the next available axis here." , " * The ellipsis ... meaning fill these positions with any remaining axes." , " * (name) meaning an axis whose id is name" - "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." - "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." - "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." + "`None`", "`setAutoBounds(mode)`:" + , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If `mode` is `'grid'` or `2` (the default), the `getBounds` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If `mode` is `'on'` or `1`, the `getBounds` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If `mode` is `'off'` or `0`, and no boundary data is explicitly defined, the bounds will NOT be generated; the `getBounds` method will return `None` for the boundaries. Note: In versions of CDMS prior to V4.0, the default `mode` was `'on'`." + "`None`", "`setClassifyGrids(mode)`:" + , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If `mode` is `'on'` (the default), grid type is determined by a grid classification method, regardless of the value of `grid.get-Type()`. If `mode` is `'off'`, the value of `grid.getType()` determines the grid type." + "`None`", "`writeScripGrid(path, grid, gridTitle=None)`:" + , "Write a grid to a SCRIP grid file. `path` is a string, the path of the SCRIP file to be created. `grid` is a CDMS grid object. It may be rectangular. `gridTitle` is a string ID for the grid." Table 2.3 Class Tags @@ -256,9 +256,9 @@ Table 2.5 Getting and setting attributes :header: "Type", "Definition" :widths: 20, 80 - "various", "``value = obj.attname``" + "various", "`value = obj.attname`" , "Get an internal or external attribute value. If the attribute is external, it is read from the database. If the attribute is not already in the database, it is created as an external attribute. Internal attributes cannot be created, only referenced." - "various", "``obj.attname = value``" + "various", "`obj.attname = value`" , "Set an internal or external attribute value. If the attribute is external, it is written to the database." @@ -282,10 +282,10 @@ Axis objects. :header: "Type", "Definition" :widths: 20, 80 - "``CoordinateAxis``", "A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``." - "``Axis``", "A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``." - "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." - "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." + "`CoordinateAxis`", "A variable that represents coordinate information. Has subtypes `Axis2D` and `AuxAxis1D`." + "`Axis`", "A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes `DatasetAxis`, `FileAxis`, and `TransientAxis`. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a `RectGrid`." + "`Axis2D`", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a `CurvilinearGrid`. Has subtypes `DatasetAxis2D`, `FileAxis2D`, and `TransientAxis2D`." + "`AuxAxis1D`", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a `GenericGrid`. Has subtypes `DatasetAuxAxis1D`, `FileAuxAxis1D`, and `TransientAuxAxis1D`. An axis in a `CdmsFile` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a `CdmsFile`." @@ -293,28 +293,28 @@ Axis objects. :header: "Type", "Name", "Definition" :widths: 20, 20, 80 - "``Dictionary``", "``attributes``", "External attribute dictionary." - "``String``", "``id``", "CoordinateAxis identifer." - "``Dataset``", "``parent``", "The dataset which contains the variable." - "``Tuple``", "``shape``", "The length of each axis." + "`Dictionary`", "`attributes`", "External attribute dictionary." + "`String`", "`id`", "CoordinateAxis identifer." + "`Dataset`", "`parent`", "The dataset which contains the variable." + "`Tuple`", "`shape`", "The length of each axis." .. csv-table:: Axis Constructors :header: "Constructor", "Description" :widths: 20, 80 - "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33." - "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" - , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" - , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited``" - , "``cdms.createEqualAreaAxis(nlat)``" + "`cdms.createAxis(data, bounds=None)`", "Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33." + "`Dataset.createAxis(name,ar)`", "Create an `Axis` in a `Dataset`. (This function is not yet implemented.)" + "`CdmsFile.createAxis(name,ar,unlimited=0)`", "Create an Axis in a `CdmsFile`. `name` is the string `name` of the `Axis`. `ar` is a 1-D data array which defines the `Axis` values. It may have the value `None` if an unlimited axis is being defined. At most one `Axis` in a `CdmsFile` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" + , "* A) set `ar` to `None`, and leave `unlimited` undefined, or" + , "* B) set `ar` to the initial 1-D array, and set `unlimited` to `cdms.Unlimited`" + , "`cdms.createEqualAreaAxis(nlat)`" , "* See Table 2.2 on page 33." - , "``cdms.createGaussianAxis(nlat)``" + , "`cdms.createGaussianAxis(nlat)`" , "* See Table 2.2 on page 18." - , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" + , "`cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`" , "* See Table 2.2 on page 18." - , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" + , "`cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`" , "* See Table 2.2 on page 18." @@ -322,35 +322,35 @@ Axis objects. :header: "Type", "Method", "Definition" :widths: 20, 20, 80 - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators." - "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." - "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." - "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." - "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." - "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis:" - ,,"* ``Axis``: ``(n,2)``" - ,,"* ``Axis2D``: ``(i,j,4)``" - ,,"* ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell." - ,,"If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." - "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are:" - ,,"* ``cdtime.GregorianCalendar``: the standard Gregorian calendar" - ,,"* ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar" - ,,"* ``cdtime.JulianCalendar``: years divisible by 4 are leap years" - ,,"* ``cdtime.NoLeapCalendar``: a year is 365 days" - ,,"* ``cdtime.Calendar360``: a year is 360 days" - ,,"* ``None``: no calendar can be identified" + "`Array`", "`array = axis[i:j]`", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators." + "`None`", "`axis[i:j] = array`", "Write a slice of data to the external file. Dataset axes are read-only." + "`None`", "`assignValue(array)`", "Set the entire value of the axis. `array` is a Numpy array, of the same dimensionality as the axis." + "`Axis`", "`clone(copyData=1)`", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." + "`None`", "`designateLatitude(persistent=0)`", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "`None`", "`designateLevel(persistent=0)`", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "`None`", "`designateLongitude(persistent=0, modulo=360.0)`", "Designate the axis to be a longitude axis. `modulo` is the modulus value. Any given axis value `x` is treated as equivalent to `x + modulus`. If `persistent` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "`None`", "`designateTime(persistent=0, calendar = cdtime.MixedCalendar)`", "Designate the axis to be a time axis. If `persistent` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. `calendar` is defined as in `getCalendar()`." + "`Array`", "`getBounds()`", "Get the associated boundary array. The shape of the return array depends on the type of axis:" + ,,"* `Axis`: `(n,2)`" + ,,"* `Axis2D`: `(i,j,4)`" + ,,"* `AuxAxis1D`: `(ncell, nvert)` where nvert is the maximum number of vertices of a cell." + ,,"If the boundary array of a latitude or longitude `Axis` is not explicitly defined, and `autoBounds` mode is on, a default array is generated by calling `genGenericBounds`. Otherwise if auto-Bounds mode is off, the return value is `None`. See `setAutoBounds`." + "`Integer`", "`getCalendar()`", "Returns the calendar associated with the `(time)`\ axis. Possible return values, as defined in the `cdtime` module, are:" + ,,"* `cdtime.GregorianCalendar`: the standard Gregorian calendar" + ,,"* `cdtime.MixedCalendar`: mixed Julian/Gregorian calendar" + ,,"* `cdtime.JulianCalendar`: years divisible by 4 are leap years" + ,,"* `cdtime.NoLeapCalendar`: a year is 365 days" + ,,"* `cdtime.Calendar360`: a year is 360 days" + ,,"* `None`: no calendar can be identified" ,," **Note** If the axis is not a time axis, the global, file-related calendar is returned." - "``Array``", "``getValue()``", "Get the entire axis vector." - "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." - "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." - "``Integer``", "``isLongitude()``", "Returns true iff the axis is a longitude axis." - "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." - "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." - "``Integer``", "``size()``", "The number of elements in the axis." - "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." + "`Array`", "`getValue()`", "Get the entire axis vector." + "`Integer`", "`isLatitude()`", "Returns true iff the axis is a latitude axis." + "`Integer`", "`isLevel()`", "Returns true iff the axis is a level axis." + "`Integer`", "`isLongitude()`", "Returns true iff the axis is a longitude axis." + "`Integer`", "`isTime()`", "Returns true iff the axis is a time axis." + "`Integer`", "`len(axis)`", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." + "`Integer`", "`size()`", "The number of elements in the axis." + "`String`", "`typecode()`", "The `Numpy` datatype identifier." @@ -358,56 +358,56 @@ Axis objects. :header: "Type", "Method", "Definition" :widths: 20, 20, 80 - "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." - "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." - "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if:" - ,," * ``axis.topology == 'circular'``, or" - ,," * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" - "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." - "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." - "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None or ':'``" - ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:" - ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" - ,,"* ``'n'`` - select node values which are contained in the interval" - ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" - ,,"* ``'e'`` - same as n, but include an extra node on either side" - ,,"* ``'s'`` - select axis elements for which the cell boundary is a subset of the interval" + "`List` of component times", "`asComponentTime(calendar=None)`", "`Array` version of `cdtime tocomp`. Returns a `List` of component times." + "`List` of relative times", "`asRelativeTime()`", "`Array` version of `cdtime torel`. Returns a `List` of relative times." + "`None`", "`designateCircular(modulo, persistent=0)`", "Designate the axis to be circular. `modulo` is the modulus value. Any given axis value `x` is treated as equivalent to `x + modulus`. If `persistent` is `True`, the external file or dataset (if any) is modified. By default, the designation is temporary." + "`Integer`", "`isCircular()`", "Returns `True` if the axis has circular topology. An axis is defined as circular if:" + ,," * `axis.topology == 'circular'`, or" + ,," * `axis.topology` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + "`Integer`", "`isLinear()`", "Returns `True` if the axis has a linear representation." + "`Tuple`", "`mapInterval(interval)`", "Same as `mapIntervalExt`, but returns only the tuple `(i,j)`, and `wraparound` is restricted to one cycle." + "`(i,j,k)`", "`mapIntervalExt(interval)`", "Map a coordinate interval to an index `interval`. `interval` is a tuple having one of the forms:" + ,,"* `(x,y)`" + ,,"* `(x,y,indicator)`" + ,,"* `(x,y,indicator,cycle)`" + ,,"* `None or ':'`" + ,,"* where `x` and `y` are coordinates indicating the interval `[x,y]`, and:" + ,,"* `indicator` is a two or three-character string, where the first character is `'c'` if the interval is closed on the left, `'o'` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" + ,,"* `'n'` - select node values which are contained in the interval" + ,,"* `'b'` -select axis elements for which the corresponding cell boundary intersects the interval" + ,,"* `'e'` - same as n, but include an extra node on either side" + ,,"* `'s'` - select axis elements for which the cell boundary is a subset of the interval" ,,"* The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected." - ,,"* If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``." - ,,"* An interval of ``None`` or ``':'`` returns the full index interval of the axis." - ,,"* The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty." - ,,"* for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``" - ,,"* if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint." + ,,"* If `cycle` is specified, the axis is treated as circular with the given cycle value. By default, if `axis.isCircular()` is true, the axis is treated as circular with a default modulus of `360.0`." + ,,"* An interval of `None` or `':'` returns the full index interval of the axis." + ,,"* The method returns the corresponding index interval as a 3tuple `(i,j,k)`, where `k` is the integer stride, and `[i.j)` is the half-open index interval `i <= k < j` `(i >= k > j if k < 0)`, or `none` if the intersection is empty." + ,,"* for an axis which is circular (`axis.topology == 'circular'`), `[i,j)` is interpreted as follows, where `n = len(axis)`" + ,,"* if `0 <= i < n` and `0 <= j <= n`, the interval does not wrap around the axis endpoint." ,,"* otherwise the interval wraps around the axis endpoint." - ,,"* see also: ``mapinterval``, ``variable.subregion()``" - "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." + ,,"* see also: `mapinterval`, `variable.subregion()`" + "`transientaxis`", "`subaxis(i,j,k=1)`", "create an axis associated with the integer range `[i:j:k]`. the stride `k` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." .. csv-table:: axis slice operators :header: "Slice", "Definition" :widths: 20, 80 - "``[i]``", "the ``ith`` element, starting with index ``0``" - "``[i:j]``", "the ``ith`` element through, but not including, element ``j``" - "``[i:]``", "the ``ith`` element through and including the end" - "``[:j]``", "the beginning element through, but not including, element ``j``" - "``[:]``", "the entire array" - "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" - "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." + "`[i]`", "the `ith` element, starting with index `0`" + "`[i:j]`", "the `ith` element through, but not including, element `j`" + "`[i:]`", "the `ith` element through and including the end" + "`[:j]`", "the beginning element through, but not including, element `j`" + "`[:]`", "the entire array" + "`[i:j:k]`", "every `kth` element, starting at `i`, through but not including `j`" + "`[-i]`", "the `ith` element from the end. `-1` is the last element." **example:** -a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length -``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index -interval(s), with wraparound. the result index interval ``-2 <= n < 3`` -wraps around, since ``-2 < 0``, and has a stride of ``1``. this is -equivalent to the two contiguous index intervals ``2 <= n < 0`` and -``0 <= n < 3`` +a longitude axis has value `[0.0, 2.0, ..., 358.0]`, of length +`180`. map the coordinate interval `-5.0 <= x < 5.0` to index +interval(s), with wraparound. the result index interval `-2 <= n < 3` +wraps around, since `-2 < 0`, and has a stride of `1`. this is +equivalent to the two contiguous index intervals `2 <= n < 0` and +`0 <= n < 3` .. doctest:: @@ -420,7 +420,7 @@ equivalent to the two contiguous index intervals ``2 <= n < 0`` and CdmsFile ^^^^^^^^ -A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` +A `CdmsFile` is a physical file, accessible via the `cdunif` interface. netCDF files are accessible in read-write mode. All other formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. @@ -433,11 +433,11 @@ Cdms-Files. See “cu Module” on page 180. :header: "Type", "Name", "Definition" :widths: 20, 20, 80 - "``Dictionary``", "``attributes``", "Global, external file attributes" - "``Dictionary``", "``axes``", "Axis objects contained in the file." - "``Dictionary``", "``grids``", "Grids contained in the file." - "``String``", "``id``", "File pathname." - "``Dictionary``", "``variables``", "Variables contained in the file." + "`Dictionary`", "`attributes`", "Global, external file attributes" + "`Dictionary`", "`axes`", "Axis objects contained in the file." + "`Dictionary`", "`grids`", "Grids contained in the file." + "`String`", "`id`", "File pathname." + "`Dictionary`", "`variables`", "Variables contained in the file." @@ -446,61 +446,61 @@ Cdms-Files. See “cu Module” on page 180. :widths: 20, 80 "Constructor", "Description" - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70." - "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." + "`fileobj = cdms.open(path, mode)`", "Open the file specified by path returning a CdmsFile object. `path` is the file pathname, a string. `mode` is the open mode indicator, as listed in Table 2.24 on page 70." + "`fileobj = cdms.createDataset(path)`", "Create the file specified by path, a string." .. csv-table:: CdmsFile Methods :header: "Type", "Method", "Definition" :widths: 20, 20, 80 - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors' on page 103." + "`Transient-Variable`", "`fileobj(varname, selector)`", "Calling a `CdmsFile`" + ,, "object as a function reads the region of data specified by the `selector`. The result is a transient variable, unless `raw = 1` is specified. See 'Selectors' on page 103." ,, " **Example:** The following reads data for variable 'prc', year 1980:" ,, " * >>> f = cdms.open('test.nc')" ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" - "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." + "`Variable`, `Axis`, or `Grid`", "`fileobj['id']`", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." ,, " **Example:** The following gets the persistent variable" - ,, " * ``v``, equivalent to" - ,, " * ``v = f.variables['prc']``." + ,, " * `v`, equivalent to" + ,, " * `v = f.variables['prc']`." ,, " * f = cdms.open('sample.nc')" ,, " * v = f['prc']" ,, " **Example:** The following gets the axis named time, equivalent to" - ,, " * ``t = f.axes['time']``." - ,, " * ``t = f['time']``" - "``None``", "``close()``", "Close the file." - "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." - "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." - "``Axis``", "``createAxis(id, ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid, String datatype, Listaxes, fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." + ,, " * `t = f.axes['time']`." + ,, " * `t = f['time']`" + "`None`", "`close()`", "Close the file." + "`Axis`", "`copyAxis(axis, newname=None)`", "Copy `axis` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. `axis` is the axis object to be copied. `newname`, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + "`Grid`", "`copyGrid(grid, newname=None)`", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. `grid` is the grid object to be copied. `newname`, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + "`Axis`", "`createAxis(id, ar, unlimited=0)`", "Create a new `Axis`. This is a persistent object which can be used to read or write axis data to the file. `id` is an alphanumeric string identifier, containing no blanks. `ar` is the one-dimensional axis array. Set `unlimited` to `cdms.Unlimited` to indicate that the axis is extensible." + "`RectGrid`", "`createRectGrid(id, lat, lon, order, type='generic', mask=None)`", "Create a `RectGrid` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. `lat` is a latitude axis in the file. `lon` is a longitude axis in the file. `order` is a string with value `'yx'` (the latitude) or `'xy'` (the first grid dimension is longitude). `type` is one of `'gaussian'`,\ `'unif orm'`,\ `'equalarea'` , or `'generic'`. If specified, `mask` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "`Variable`", "`createVariable(Stringid, String datatype, Listaxes, fill_value=None)`", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. `id` is a String name which is unique with respect to all other objects in the file. `datatype` is an `MV2` typecode, e.g., `MV2.Float`, `MV2.Int`. `axes` is a list of Axis and/or Grid objects. `fill_value` is the missing value (optional)." + "`Variable`", "`createVariableCopy(var, newname=None)`", "Create a new `Variable`, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. `var` is the `Variable` to be copied. `newname`, if specified is the name of the new variable. If unspecified, the returned variable has the same name as `var`." ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self, whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." - "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." - ,,"* ``var`` is a Variable, masked array, or Numpy array." - ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." - ,,"* ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``." - ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." - ,,"* ``id`` is the variable name in the file. Default is ``var.id``." - ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." - ,," * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." - ,,"* ``fill_value`` is the missing value flag." - ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." + "`CurveGrid` or `Generic-Grid`", "`readScripGrid(self, whichGrid='destination', check-Grid=1)`", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, `whichGrid` chooses the grid to read, either `'source'` or `'destination'`. If `checkGrid` is `1` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a `0 / 2pi` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "`None`", "`sync()`", "Writes any pending changes to the file." + "`Variable`", "`write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)`","Write a variable or array to the file. The return value is the associated file variable." + ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords `extend` and `index`, and the unlimited dimension values associated with `var`." + ,,"* `var` is a Variable, masked array, or Numpy array." + ,,"* `attributes` is the attribute dictionary for the variable. The default is `var.attributes`." + ,,"* `axes` is the list of file axes comprising the domain of the variable. The default is to copy `var.getAxisList()`." + ,,"* `extbounds` is the unlimited dimension bounds. Defaults to `var.getAxis(0).getBounds()`." + ,,"* `id` is the variable name in the file. Default is `var.id`." + ,,"* `extend = 1` causes the first dimension to be unlimited: iteratively writeable." + ,," * The default is `None`, in which case the first dimension is extensible if it is `time.Set` to `0` to turn off this behaviour." + ,,"* `fill_value` is the missing value flag." + ,,"* `index` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." .. csv-table:: CDMS Datatypes :header: "CDMS Datatype", "Definition" :widths: 20, 30 - "``CdChar``", "character" - "``CdDouble``", "double-precision floating-point" - "``CdFloat``", "floating-point" - "``CdInt``", "integer" - "``CdLong``", "long integer" - "``CdShort``", "short integer" + "`CdChar`", "character" + "`CdDouble`", "double-precision floating-point" + "`CdFloat`", "floating-point" + "`CdInt`", "integer" + "`CdLong`", "long integer" + "`CdShort`", "short integer" Database @@ -522,7 +522,7 @@ The figure below illustrates several important points: - The name of the object consists of its relative name followed by the relative name(s) of its antecedent objects, up to and including the database name. In the figure below, one of the variables has name - ``"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"``. + `"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS"`. - Subordinate objects are thought of as being contained in the parent. In this example, the database ‘CDMS’ contains two datasets, each of @@ -539,7 +539,7 @@ To access a database: #. Open a connection. The connect method opens a database connection. connect takes a database URI and returns a database object: - ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` + `db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")` #. Search the database, locating one or more datasets, variables, and/or other objects. @@ -548,13 +548,13 @@ To access a database: **Example**: Find all observed datasets - ``result = db.searchFilter(category="observed",tag="dataset")`` + `result = db.searchFilter(category="observed",tag="dataset")` Searches can be restricted to a subhierarchy of the database. - **Example:** Search just the dataset ``'ncep_reanalysis_mo'``: + **Example:** Search just the dataset `'ncep_reanalysis_mo'`: - ``result = db.searchFilter(relbase="dataset=ncep_reanalysis")`` + `result = db.searchFilter(relbase="dataset=ncep_reanalysis")` #. Refine the search results if necessary. The result of a search can be narrowed with the searchPredicate method. @@ -563,32 +563,32 @@ To access a database: attribute dictionary, consisting of the attributes located by the search: - `` for entry in result: print entry.name, entry.attributes`` + ` for entry in result: print entry.name, entry.attributes` #. Access the data. The CDMS object associated with an entry is obtained from the getObject method: - ``obj = entry.getObject()`` + `obj = entry.getObject()` If the id of a dataset is known, the dataset can be opened directly with the open method: - ``dset = db.open("ncep_reanalysis_mo")`` + `dset = db.open("ncep_reanalysis_mo")` #. Close the database connection: - ``db.close()`` + `db.close()` .. csv-table:: Database Internal Attributes :header: "Type", "Name", "Summary" :widths: 20, 20, 80 - "``Dictionary``", "``attributes``", "Database attribute dictionary" - "``LDAP``", "``db``", "(LDAP only) LDAP database object" - "``String``", "``netloc``", "Hostname, for server-based databases" - "``String``", "``path``", "path name" - "``String``", "``uri``", "Uniform Resource Identifier" + "`Dictionary`", "`attributes`", "Database attribute dictionary" + "`LDAP`", "`db`", "(LDAP only) LDAP database object" + "`String`", "`netloc`", "Hostname, for server-based databases" + "`String`", "`path`", "path name" + "`String`", "`uri`", "Uniform Resource Identifier" ------------ @@ -596,9 +596,9 @@ To access a database: :header: "Constructor", "Description" :widths: 30, 80 - "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." - ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." - ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" + "`db = cdms.connect(uri=None, user='', password='')`", "Connect to the database. `uri` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." + ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: `ldap://host[:port]/dbname`." + ,"For example, if the database is located on host dbhost.llnl.gov, and is named `'database=CDMS,ou=PCMDI,o=LLNL,c=US'`, the URI is: `ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US`. If unspecified, the URI defaults to the value of environment variable CDMSROOT. `user` is the user ID. If unspecified, an anonymous connection is made. `password` is the user password. A password is not required for an anonymous connection" ------------ @@ -606,35 +606,35 @@ To access a database: :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "None", "``close()``", "Close a database" - "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." - "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." - , "* ``dsetid``"," is the string dataset identifier" - , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." - , "* ``openDataset``", "is a synonym for ``open``." - "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." + "None", "`close()`", "Close a database" + "List", "`listDatasets()`", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the `open` command." + "Dataset", "`open(dsetid, mode='r')`", "Open a dataset." + , "* `dsetid`"," is the string dataset identifier" + , "* `mode`","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." + , "* `openDataset`", "is a synonym for `open`." + "SearchResult","`searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)`","Search a CDMS database." + ,, "`filter` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." ,, ,," **Example:**" - ,," * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'." + ,," * The filter `'(&(objec)(id=cli))'` finds all variables named 'cli'." ,," - A formal definition of search filters is provided in the following section." - ,," - ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." - ,," - ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." + ,," - `tag` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." + ,," - `relbase` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." ,, ,," **Example:**" ,," * To search only dataset 'ncep_reanalysis_mo', specify:" - ,," - ``relbase='dataset=ncep_reanalysis_mo'``" + ,," - `relbase='dataset=ncep_reanalysis_mo'`" ,," * To search only variable 'ua' in 'ncep_reanalysis_mo', use:" - ,," - ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``" + ,," - `relbase='variable=ua, dataset=ncep_reanalysis_mo'`" ,, - ,,"If no base is specified, the entire database is searched. See the ``scope`` argument also." - ,,"``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**)." + ,,"If no base is specified, the entire database is searched. See the `scope` argument also." + ,,"`scope` is the search scope (**Subtree** | **Onelevel** | **Base**)." ,," * **Subtree** searches the base object and its descendants." ,," * **Onelevel** searches the base object and its immediate descendants." ,," * **Base**\ searches the base object alone." ,," * The default is **Subtree**." - ,,"``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." - ,,"``timeout``: integer number of seconds before timeout. The default is no timeout." + ,,"`attnames`: list of attribute names. Restricts the attributes returned. If `None`, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." + ,,"`timeout`: integer number of seconds before timeout. The default is no timeout." ------------ @@ -644,10 +644,10 @@ To access a database: 2.7.2 Searching a database -The ``searchFilter`` method is used to search a database. The result is +The `searchFilter` method is used to search a database. The result is called a search result, and consists of a sequence of result entries. -In its simplest form, ``searchFilter`` takes an argument consisting of a +In its simplest form, `searchFilter` takes an argument consisting of a string filter. The search returns a sequence of entries, corresponding to those objects having an attribute which matches the filter. Simple filters have the form (tag = value), where value can contain wildcards. @@ -695,10 +695,10 @@ Attribute names are defined in the chapter on “Climate Data Markup Language (CDML)” on page 149. In addition, some special attributes are defined for convenience: -- ``category`` is either “experimental” or “observed” -- ``parentid`` is the ID of the parent dataset -- ``project`` is a project identifier, e.g., “AMIP2” -- ``objectclass`` is the list of tags associated with the object. +- `category` is either “experimental” or “observed” +- `parentid` is the ID of the parent dataset +- `project` is a project identifier, e.g., “AMIP2” +- `objectclass` is the list of tags associated with the object. The set of objects searched is called the search scope. The top object in the hierarchy is the base object. By default, all objects in the @@ -723,7 +723,7 @@ several ways: for entry in result: print entry.name -Search results can be narrowed using ``searchPredicate``. In the +Search results can be narrowed using `searchPredicate`. In the following example, the result of one search is itself searched for all variables defined on a 94x192 grid: @@ -756,10 +756,10 @@ Table 2.19 SearchResult Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):``" - "Integer", "``len()``", "Number of entries in the result." - "SearchResult", " ``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." - ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + "ResultEntry", "`[i]`", "Return the i-th search result. Results can also be returned in a for loop: `for entry in db.searchResult(tag='dataset'):`" + "Integer", "`len()`", "Number of entries in the result." + "SearchResult", " `searchPredicate(predicate, tag=None)`", "Refine a search result, with a predicate search. `predicate` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. `tag` restricts the search to objects of the class denoted by the tag." + ,,"**Note**: In the current implementation, `searchPredicate` is much less efficient than `searchFilter`. For best performance, use `searchFilter` to narrow the scope of the search, then use `searchPredicate` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -767,7 +767,7 @@ dictionary. An entry corresponds to an object found by the search, but differs from the object, in that only the attributes requested are associated with the entry. In general, there will be much more information defined for the associated CDMS object, which is retrieved -with the ``getObject`` method. +with the `getObject` method. Table 2.20 ResultEntry Attributes @@ -776,8 +776,8 @@ Table 2.20 ResultEntry Attributes :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "String", "``name``", "The name of this entry in the database." - "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" + "String", "`name`", "The name of this entry in the database." + "Dictionary", "`attributes`", "The attributes returned from the search. `attributes[key]` is a list of all string values associated with the key" Table 2.21 ResultEntry Methods @@ -786,7 +786,7 @@ Table 2.21 ResultEntry Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry." + "`CdmsObj`", "`getObject()`", "Return the CDMS object associated with this entry." ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." @@ -817,7 +817,7 @@ In the following examples, db is the database opened with db = cdms.connect() This defaults to the database defined in environment variable -``CDMSROOT``. +`CDMSROOT`. **Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: @@ -902,15 +902,15 @@ Table 2.22 Dataset Internal Attributes :header: "Type", "Name", "Description" :widths: 20, 30, 80 - "Dictionary", "``attributes``", "Dataset external attributes." - "Dictionary", "``axes``", "Axes contained in the dataset." - "String", "``datapath``", "Path of data files, relative to the parent database. If no parent, the datapath is absolute." - "Dictionary", "``grids``", "Grids contained in the dataset." - "String", "``mode``", "Open mode." - "Database", "``parent``", "Database which contains this dataset. If the dataset is not part of a database, the value is ``None``." - "String", "``uri``", "Uniform Resource Identifier of this dataset." - "Dictionary", "``variables``", "Variables contained in the dataset." - "Dictionary", "``xlinks``", "External links contained in the dataset." + "Dictionary", "`attributes`", "Dataset external attributes." + "Dictionary", "`axes`", "Axes contained in the dataset." + "String", "`datapath`", "Path of data files, relative to the parent database. If no parent, the datapath is absolute." + "Dictionary", "`grids`", "Grids contained in the dataset." + "String", "`mode`", "Open mode." + "Database", "`parent`", "Database which contains this dataset. If the dataset is not part of a database, the value is `None`." + "String", "`uri`", "Uniform Resource Identifier of this dataset." + "Dictionary", "`variables`", "Variables contained in the dataset." + "Dictionary", "`xlinks`", "External links contained in the dataset." Table 2.23 Dataset Constructors @@ -918,7 +918,7 @@ Table 2.23 Dataset Constructors :header: "Constructor", "Description" :widths: 50, 80 - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open``" + "`datasetobj = cdms.open(String uri, String mode='r')`", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. `openDataset` is a synonym for `open`" Table 2.24 Open Modes @@ -939,35 +939,35 @@ Table 2.25 Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See "Selectors" on page 103." + "Transient-Variable", "`datasetobj(varname, selector)`", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless `raw = 1` is specified. See 'Selectors' on page 103." ,, "**Example:** The following reads data for variable 'prc', year 1980:" ,, " * f = cdms.open('test. xml')" ,, " * x = f('prc', time=('1980-1','1981-1'))" - "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found." + "Variable, Axis, or Grid", "`datasetobj['id']`", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns `None` if not found." ,, "**Example:**" ,, " * f = cdms.open('sampl e.xml')" ,, " * v = f['prc']" - ,, " * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``." + ,, " * gets the persistent variable v, equivalent to `v =f.variab les['prc']`." ,, "**Example:**" - ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" - "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type="generic", mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." - ,,"``lat`` is a latitude axis in the dataset." - ,,"``lon`` is a longitude axis in the dataset." - ,,"``order`` is a string with value "yx" (the first grid dimension is latitude) or "xy" (the first grid dimension is longitude)." - ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" - ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." - ,,"``id`` is the string axis identifier." - "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset." - ,,"``id`` is the string grid identifier." - "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." - "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." - ,,"``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-or Generic-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." - ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``"source"`` or ``"destination"``." - ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." - "None", "``sync()``", "Write any pending changes to the dataset." + ,, "`t = f['time']` gets the axis named 'time', equivalent to `t = f.axes['time']`" + "`None`", "`close()`", "Close the dataset." + "`RectGrid`", "`createRectGrid(id, lat, lon, order, type='generic', mask=None)`", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." + ,,"`lat` is a latitude axis in the dataset." + ,,"`lon` is a longitude axis in the dataset." + ,,"`order` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." + ,,"`type` is one of 'gaussian','uniform','eq ualarea',or 'generic'" + ,,"If specified, `mask` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "Axis", "`getAxis(id)`", "Get an axis object from the file or dataset." + ,,"`id` is the string axis identifier." + "Grid", "`getGrid(id)`", "Get a grid object from a file or dataset." + ,,"`id` is the string grid identifier." + "List", "`getPaths()`", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." + "Variable", "`getVariable(id)`", "Get a variable object from a file or dataset." + ,,"`id` is the string variable identifier." + "CurveGrid or GenericGrid", "`readScripGrid(self, whichGrid='destination', check-or Generic-Grid=1)`", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." + ,, "If a mapping file, `whichGrid` chooses the grid to read, either `'source'` or `'destination'`." + ,, " If `checkGrid` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a `0 / 2pi` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "None", "`sync()`", "Write any pending changes to the dataset." MV module @@ -1017,14 +1017,14 @@ attribute, it can also be set like any attribute: For completeness MV provides access to all the MV2 functions. The functions not listed in the following tables are identical to the -corresponding MV2 function: ``allclose``, ``allequal``, -``common_fill_value``, ``compress``, ``create_mask``, ``dot``, ``e``, -``fill_value``, ``filled``, ``get_print_limit``, ``getmask``, -``getmaskarray``, ``identity``, ``indices``, ``innerproduct``, ``isMV2``, -``isMaskedArray``, ``is_mask``, ``isarray``, ``make_mask``, -``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, -``putmask``, ``rank``, ``ravel``, ``set_fill_value``, -``set_print_limit``, ``shape``, ``size``. See the documentation at +corresponding MV2 function: `allclose`, `allequal`, +`common_fill_value`, `compress`, `create_mask`, `dot`, `e`, +`fill_value`, `filled`, `get_print_limit`, `getmask`, +`getmaskarray`, `identity`, `indices`, `innerproduct`, `isMV2`, +`isMaskedArray`, `is_mask`, `isarray`, `make_mask`, +`make_mask_none`, `mask_or`, `masked`, `pi`, `put`, +`putmask`, `rank`, `ravel`, `set_fill_value`, +`set_print_limit`, `shape`, `size`. See the documentation at http://numpy.sourceforge.net for a description of these functions. @@ -1034,14 +1034,14 @@ Table 2.26 Variable Constructors in module MV :header: "Constructor", "Description" :widths: 30, 80 - "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange``" - "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." - "``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." - "``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead." - "``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." - "``reshape(a, newshape, axes=none, attributes=none, id=none)``", "copy of a with a new shape." - "``resize(a, new_shape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size". - "``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "an array of all zeros of the given length or shape" + "`arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)`", "Just like `MV2.arange()` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* `arange`" + "`masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)`", "Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." + "`masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)`", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." + "`masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)`", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where `abs(data - value) < atol + rtol * abs(data)`. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead." + "`ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`", "return an array of all ones of the given length or shape." + "`reshape(a, newshape, axes=none, attributes=none, id=none)`", "copy of a with a new shape." + "`resize(a, new_shape, axes=none, attributes=none, id=none)`", "return a new array with the specified shape. the original arrays total size can be any size". + "`zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)`", "an array of all zeros of the given length or shape" The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. @@ -1053,33 +1053,33 @@ Table 2.27 MV functions :header: "Function", "Description" :widths: 30, 80 - "``argsort(x, axis=-1, fill_value=None)``", "Return a Numpy array of indices for sorting along a given axis." - "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function." - "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." | - "``choose(condition, t)``", "Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked." - "``concatenate(arrays, axis=0, axisid=None, axisattributes=None)``", "Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array." - "``count(a, axis=None)``", "Count of the non-masked elements in ``a``, or along a certain axis." - "``isMaskedVariable(x)``", "Return true if ``x`` is an instance of a variable." - "``masked_equal(x, value)``", "``x`` masked where ``x`` equals the scalar value. For floating point values consider ``masked_values(x, value)`` instead." - "``masked_greater(x, value)``", "``x`` masked where ``x > value``" - "``masked_greater_equal(x, value)``", "``x`` masked where ``x >= value``" - "``masked_less(x, value)``", "``x`` masked where ``x < value``" - "``masked_less_equal(x, value)``", "``x`` masked where ``x ≤ value``" - "``masked_not_equal(x, value)``", "``x`` masked where ``x != value``" - "``masked_outside(x, v1, v2)``", "``x`` with mask of all values of ``x`` that are outside ``[v1,v2]``" - "``masked_where(condition, x, copy=1)``", "Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``." - "``maximum(a, b=None)``", "Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked." - "``minimum(a, b=None)``", "Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked." - "``outerproduct(a, b)``", "Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked." - "``power(a, b)``", "``a**b``" - "``product(a, axis=0, fill_value=1)``", "Product of elements along axis using ``fill_value`` for missing elements." - "``repeat(ar, repeats, axis=0)``", "Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element." - "``set_default_fill_value(value_type, value)``", "Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array." - "``sort(ar, axis=-1)``", "Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values." - "``sum(a, axis=0, fill_value=0)``", "Sum of elements along a certain axis using ``fill_value`` for missing." - "``take(a, indices, axis=0)``", "Return a selection of items from ``a``. See the documentation in the Numpy manual." - "``transpose(ar, axes=None)``", "Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes." - "``where(condition, x, y)``", "``x`` where ``condition`` is true, ``y`` otherwise" + "`argsort(x, axis=-1, fill_value=None)`", "Return a Numpy array of indices for sorting along a given axis." + "`asarray(data, typecode=None)`", "Same as `cdms.createVariable(data, typecode, copy=0)`. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in `data = asarray(data)`. Also see the variable `astype()` function." + "`average(a, axis=0, weights=None)`", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: `sum(a*weights)/sum(weights)` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." | + "`choose(condition, t)`", "Has a result shaped like array condition. `t` must be a tuple of two arrays `t1` and `t2`. Each element of the result is the corresponding element of `t1`\ where `condition` is true, and the corresponding element of `t2` where `condition` is false. The result is masked where `condition` is masked or where the selected element is masked." + "`concatenate(arrays, axis=0, axisid=None, axisattributes=None)`", "Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array." + "`count(a, axis=None)`", "Count of the non-masked elements in `a`, or along a certain axis." + "`isMaskedVariable(x)`", "Return true if `x` is an instance of a variable." + "`masked_equal(x, value)`", "`x` masked where `x` equals the scalar value. For floating point values consider `masked_values(x, value)` instead." + "`masked_greater(x, value)`", "`x` masked where `x > value`" + "`masked_greater_equal(x, value)`", "`x` masked where `x >= value`" + "`masked_less(x, value)`", "`x` masked where `x < value`" + "`masked_less_equal(x, value)`", "`x` masked where `x ≤ value`" + "`masked_not_equal(x, value)`", "`x` masked where `x != value`" + "`masked_outside(x, v1, v2)`", "`x` with mask of all values of `x` that are outside `[v1,v2]`" + "`masked_where(condition, x, copy=1)`", "Return `x` as a variable masked where condition is true. Also masked where `x` or `condition` masked. `condition` is a masked array having the same shape as `x`." + "`maximum(a, b=None)`", "Compute the maximum valid values of `x` if `y` is `None`; with two arguments, return the element-wise larger of valid values, and mask the result where either `x` or `y` is masked." + "`minimum(a, b=None)`", "Compute the minimum valid values of `x` if `y` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either `x` or `y` is masked." + "`outerproduct(a, b)`", "Return a variable such that `result[i, j] = a[i] * b[j]`. The result will be masked where `a[i]` or `b[j]` is masked." + "`power(a, b)`", "`a**b`" + "`product(a, axis=0, fill_value=1)`", "Product of elements along axis using `fill_value` for missing elements." + "`repeat(ar, repeats, axis=0)`", "Return `ar` repeated `repeats` times along `axis`. `repeats` is a sequence of length `ar.shape[axis]` telling how many times to repeat each element." + "`set_default_fill_value(value_type, value)`", "Set the default fill value for `value_type` to `value`. `value_type` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. `value` should be a scalar or single-element array." + "`sort(ar, axis=-1)`", "Sort array `ar` elementwise along the specified axis. The corresponding axis in the result has dummy values." + "`sum(a, axis=0, fill_value=0)`", "Sum of elements along a certain axis using `fill_value` for missing." + "`take(a, indices, axis=0)`", "Return a selection of items from `a`. See the documentation in the Numpy manual." + "`transpose(ar, axes=None)`", "Perform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes." + "`where(condition, x, y)`", "`x` where `condition` is true, `y` otherwise" HorizontalGrid @@ -1103,8 +1103,8 @@ Table 2.28 :header: "Grid Type", "Definition" :widths: 30, 80 - "``RectGrid``", "Associated latitude an longitude are 1-D axes, with strictly monotonic values." - "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" + "`RectGrid`", "Associated latitude an longitude are 1-D axes, with strictly monotonic values." + "`GenericGrid`", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" Table 2.29 HorizontalGrid Internal Attribute @@ -1113,10 +1113,10 @@ Table 2.29 HorizontalGrid Internal Attribute :header: "Type", "Name", "Definition" :widths: 30, 30, 80 - "Dictionary","``attributes``", "External attribute dictionary." - "String", "``id``", "The grid identifier." - "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." - "Tuple", "``shape``", "The shape of the grid, a 2-tuple" + "Dictionary","`attributes`", "External attribute dictionary." + "String", "`id`", "The grid identifier." + "Dataset or CdmsFile", "`parent`", "The dataset or file which contains the grid." + "Tuple", "`shape`", "The shape of the grid, a 2-tuple" Table 2.30 RectGrid Constructors @@ -1125,15 +1125,15 @@ Table 2.30 RectGrid Constructors :header: "Constructor", "Description" :widths: 30, 80 - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See Table 2.2" - "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" - "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" - "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See Table 2.2" - "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See Table 2.2" - "``cdms.createGlobalMeanGrid(grid)``", "See Table 2.2." - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "See Table 2.2" - "``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None)``", "See Table 2.2" - "``cdms.createZonalGrid(grid)``", " See Table 2.2" + "`cdms.createRectGrid(lat, lon, order, type='generic', mask=None)`", "Create a grid not associated with a file or dataset. See Table 2.2" + "`CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)`", "Create a grid associated with a file. See Table 2.14" + "`Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)`", "Create a grid associated with a dataset. See Table 2.25" + "`cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')`", "See Table 2.2" + "`cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)`", "See Table 2.2" + "`cdms.createGlobalMeanGrid(grid)`", "See Table 2.2." + "`cdms.createRectGrid(lat, lon, order, type='generic', mask=None)`", "See Table 2.2" + "`cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None)`", "See Table 2.2" + "`cdms.createZonalGrid(grid)`", " See Table 2.2" Table 2.31 HorizontalGrid Methods @@ -1142,36 +1142,36 @@ Table 2.31 HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." - "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." - "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" + "Horizontal-Grid", "`clone()`", "Return a transient copy of the grid." + "Axis", "`getAxis(Integer n)`", "Get the n-th axis.n is either 0 or 1." + "Tuple", "`getBounds()`", "Get the grid boundary arrays." + ,,"Returns a tuple `(latitudeArray, longitudeArray)`, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." - ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids` `)." + ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see `cdms.setAutoBounds`) and the grid classification mode (see `cdms.setClassifyGrids` `)." ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." - "Axis", "``getLatitude()``", "Get the latitude axis of this grid." - "Axis", "``getLongitude()``", " Get the latitude axis of this grid." - "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." - "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." - "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." - ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." - "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." - "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.``" - ,,"``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively." + "Axis", "`getLatitude()`", "Get the latitude axis of this grid." + "Axis", "`getLongitude()`", " Get the latitude axis of this grid." + "Axis", "`getMask()`", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is `None`." + "Axis", "`getMesh(self, transpose=None)`", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." + "None", "`setBounds(latBounds, lonBounds, persistent=0)`", "Set the grid boundaries. `latBounds` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are `[latBounds[k,0],latBou nds[k,1] ]`. `lonBounds` is defined similarly for the longitude array." + ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument `persistent` is set to the boundary array is written to the file." + "None", "`setMask(mask, persistent=0)`", "Set the grid mask. If `persistent == 1`, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. `mask` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." + "Horizontal-Grid", "`subGridRegion(latInterval, lonInterval)`", "Create a new grid corresponding to the coordinate region defined by `latInterval, lonInterv al.`" + ,,"`latInterval` and `lonInterval` are the coordinate intervals for latitude and longitude, respectively." ,,"Each interval is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None``" - ,,"where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" - ,,"``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." - ,,"If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0." - ,,"An interval of ``None`` returns the full index interval of the axis." + ,,"* `(x,y)`" + ,,"* `(x,y,indicator)`" + ,,"* `(x,y,indicator,cycle)`" + ,,"* `None`" + ,,"where `x` and `y` are coordinates indicating the interval `[x,y)`, and:" + ,,"`indicator` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." + ,,"If `cycle` is specified, the axis is treated as circular with the given cycle value. By default, if `grid.isCircular()` is true, the axis is treated as circular with a default value of 360.0." + ,,"An interval of `None` returns the full index interval of the axis." ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." - ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + "Transient-CurveGrid", "`toCurveGrid(gridid=None)`", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. `gridid` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid `toGenericGrid(gridid=None)` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. `gridid` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods @@ -1180,27 +1180,27 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if longitude is the first axis. String ``getType()`` Get the grid type, either "gaussian", "uniform", "equalarea", or "generic". (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." + "String", "`getOrder()`", Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if longitude is the first axis. String `getType()` Get the grid type, either "gaussian", "uniform", "equalarea", or "generic". (Array,Array) `getWeights()` Get the normalized area weight arrays, as a tuple `(latWeights, lonWeights)`. It is assumed that the latitude and longitude axes are defined in degrees." ,,"The latitude weights are defined as:" - ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" + ,,"`latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`" ,," The longitude weights are defined as: - ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" + ,,"`lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0`" ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" ,,"**Example:**" - ,,"Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``." + ,,"Generate the 2-D weights array, such that `weights[i.j]` is the fractional area of grid zone `[i,j]`." ,,"* from cdms import MV" ,,"* latwts, lonwts = gri d.getWeights()" ,,"* weights = MV.outerproduct(latwts, lonwts)" - ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." + ,,"Also see the function `area_weights` in module `pcmdi.weighting`." ,,"" - "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of "gaussian", "uniform", "equalarea", or "generic"." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." + "None", "`setType(gridtype)`", "Set the grid type. `gridtype` is one of "gaussian", "uniform", "equalarea", or "generic"." + "RectGrid", "`subGrid((latStart,latStop),(lonStart,lonStop))`", "Create a new grid, with latitude index range ` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." ,,"**Example:**" ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." - ,,"``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))``" + ,,"`newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`" ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges." ,,"**Note:** The result grid is not associated with any file or dataset." - "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed." + "RectGrid", "`transpose()`", "Create a new grid, with axis order reversed. The grid mask is also transposed." ,,"**Note:** The result grid is not associated with any file or dataset." @@ -1238,11 +1238,11 @@ Table 2.33 Variable Internal Attributes :header: "Type", "Name", "Definition" :widths: 30, 30, 80 - "Dictionary", "``attributes``", "External attribute dictionary." - "String", "``id``", "Variable identifier." - "String", "``name_in_file``", "The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased." - "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the variable." - "Tuple", "``shape``", "The length of each axis of the variable" + "Dictionary", "`attributes`", "External attribute dictionary." + "String", "`id`", "Variable identifier." + "String", "`name_in_file`", "The name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased." + "Dataset or CdmsFile", "`parent`", "The dataset or file which contains the variable." + "Tuple", "`shape`", "The length of each axis of the variable" Table 2.34 Variable Constructors @@ -1251,11 +1251,11 @@ Table 2.34 Variable Constructors :header: "Constructor", "Description" :widths: 30, 80 - "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." - "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)", "Create a Variable in a CdmsFile." - ,,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "`Dataset.createVariable(String id, String datatype, List axes)`", "Create a Variable in a Dataset. This function is not yet implemented." + "`CdmsFile.createVariable(String id, String datatype, List axes or Grids)`", "Create a Variable in a CdmsFile." + ,,"`id` is the name of the variable. `datatype` is the MV2 or Numpy | typecode, for example, MV2.Float. `axesOrGrids` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: `(axisobj,)`." - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None) ``", " Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer n." + "`cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None) `", " Create a transient variable, not associated with a file or dataset. `array` is the data values: a Variable, masked array, or Numpy array. `typecode` is the MV2 typecode of the array. Defaults to the typecode of array. `copy` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. `savespace` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. `mask` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. `fill_value` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. `grid` is a rectilinear grid object. `axes` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. `attributes` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. `id` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer n." @@ -1265,46 +1265,46 @@ Table 2.35 Variable Methods :header: "Type", "Method", "Definition" :widths: 30, 30, 80 - "Variable", "``tvar = var[ i:j, m:n]``","Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" - "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See "Selectors"." - "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." - "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." - "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." + "Variable", "`tvar = var[ i:j, m:n]`","Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" + "None", "`var[ i:j, m:n] = array`", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)" + "Variable", "`tvar = var(selector)`", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See "Selectors"." + "None", "`assignValue(Array ar)`", "Write the entire data array. Equivalent to `var[:] = ar`. (Variables in CdmsFiles only)." + "Variable", "`astype(typecode)`", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." + "Variable", "`clone(copyData=1)`", "Return a copy of a transient variable." ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." ,,"Transient Variable :: Return a lat/level vertical cross-section" ,,"crossSectionRegrid(n regridded to a new set ewLevel, newLatitude, me of latitudes newLatitude thod="log", missing=None and levels newLevel. The , order=None) variable should be a function of latitude, level, and (optionally) time." - ,,"``newLevel`` is an axis of the result pressure levels." - ,,"``newLatitude`` is an axis of the result latitudes." - ,,"``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." - ,,"``missing`` is a missing data value. The default is ``var.getMissing()``" - ,,"``order`` is an order string such as "tzy" or "zy". The default is ``var.getOrder()``." - ,,"*See also:* ``regrid``, ``pressureRegrid``." + ,,"`newLevel` is an axis of the result pressure levels." + ,,"`newLatitude` is an axis of the result latitudes." + ,,"`method` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." + ,,"`missing` is a missing data value. The default is `var.getMissing()`" + ,,"`order` is an order string such as "tzy" or "zy". The default is `var.getOrder()`." + ,,"*See also:* `regrid`, `pressureRegrid`." ,,"" - "Axis", "``getAxis(n)``", "Get the n-th axis." - ,,"``n`` is an integer." - "List", "``getAxisIds()``", "Get a list of axis identifiers." - "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." - ,,"``axis_spec`` is a specification as defined for getAxisList" - "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable." - ,,"If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." - ,,"If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." - ,,"``order`` is an optional string determining the output order." + "Axis", "`getAxis(n)`", "Get the n-th axis." + ,,"`n` is an integer." + "List", "`getAxisIds()`", "Get a list of axis identifiers." + "Integer", "`getAxisIndex(axis_spec)`", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." + ,,"`axis_spec` is a specification as defined for getAxisList" + "List", "`getAxisList(axes=None, omit=None, order=None)`", "Get an ordered list of axis objects in the domain of the variable." + ,,"If `axes` is not `None`, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." + ,,"If `omit` is not `None`, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." + ,,"`order` is an optional string determining the output order." ,,"Specifications for the axes or omit keywords are a list, each element having one of the following forms:" ,,"* an integer dimension index, starting at 0." ,,"* a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'." ,,"* a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches." ,,"* an axis object; will match if it is the same object as axis." - ,,"``order`` can be a string containing the characters t,x,y,z, or * ." + ,,"`order` can be a string containing the characters t,x,y,z, or * ." ,,"If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." - "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." - "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." - "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." - "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." - "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." - "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." - "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found." - ,, "String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" + "List", "`getAxisListIndex(axes=None, omit=None, order=None)`", "Return a list of indices of axis objects. Arguments are as for getAxisList." + "List", "`getDomain()`", "Get the domain. Each element of the list is itself a tuple of the form `(axis,start,length,tru e_length)` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* `getAxisList`." + "Horizontal-Grid", "`getGrid()`", "Return the associated grid, or `None` if the variable is not gridded." + "Axis", "`getLatitude()`", "Get the latitude axis, or `None` if not found." + "Axis", "`getLevel()`", "Get the vertical level axis, or `None` if not found." + "Axis", "`getLongitude()`", "Get the longitude axis, or `None` if not found." + "Various", "`getMissing()`", "Get the missing data value, or `None` if not found." + ,, "String `getOrder()` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" ,, "* 't': time" ,, "* 'z': vertical level" ,, "* 'y': latitude" @@ -1314,45 +1314,45 @@ Table 2.35 Variable Methods ,, "**Example:**" ,, "A variable with ordering "tzyx" is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." ,, "**Note:** The order string is of the form required for the order argument of a regridder function." - "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." - ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." + "List", "`getPaths(*intervals)`", "Get the file paths associated with the index region specified by intervals." + ,,"`intervals` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no `argument(s)` are present, all file paths associated with the variable are returned." ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." ,, " **Note:** This function is not defined for transient variables." - "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." - "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." - ,,"**Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method="log", missin=None, order=None)``", Return the variable el, method="log", missin regridded to a new set g=None, order=None of pressure levels)`` newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." - ,, "``newLevel`` is an axis of the result pressure levels." - ,, "``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." - ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" - ,, "``order`` is an order string such as "tzyx" or "zyx". The default is ``var.getOrder()``" - ,, "See also: ``regrid``, ``crossSectionRegrid``." - ,, "Integer ``rank()`` The number of dimensions of the variable." - ,, "Transient :: Return the variable regridded to the regrid (togrid, miss horizontal grid togrid. ing=None, order=None, Va riable mask=None) ``missing`` is a Float specifying the missing data value. The default is 1.0e20." - ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string "tzyx" indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." - ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." - ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." - "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." - "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." - "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." + "Axis", "`getTime()`", "Get the time axis, or `None` if not found." + "Integer", "`len(var)`", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." + ,,"**Note:** `size()` returns the total number of elements." + "Transient Variable", "`pressureRegrid (newLevel, method="log", missin=None, order=None)`", Return the variable el, method="log", missin regridded to a new set g=None, order=None of pressure levels)` newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." + ,, "`newLevel` is an axis of the result pressure levels." + ,, "`method` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." + ,, "`missing` is a missing data value. The default is `var.getMissing()`" + ,, "`order` is an order string such as "tzyx" or "zyx". The default is `var.getOrder()`" + ,, "See also: `regrid`, `crossSectionRegrid`." + ,, "Integer `rank()` The number of dimensions of the variable." + ,, "Transient :: Return the variable regridded to the regrid (togrid, miss horizontal grid togrid. ing=None, order=None, Va riable mask=None) `missing` is a Float specifying the missing data value. The default is 1.0e20." + ,, "`order` is a string indicating the order of dimensions of the array. It has the form returned from `variable.getOrder()`. For example, the string "tzyx" indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." + ,, "`mask` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." + ,, "See also: `crossSectionRegrid`, `pressureRegrid`." + "`None`", "`setAxis(n, axis)`", "Set the n-th axis (0-origin index) of to a copy of axis." + "`None`", "`setAxisList(axislist)`", "Set all axes of the variable. axislist is a list of axis objects." + "`None`", "`setMissing(value)`", "Set the missing value. Integer `size()` Number of elements of the variable." "Variable", "subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)", Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37 on page 102. Also see ``axis.mapIntervalExt``." - ,," The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." - ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." - ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(*specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." - ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" - ,,"* a single integer n, meaning ``slice(n, n+1)``" + ,,"`region` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37 on page 102. Also see `axis.mapIntervalExt`." + ,," The optional keyword arguments `time`, `level`, `latitude`, and `longitude` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." + ,,"The optional keyword argument `squeeze` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." + ,,"The optional keyword argument `raw` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." + "Variable", "`subSlice(*specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)`", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." + ,,"`specs` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" + ,,"* a single integer n, meaning `slice(n, n+1)`" ,,"* an instance of the slice class" ,,"* a tuple, which will be used as arguments to create a slice" ,,"* ':', which means a slice covering that entire dimension" ,,"* Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments" - ,,"* a Python slice object, of the form ``slice(i,j,k)``" + ,,"* a Python slice object, of the form `slice(i,j,k)`" ,,"If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read." ,,"The keyword arguments are defined as in subRegion." ,,"There must be no conflict between the positional arguments and the keywords." - ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." - ,,"String ``typecode()`` The Numpy datatype identifier." + ,,"In `(a)-(c)` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." + ,,"String `typecode()` The Numpy datatype identifier." Example Get a region of data. ***************************** @@ -1386,15 +1386,15 @@ Table 2.36 Variable Slice Operators :header: "Operator", "Description" :widths: 30, 80 - "``[i]``", "The ith element, zero-origin indexing." - "``[i:j]``", "The ith element through, but not including, element j" - "``[i:]``", "The ith element through the end" - "``[:j]``", "The beginning element through, but not including, element j" - "``[:]``", "The entire array" - "``[i:j:k]``", "Every kth element" - "``[i:j, m:n]``", "Multidimensional slice" - "``[i, ..., m]``", "(Ellipsis) All dimensions between those specified." - "``[-1]``", "Negative indices ‘wrap around’. -1 is the last element" + "`[i]`", "The ith element, zero-origin indexing." + "`[i:j]`", "The ith element through, but not including, element j" + "`[i:]`", "The ith element through the end" + "`[:j]`", "The beginning element through, but not including, element j" + "`[:]`", "The entire array" + "`[i:j:k]`", "Every kth element" + "`[i:j, m:n]`", "Multidimensional slice" + "`[i, ..., m]`", "(Ellipsis) All dimensions between those specified." + "`[-1]`", "Negative indices ‘wrap around’. -1 is the last element" @@ -1403,9 +1403,9 @@ Table 2.36 Variable Slice Operators :widths: 30, 30, 80 - "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "`180.0`" + "`x`", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "180.0`" ,,"`cdtime.reltime(48,'hour s since 1980-1')`" - ,,"``'1980-1-3'``" + ,,"`'1980-1-3'`" "`(x,y)`", "indices i such that x ≤ axis[i] ≤ y", "`(-180,180)`" "`(x,y,'co')`", "`x ≤ axis[i] < y`. The third item is defined as in mapInterval.", "`(-90,90,'cc')`" "`(x,y,'co',cycle)`", "`x ≤ axis[i]< y`, with wraparound", "`( 180, 180, 'co', 360.0)`" @@ -1483,25 +1483,25 @@ Table 2.38 Selector keywords +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ | Keyword | Description | Value | +=================+======================================================================+============================================================================+ -| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | +| `axisid` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``grid`` | Regrid the result to the grid. | Grid object | +| `grid` | Regrid the result to the grid. | Grid object | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | +| `latitude` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | +| `level` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | +| `longitude` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | +| `order` | Reorder the result. | Order string, e.g., “tzyx” | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``raw`` | Return a masked array (MV2.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | +| `raw` | Return a masked array (MV2.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | +| `required` | Require that the axis IDs be present. | List of axis identifiers. | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | +| `squeeze` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | +| `time` | Restrict time values to a value or range. | See Table 2.37 on page 10 | +-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ Another form of selector components is the positional form, where the @@ -1719,20 +1719,20 @@ results are written to a netCDF file. For brevity, the functions **Notes:** -#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements +#. Two modules are imported, `cdms`, and `MV`. `MV` implements arithmetic functions. -#. ``taObj`` is a file (persistent) variable. At this point, no data has +#. `taObj` is a file (persistent) variable. At this point, no data has actually been read. This happens when the file variable is sliced, or when the subRegion function is called. levs is an axis. #. Calling the file like a function reads data for the given variable and time range. Note that month1 and month2 are time strings. -#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are +#. In contrast to `taObj`, the variables `cc`, `b`, and `v` are transient variables, not associated with a file. The assigned names are used when the variables are written. #. Another way to read data is to call the variable as a function. The squeeze option removes singleton axes, in this case the level axis. #. Write the data. Axis information is written automatically. -#. This is the main routine of the script. ``pathTa`` and ``pathTas`` +#. This is the main routine of the script. `pathTa` and `pathTas` pathnames. Data is processed from January 1980 through December 1981. From 7bc7d13d760366706040ce2222e014a8b13d233b Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Feb 2018 16:39:09 -0800 Subject: [PATCH 045/239] finish chapter 2 --- docs/source/manual/cdms_2.rst | 272 ++++++++++------------------------ docs/source/manual/cdms_4.rst | 78 ++++------ 2 files changed, 106 insertions(+), 244 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 80329b1f..6849697f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -596,9 +596,9 @@ To access a database: :header: "Constructor", "Description" :widths: 30, 80 - "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." - ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." - ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." + ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." + ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" ------------ @@ -756,7 +756,7 @@ Table 2.19 SearchResult Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag="dataset"):``" + "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." "SearchResult", " ``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." @@ -939,7 +939,7 @@ Table 2.25 Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See "Selectors" on page 103." + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors' on page 103." ,, "**Example:** The following reads data for variable 'prc', year 1980:" ,, " * f = cdms.open('test. xml')" ,, " * x = f('prc', time=('1980-1','1981-1'))" @@ -951,10 +951,10 @@ Table 2.25 Dataset Methods ,, "**Example:**" ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type="generic", mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." + "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." ,,"``lat`` is a latitude axis in the dataset." ,,"``lon`` is a longitude axis in the dataset." - ,,"``order`` is a string with value "yx" (the first grid dimension is latitude) or "xy" (the first grid dimension is longitude)." + ,,"``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." @@ -965,7 +965,7 @@ Table 2.25 Dataset Methods "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." ,,"``id`` is the string variable identifier." "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-or Generic-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." - ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``"source"`` or ``"destination"``." + ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``." ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1034,15 +1034,17 @@ Table 2.26 Variable Constructors in module MV :header: "Constructor", "Description" :widths: 30, 80 - "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. *Synonym:* ``arange``" - "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked\_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." + "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. **Synonym:** ``arange``" + "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." "``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." - "``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) < atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked\_object instead." + "``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) > atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked_object instead." "``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." "``reshape(a, newshape, axes=none, attributes=none, id=none)``", "copy of a with a new shape." - "``resize(a, new_shape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size". + "``resize(a, newshape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size." "``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "an array of all zeros of the given length or shape" + + The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. @@ -1055,7 +1057,7 @@ Table 2.27 MV functions "``argsort(x, axis=-1, fill_value=None)``", "Return a Numpy array of indices for sorting along a given axis." "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function." - "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." | + "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." "``choose(condition, t)``", "Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked." "``concatenate(arrays, axis=0, axisid=None, axisattributes=None)``", "Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array." "``count(a, axis=None)``", "Count of the non-masked elements in ``a``, or along a certain axis." @@ -1149,7 +1151,7 @@ Table 2.31 HorizontalGrid Methods ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." - ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids` `)." + ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``)." ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", " Get the latitude axis of this grid." @@ -1180,10 +1182,10 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", Get the grid ordering, either "yx" if latitude is the first axis, or "xy" if longitude is the first axis. String ``getType()`` Get the grid type, either "gaussian", "uniform", "equalarea", or "generic". (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." ,,"The latitude weights are defined as:" ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" - ,," The longitude weights are defined as: + ,," The longitude weights are defined as:" ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" ,,"**Example:**" @@ -1192,8 +1194,8 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods ,,"* latwts, lonwts = gri d.getWeights()" ,,"* weights = MV.outerproduct(latwts, lonwts)" ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." - ,,"" - "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of "gaussian", "uniform", "equalarea", or "generic"." + ,," " + "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." ,,"**Example:**" ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." @@ -1252,10 +1254,9 @@ Table 2.34 Variable Constructors :widths: 30, 80 "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." - "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)", "Create a Variable in a CdmsFile." - ,,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." - - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None) ``", " Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer n." + "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." + ,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", " Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1263,24 +1264,22 @@ Table 2.35 Variable Methods .. csv-table:: Variable Methods :header: "Type", "Method", "Definition" - :widths: 30, 30, 80 + :widths: 30, 30, 180 - "Variable", "``tvar = var[ i:j, m:n]``","Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See "Selectors"." + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." - ,,"Transient Variable :: Return a lat/level vertical cross-section" - ,,"crossSectionRegrid(n regridded to a new set ewLevel, newLatitude, me of latitudes newLatitude thod="log", missing=None and levels newLevel. The , order=None) variable should be a function of latitude, level, and (optionally) time." - ,,"``newLevel`` is an axis of the result pressure levels." - ,,"``newLatitude`` is an axis of the result latitudes." - ,,"``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." - ,,"``missing`` is a missing data value. The default is ``var.getMissing()``" - ,,"``order`` is an order string such as "tzy" or "zy". The default is ``var.getOrder()``." + "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time." + ,,"* ``newLevel`` is an axis of the result pressure levels." + ,,"* ``newLatitude`` is an axis of the result latitudes." + ,,"* ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." + ,,"* ``missing`` is a missing data value. The default is ``var.getMissing()``" + ,,"* ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``." ,,"*See also:* ``regrid``, ``pressureRegrid``." - ,,"" "Axis", "``getAxis(n)``", "Get the n-th axis." ,,"``n`` is an integer." "List", "``getAxisIds()``", "Get a list of axis identifiers." @@ -1310,37 +1309,37 @@ Table 2.35 Variable Methods ,, "* 'y': latitude" ,, "* 'x': longitude" ,, "* '-': the axis is not spatio-temporal." - ,, "" ,, "**Example:**" - ,, "A variable with ordering "tzyx" is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." + ,, "A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." ,, "**Note:** The order string is of the form required for the order argument of a regridder function." - "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." - ,, " **Note:** This function is not defined for transient variables." + ,, "**Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." + "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." ,,"**Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method="log", missin=None, order=None)``", Return the variable el, method="log", missin regridded to a new set g=None, order=None of pressure levels)`` newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." ,, "``newLevel`` is an axis of the result pressure levels." - ,, "``method`` is optional, either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation." + ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" - ,, "``order`` is an order string such as "tzyx" or "zyx". The default is ``var.getOrder()``" + ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" ,, "See also: ``regrid``, ``crossSectionRegrid``." - ,, "Integer ``rank()`` The number of dimensions of the variable." - ,, "Transient :: Return the variable regridded to the regrid (togrid, miss horizontal grid togrid. ing=None, order=None, Va riable mask=None) ``missing`` is a Float specifying the missing data value. The default is 1.0e20." - ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string "tzyx" indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." + "Integer", "``rank()``", "The number of dimensions of the variable." + "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid." + ,, "``missing`` is a Float specifying the missing data value. The default is 1.0e20." + ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." - "Variable", "subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)", Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." + "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37 on page 102. Also see ``axis.mapIntervalExt``." - ,," The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." + ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(*specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." + "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" ,,"* a single integer n, meaning ``slice(n, n+1)``" ,,"* an instance of the slice class" @@ -1400,27 +1399,21 @@ Table 2.36 Variable Slice Operators Table 2.37 Index and Coordinate Intervals -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| Interval Definition | Example Interval Definition | Example | -+========================+===========================================================================================================================================================================================================================================================================================================+=======================================================+ -| ``x`` | single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. | ``180.0`` | -| | | ``cdtime.reltime(48,"hour s since 1980-1")`` | -| | | ``'1980-1-3'`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y)`` | indices i such that x ≤ axis[i] ≤ y | ``(-180,180)`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co')`` | ``x ≤ axis[i] < y``. The third item is defined as in mapInterval. | ``(-90,90,'cc')`` | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``(x,y,'co',cycle)`` | ``x ≤ axis[i]< y``, with wraparound | ``( 180, 180, 'co', 360.0)`` | -| | **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true. | | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``slice(i,j,k)`` | slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative. | ``slice(1,10)`` | -| | | ``slice(,,-1)`` reverses the direction of the axis. | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``':'`` | all axis values of one dimension |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ -| ``Ellipsis`` | all values of all intermediate axes |   | -+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------+ +.. csv-table:: Index and Coordinate Intervals + :header: "Interval Definition", "Example Interval Definition", "Example" + :widths: 30, 80, 80 + + "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0``" + ,,"``cdtime.reltime(48,'hour s since 1980-1')``" + ,,"``'1980-1-3'``" + "``(x,y)``", "indices i such that x ≤ axis[i] ≤ y", "``(-180,180)``" + "``(x,y,'co')``", "``x ≤ axis[i] < y``. The third item is defined as in mapInterval.", "``(-90,90,'cc')``" + "``(x,y,'co',cycle)``", "``x ≤ axis[i]< y``, with wraparound", "``( 180, 180, 'co', 360.0)``" + "","**Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true.", + "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)``" + ,,"``slice(,,-1)`` reverses the direction of the axis." + "``':'``", "all axis values of one dimension", + "``Ellipsis``", "all values of all intermediate axes", @@ -1429,17 +1422,10 @@ Table 2.37 Index and Coordinate Intervals A selector is a specification of a region of data to be selected from a variable. For example, the statement -.. raw:: html - -
- :: x = v(time='1979-1-1', level=(1000.0,100.0)) -.. raw:: html - -
means ‘select the values of variable v for time ‘1979-1-1’ and levels 1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are @@ -1447,31 +1433,18 @@ generally used to represent regions of space and time. The form for using a selector is -.. raw:: html - -
:: result = v(s) -.. raw:: html - -
where v is a variable and s is the selector. An equivalent form is -.. raw:: html - -
- :: result = f('varid', s) -.. raw:: html - -
where f is a file or dataset, and ‘varid’ is the string ID of a variable. @@ -1479,33 +1452,21 @@ variable. A selector consists of a list of selector components. For example, the selector -.. raw:: html - -
:: time='1979-1-1', level=(1000.0,100.0) -.. raw:: html - -
has two components: time=’1979-1-1’, and level=(1000.0,100.0). This illustrates that selector components can be defined with keywords, using the form: -.. raw:: html - -
:: keyword=value -.. raw:: html - -
Note that for the keywords time, level, latitude, and longitude, the selector can be used with any variable. If the corresponding axis is not @@ -1520,47 +1481,31 @@ to the axis order of a variable. For example: -Table 2.38 Selector keywords - -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| Keyword | Description | Value | -+=================+======================================================================+============================================================================+ -| ``axisid`` | Restrict the axis with ID axisid to a value or range of values. | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``grid`` | Regrid the result to the grid. | Grid object | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``latitude`` | Restrict latitude values to a value or range. Short form: lat | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``level`` | Restrict vertical levels to a value or range. Short form: lev | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``longitude`` | Restrict longitude values to a value or range. Short form: lon | See Table 2.37 on page 102 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``order`` | Reorder the result. | Order string, e.g., “tzyx” | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``raw`` | Return a masked array (MV2.array) rather than a transient variable. | 0: return a transient variable (default); =1: return a masked array. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``required`` | Require that the axis IDs be present. | List of axis identifiers. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``squeeze`` | Remove singleton dimensions from the result. | 0: leave singleton dimensions (default); 1: remove singleton dimensions. | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ -| ``time`` | Restrict time values to a value or range. | See Table 2.37 on page 10 | -+-----------------+----------------------------------------------------------------------+----------------------------------------------------------------------------+ + +.. csv-table:: Selector keywords + :header: "Keyword", "Description", "Value" + :widths: 30, 80, 80 + + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", " See Table 2.37 on page 102" + "``grid``", "Regrid the result to the grid.", " Grid object" + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", " See Table 2.37 on page 102" + "``level``", "Restrict vertical levels to a value or range. Short form: lev", " See Table 2.37 on page 102" + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", " See Table 2.37 on page 102" + "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" + "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." + "``required``", "Require that the axis IDs be present.", " List of axis identifiers." + "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." + "``time``", "Restrict time values to a value or range.", " See Table 2.37 on page 10" Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example: -.. raw:: html - -
:: x9 = hus(('1979-1-1','1979-2-1'),1000.0) -.. raw:: html - -
reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the @@ -1573,9 +1518,6 @@ be defined and reused, independent of a particular variable. Selectors are constructed using the cdms.selectors.Selector class. The constructor takes an argument list of selector components. For example: -.. raw:: html - -
:: @@ -1584,64 +1526,40 @@ takes an argument list of selector components. For example: x1 = v1(sel) x2 = v2(sel) -.. raw:: html - -
For convenience CDMS provides several predefined selectors, which can be used directly or can be combined into more complex selectors. The selectors time, level, latitude, longitude, and required are equivalent to their keyword counterparts. For example: -.. raw:: html - -
:: from cdms import time, level x = hus(time('1979-1-1','1979-2-1'), level(1000.)) -.. raw:: html - -
and -.. raw:: html - -
:: x = hus(time=('1979-1-1','1979-2-1'), level=1000.) -.. raw:: html - -
are equivalent. Additionally, the predefined selectors ``latitudeslice``, ``longitudeslice``, ``levelslice``, and ``timeslice`` take arguments ``(startindex, stopindex[, stride])``: -.. raw:: html - -
:: from cdms import timeslice, levelslice x = v(timeslice(0,2), levelslice(16,17)) -.. raw:: html - -
Finally, a collection of selectors is defined in module cdutil.region: -.. raw:: html - -
:: @@ -1652,17 +1570,10 @@ Finally, a collection of selectors is defined in module cdutil.region: NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) -.. raw:: html - -
Selectors can be combined using the & operator, or by refining them in the call: -.. raw:: html - -
- :: from cdms.selectors import Selector @@ -1672,10 +1583,6 @@ the call: x1 = hus(sel3) x2 = hus(sel2, level=1000.0) -.. raw:: html - -
- 2.11.2 Selector examples @@ -1688,10 +1595,6 @@ monthly starting at 1979-1-1. There are 17 levels, the last level being select the first two times and the last level. The last two examples remove the singleton level dimension from the result array. -.. raw:: html - -
- :: import cdms @@ -1739,11 +1642,6 @@ remove the singleton level dimension from the result array. f.close() -.. raw:: html - -
- - Examples ^^^^^^^^ @@ -1765,10 +1663,6 @@ three quantities are calculated: slope, variance, and correlation. The results are written to a netCDF file. For brevity, the functions ``corrCoefSlope`` and ``removeSeasonalCycle`` are omitted. -.. raw:: html - -
- :: 1. import cdms @@ -1826,9 +1720,6 @@ results are written to a netCDF file. For brevity, the functions # Process Jan80 through Dec81 ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') -.. raw:: html - -
**Notes:** @@ -1858,9 +1749,6 @@ calculated, for all times in a dataset. The name of the dataset and variable are entered, then the variance is calculated and plotted via the vcs module. -.. raw:: html - -
:: @@ -1941,16 +1829,9 @@ the vcs module. pause() w.clear() -.. raw:: html - -
The result of running this script is as follows: -.. raw:: html - -
- :: % calcVar.py @@ -1974,9 +1855,6 @@ The result of running this script is as follows: -.. raw:: html - -
**Notes:** diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index fe880a17..13d5a2cc 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -148,14 +148,11 @@ conservative interpolator. In this example: -- The input grid is defined in remap\_grid\_T42.nc. -- The output grid is defined in remap\_grid\_POP43.nc. -- The input data is variable src\_array in file sampleT42Grid.nc. -- The file scrip\_in has contents: +- The input grid is defined in remap_grid_T42.nc. +- The output grid is defined in remap_grid_POP43.nc. +- The input data is variable src_array in file sampleT42Grid.nc. +- The file scrip_in has contents: -.. raw:: html - -
:: @@ -176,9 +173,6 @@ In this example: luse_grid1_area = .false. luse_grid2_area = .false. -.. raw:: html - -
``num_maps`` specifies the number of mappings generated, either 1 or 2. For a single mapping, ``grid1_file`` and ``grid2_file`` are the source @@ -190,9 +184,6 @@ in the SCRIP documentation. Once the grids and input file are defined, run the scrip executable to generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ -.. raw:: html - -
:: @@ -206,9 +197,6 @@ generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ grid2 sweep Total number of links = 63112 -.. raw:: html - -
Next, run UV-CDAT and create the regridder: @@ -311,14 +299,14 @@ makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. -Table 4.1 CDMS Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CDMS Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: REgridder Constructure :header: "Constructor", "Description" :widths: 50, 90 - "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `Table 4.3 <#Table_4.3>`__ on page 131 describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -326,8 +314,8 @@ SCRIP Regridder SCRIP regridder functions are created with the ``regrid.readRegridder`` function: -Table 4.2 SCRIP Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +SCRIP Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" @@ -355,8 +343,8 @@ convexity, and ‘repaired’ if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees. -CDMS regridder functions -^^^^^^^^^^^^^^^^^^^^^^^^ +_`CDMS regridder functions` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ A CDMS regridder function is an instance of the CDMS ``Regridder`` class. The function is associated with rectangular input and output @@ -408,8 +396,8 @@ data value, or 1.0e20 if undefined. The result array or transient variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values -Table 4.3 CDMS Regridder function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CDMS Regridder function +~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Function", "Description" @@ -468,28 +456,24 @@ following fields: In addition, a conservative regridder has the associated grid cell areas for source and target grids. -Table 4.4 SCRIP Regridder functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Return Type | Method | Description | -+===============================+============================================================================================+================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| Array or Transient-Variable | [conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)`` | Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Array or Transient-Variable | [bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)`` |

Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.

\ ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.

\ ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.

gradientLon: df/dj. Same shape as ``array``.

\ ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.

| -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numpy array | ``getDestinationArea()`` [conservative regridders only] | Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numpy array | ``getDestinationFraction()`` | Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| CurveGrid or Generic-Grid | ``getInputGrid()`` | Return the input grid, or None if no input grid is associated with the regridder. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| CurveGrid or Generic-Grid | ``getOutputGrid()`` | Return the output grid. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numpy array | ``getSourceArea()`` [conservative regridders only] | Return the area of the source (input) grid cell. The array is 1- D, with length equal to the number of cells in the input grid. | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Numpy array | ``getSourceFraction()`` | Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid | -+-------------------------------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +SCRIP Regridder functions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. csv-table:: + :header: "Return Type", "Method", "Description" + :widths: 40, 40, 80 + + "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." + "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable." + ,,"``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." + ,,"``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``." + ,,"``gradientLon``: df/dj. Same shape as ``array``." + ,,"``gradientLatLon``: d(df)/(di)(dj). Same shape as array." + "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid." + "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid." + "CurveGrid or Generic-Grid", "``getInputGrid()``", "Return the input grid, or None if no input grid is associated with the regridder." + "CurveGrid or Generic-Grid", "``getOutputGrid()``", "Return the output grid." + "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid" 4.4 Examples ^^^^^^^^^^^^ From 322803c85e8f8f80513b110e836a3750c5d2da63 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Feb 2018 16:52:29 -0800 Subject: [PATCH 046/239] fix litteral error --- docs/source/manual/cdms_appendix.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index d56ad2c4..c311f0db 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -193,13 +193,13 @@ Table C.1 Slab Methods ^^^^^^^^^^^^^^^^^^^^^^ -.. csv-table:: Slab_Methods - :header: "Type","Method","Definition" +.. csv-table:: Slab Methods + :header: "Type", "Method", "Definition" :widths: 20,50,80 "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." - "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device ``. " + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." From c4563eee0942c3f549cd9897c444b466f554eda9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Feb 2018 18:44:07 -0800 Subject: [PATCH 047/239] unlink .dodsrc for cdscan --- tests/test_cdscan.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index e5730c25..e53bdcba 100755 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -52,6 +52,10 @@ def testopenFile(self): ''' retrieve value from cdscan ''' + try: + os.unlink(os.environ['HOME']+'/.dodsrc') + except: + pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() os.chdir(pth) From 9ae560a522d556f691b676cc7e2ce2f2ab8b411d Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 27 Feb 2018 14:45:44 -0800 Subject: [PATCH 048/239] First changes from Tanya --- docs/source/manual/cdms_1.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index cebb795b..b5a327a7 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -21,7 +21,7 @@ Variables The basic unit of computation in CDMS is the variable. A variable is essentially a multidimensional data array, augmented with a domain, a set of attributes, and optionally a spatial and/or temporal coordinate -system (see `Coordinate Axes <#1.4>`__). As a data array, a variable can +system (see `Coordinate Axes <#coordinate-axes>`__). As a data array, a variable can be sliced to obtain a portion of the data, and can be used in arithmetic computations. For example, if ``u`` and ``v`` are variables representing the eastward and northward components of wind speed, respectively, and @@ -200,7 +200,7 @@ a domain is spatiotemporal: system. - The latitude and/or longitude coordinate axes associated with a variable need not be elements of the domain. In particular this will - be true if the variable is defined on a non-rectangular grid (see `Grids <#1.9>`__). + be true if the variable is defined on a non-rectangular grid (see `Grids <#grids>`__). As previously noted, a spatial and/or temporal coordinate system may be associated with a variable. The methods getLatitude, getLongitude, From f93e64f1316edcb787ccea00a398c86319c8e9c5 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 1 Mar 2018 11:47:14 -0800 Subject: [PATCH 049/239] some change in chapter 1 and 2 --- docs/source/manual/cdms_1.rst | 1 + docs/source/manual/cdms_2.rst | 55 ++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index b5a327a7..cde9f460 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -28,6 +28,7 @@ the eastward and northward components of wind speed, respectively, and both variables are functions of time, latitude, and longitude, then the velocity for time 0 (first index) can be calculated as + .. highlight:: python .. doctest:: diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 6849697f..dea7182b 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1,8 +1,9 @@ -CDMS Python Application Programming Interface ---------------------------------------------- +=============================================== + CDMS Python Application Programming Interface +=============================================== Overview -^^^^^^^^ +======== .. highlight:: python :linenothreshold: 3 @@ -38,7 +39,8 @@ an application. This chapter documents the cdms, cdtime, and regrid modules. The chapter sections correspond to the CDMS classes. Each section -contains tables base. If no parent, the datapath is absolute.describing +contains table +s base. If no parent, the datapath is absolute.describing the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: @@ -59,7 +61,7 @@ return an instance of a CDMS class, or one of the Python types: "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``" A first example -^^^^^^^^^^^^^^^ +=============== The following Python script reads January and July monthly temperature data from an input dataset, averages over time, and writes the results @@ -107,7 +109,8 @@ latitude, longitude). "18", "Close the output file." -2.3 cdms module +Cdms module +=========== The cdms module is the Python interface to CDMS. The objects and methods in this chapter are made accessible with the command: @@ -124,7 +127,10 @@ Rather, they are called as module functions, e.g., file = cdms2.open('sample.nc') -.. csv-table:: cdms module funtions +Table Cdms module functions +--------------------------- + +.. csv-table:: Cdms module functions :header: "Type", "Definition" :widths: 10, 80 @@ -185,7 +191,7 @@ Rather, they are called as module functions, e.g., , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See Table 2.24" + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. (See `Open Modes <#id25>`__)" , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" @@ -221,7 +227,7 @@ Table 2.3 Class Tags CdmsObj -^^^^^^^ +======= A CdmsObj is the base class for all CDMS database objects. At the application level, CdmsObj objects are never created and used directly. @@ -263,7 +269,7 @@ Table 2.5 Getting and setting attributes CoordinateAxis -^^^^^^^^^^^^^^ +============== A CoordinateAxis is a variable that represents coordinate information. It may be contained in a file or dataset, or may be transient @@ -318,7 +324,10 @@ Axis objects. , "* See Table 2.2 on page 18." -.. csv-table:: CoordinateAxis Methods +CoordinateAxis Methods +---------------------- + +.. csv-table:: Table: CoordinateAxis Methods :header: "Type", "Method", "Definition" :widths: 20, 20, 80 @@ -419,7 +428,7 @@ equivalent to the two contiguous index intervals ``2 <= n < 0`` and CdmsFile -^^^^^^^^ +======== A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` interface. netCDF files are accessible in read-write mode. All other formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. @@ -504,7 +513,7 @@ Cdms-Files. See “cu Module” on page 180. Database -^^^^^^^^ +======== A Database is a collection of datasets and other CDMS objects. It consists of a hierarchical collection of objects, with the database being at the root, or top of the hierarchy. A database is used to: @@ -888,7 +897,7 @@ This defaults to the database defined in environment variable Dataset -^^^^^^^ +======= A Dataset is a virtual file. It consists of a metafile, in CDML/XML representation, and one or more data files. @@ -918,7 +927,7 @@ Table 2.23 Dataset Constructors :header: "Constructor", "Description" :widths: 50, 80 - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table 2.24 on page 70. ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table `Open Modes <#id25>`__ . ``openDataset`` is a synonym for ``open``" Table 2.24 Open Modes @@ -971,7 +980,7 @@ Table 2.25 Dataset Methods MV module -^^^^^^^^^ +========= The fundamental CDMS data object is the variable. A variable is comprised of: @@ -1085,7 +1094,7 @@ Table 2.27 MV functions HorizontalGrid -^^^^^^^^^^^^^^ +============== A HorizontalGrid represents a latitude-longitude coordinate system. In addition, it optionally describes how lat-lon space is partitioned into @@ -1207,7 +1216,7 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods Variable -^^^^^^^^ +======== A Variable is a multidimensional data object, consisting of: @@ -1249,7 +1258,7 @@ Table 2.33 Variable Internal Attributes Table 2.34 Variable Constructors -.. csv-table:: Variable Constructgors +.. csv-table:: Variable Constructors :header: "Constructor", "Description" :widths: 30, 80 @@ -1354,7 +1363,7 @@ Table 2.35 Variable Methods ,,"String ``typecode()`` The Numpy datatype identifier." Example Get a region of data. -***************************** +----------------------------- Variable ta is a function of (time, latitude, longitude). Read data corresponding to all times, latitudes -45.0 up to but not @@ -1644,11 +1653,11 @@ remove the singleton level dimension from the result array. Examples -^^^^^^^^ +======== Example 1 -********* +--------- In this example, two datasets are opened, containing surface air temperature (‘tas’) and upper-air temperature (‘ta’) respectively. @@ -1742,7 +1751,7 @@ results are written to a netCDF file. For brevity, the functions Example 2 -********* +--------- In the next example, the pointwise variance of a variable over time is calculated, for all times in a dataset. The name of the dataset and From 42d56eedd668ea612050c1ac1ea80d25f9557eef Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 1 Mar 2018 15:22:46 -0800 Subject: [PATCH 050/239] some changes in Chapter 2 --- docs/source/manual/cdms_2.rst | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index dea7182b..d4526b68 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -191,7 +191,7 @@ Table Cdms module functions , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. (See `Open Modes <#id25>`__)" + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode.(See `Open Modes <#id25>`__" , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" @@ -277,9 +277,9 @@ It may be contained in a file or dataset, or may be transient file, and referencing a file CoordinateAxis slice reads data from the file. Axis objects are also used to define the domain of a Variable. -CDMS defines several different types of CoordinateAxis objects. Table -2.9 on page 45 documents methods that are common to all CoordinateAxis -types. Table 2.10 on page 48 specifies methods that are unique to 1D +CDMS defines several different types of CoordinateAxis objects. See `MV module <#mv-module>`_ +documents methods that are common to all CoordinateAxis +types. See `HorizontalGrid <#horizontalgrid>`_ specifies methods that are unique to 1D Axis objects. @@ -309,25 +309,25 @@ Axis objects. :header: "Constructor", "Description" :widths: 20, 80 - "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See Table 2.2 on page 33." + "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" - , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlimited``" + , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited``" , "``cdms.createEqualAreaAxis(nlat)``" - , "* See Table 2.2 on page 33." + , "* See `A First Example`_." , "``cdms.createGaussianAxis(nlat)``" - , "* See Table 2.2 on page 18." + , "* See `A First Example`_." , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" - , "* See Table 2.2 on page 18." + , "* See `A First Example`_." , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" - , "* See Table 2.2 on page 18." + , "* See `A First Example`_ ." CoordinateAxis Methods ---------------------- -.. csv-table:: Table: CoordinateAxis Methods +.. csv-table:: CoordinateAxis Methods :header: "Type", "Method", "Definition" :widths: 20, 20, 80 @@ -455,7 +455,7 @@ Cdms-Files. See “cu Module” on page 180. :widths: 20, 80 "Constructor", "Description" - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in Table 2.24 on page 70." + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in "See `Open Modes`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." @@ -1136,7 +1136,7 @@ Table 2.30 RectGrid Constructors :header: "Constructor", "Description" :widths: 30, 80 - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See Table 2.2" + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset." "*See `A First Example`_)." "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See Table 2.2" @@ -1482,7 +1482,7 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in Table 2.37 on page 102. +ranges as defined in See `Index and Coordinate Intervals <#36>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds @@ -1495,16 +1495,16 @@ to the axis order of a variable. For example: :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", " See Table 2.37 on page 102" + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#36>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", " See Table 2.37 on page 102" - "``level``", "Restrict vertical levels to a value or range. Short form: lev", " See Table 2.37 on page 102" - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", " See Table 2.37 on page 102" + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#36>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#36>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#36>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", " See Table 2.37 on page 10" + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#36>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For From af15c81a0cc6de941937d6a3509b0feecfa1ff04 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 1 Mar 2018 15:51:59 -0800 Subject: [PATCH 051/239] fix tables --- docs/source/manual/cdms_2.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index d4526b68..a4ae2cfd 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -191,7 +191,7 @@ Table Cdms module functions , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode.(See `Open Modes <#id25>`__" + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. (See `Open Modes <#id25>`__" , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" @@ -455,7 +455,7 @@ Cdms-Files. See “cu Module” on page 180. :widths: 20, 80 "Constructor", "Description" - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in "See `Open Modes`_." + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in 'See `Open Modes <#id25>`_.'" "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." @@ -1136,7 +1136,7 @@ Table 2.30 RectGrid Constructors :header: "Constructor", "Description" :widths: 30, 80 - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset." "*See `A First Example`_)." + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. *See `A First Example`_)*'" "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See Table 2.2" From 69478bd1d65adb45c3fe6aa3c2abfa8fb560caa4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 5 Mar 2018 15:49:22 -0800 Subject: [PATCH 052/239] Some changes to Chapter 2 --- docs/source/manual/cdms_2.rst | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index a4ae2cfd..0bba1d3e 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -304,7 +304,6 @@ Axis objects. "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." - .. csv-table:: Axis Constructors :header: "Constructor", "Description" :widths: 20, 80 @@ -1130,21 +1129,29 @@ Table 2.29 HorizontalGrid Internal Attribute "Tuple", "``shape``", "The shape of the grid, a 2-tuple" +.. _RectGrid_Constructors: + + +sldjsalfa + +See :ref:`RectGrid_Constructors` + + Table 2.30 RectGrid Constructors .. csv-table:: RectGrid Constructors :header: "Constructor", "Description" :widths: 30, 80 - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. *See `A First Example`_)*'" + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See `A First Example`_" "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" - "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" - "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See Table 2.2" - "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See Table 2.2" - "``cdms.createGlobalMeanGrid(grid)``", "See Table 2.2." - "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "See Table 2.2" - "``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None)``", "See Table 2.2" - "``cdms.createZonalGrid(grid)``", " See Table 2.2" + "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See `Dataset Methods_<#id33>`_ + "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See `A First Example`_ " + "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See `A First Example`_" + "``cdms.createGlobalMeanGrid(grid)``", "See `A First Example`_" + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "See `A First Example`_" + "``cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None)``", "See `A First Example`_" + "``cdms.createZonalGrid(grid)``", "See `A First Example`_" Table 2.31 HorizontalGrid Methods From f542e150cce0531ba0a47513462406e421ec9628 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 6 Mar 2018 15:43:32 -0800 Subject: [PATCH 053/239] Some Changes to Chapter 2 --- docs/source/manual/cdms_2.rst | 39 +++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 0bba1d3e..b83bfae9 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -109,6 +109,9 @@ latitude, longitude). "18", "Close the output file." + + + Cdms module =========== @@ -126,6 +129,9 @@ Rather, they are called as module functions, e.g., .. doctest:: file = cdms2.open('sample.nc') +: + + Table Cdms module functions --------------------------- @@ -210,6 +216,9 @@ Table Cdms module functions , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." +:: + + Table 2.3 Class Tags @@ -268,6 +277,8 @@ Table 2.5 Getting and setting attributes , "Set an internal or external attribute value. If the attribute is external, it is written to the database." + + CoordinateAxis ============== @@ -330,7 +341,7 @@ CoordinateAxis Methods :header: "Type", "Method", "Definition" :widths: 20, 20, 80 - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 on page 51 for a description of slice operators." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." @@ -433,7 +444,7 @@ interface. netCDF files are accessible in read-write mode. All other formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. As of CDMS V3, the legacy cuDataset interface is also supported by -Cdms-Files. See “cu Module” on page 180. +Cdms-Files. See “cu Module”. @@ -463,7 +474,7 @@ Cdms-Files. See “cu Module” on page 180. :widths: 20, 20, 80 "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors' on page 103." + ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." ,, " **Example:** The following reads data for variable 'prc', year 1980:" ,, " * >>> f = cdms.open('test.nc')" ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" @@ -700,7 +711,7 @@ Formally, search filters are strings defined as follows: Attribute names are defined in the chapter on “Climate Data Markup -Language (CDML)” on page 149. In addition, some special attributes are +Language (CDML)”. In addition, some special attributes are defined for convenience: - ``category`` is either “experimental” or “observed” @@ -901,7 +912,7 @@ A Dataset is a virtual file. It consists of a metafile, in CDML/XML representation, and one or more data files. As of CDMS V3, the legacy cuDataset interface is supported by Datasets. -See “cu Module” on page 180. +See “cu Module". Table 2.22 Dataset Internal Attributes @@ -947,7 +958,7 @@ Table 2.25 Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors' on page 103." + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." ,, "**Example:** The following reads data for variable 'prc', year 1980:" ,, " * f = cdms.open('test. xml')" ,, " * x = f('prc', time=('1980-1','1981-1'))" @@ -1127,15 +1138,15 @@ Table 2.29 HorizontalGrid Internal Attribute "String", "``id``", "The grid identifier." "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." "Tuple", "``shape``", "The shape of the grid, a 2-tuple" - +:: .. _RectGrid_Constructors: - -sldjsalfa +:: See :ref:`RectGrid_Constructors` + Table 2.30 RectGrid Constructors @@ -1145,7 +1156,7 @@ Table 2.30 RectGrid Constructors "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See `A First Example`_" "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" - "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See `Dataset Methods_<#id33>`_ + "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See `A First Example`_ " "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See `A First Example`_" "``cdms.createGlobalMeanGrid(grid)``", "See `A First Example`_" @@ -1154,8 +1165,10 @@ Table 2.30 RectGrid Constructors "``cdms.createZonalGrid(grid)``", "See `A First Example`_" + Table 2.31 HorizontalGrid Methods + .. csv-table:: HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 @@ -1283,7 +1296,7 @@ Table 2.35 Variable Methods :widths: 30, 30, 180 "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" - "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21 on page 32. (Variables in CdmsFiles only)" + "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21. (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." @@ -1351,7 +1364,7 @@ Table 2.35 Variable Methods "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37 on page 102. Also see ``axis.mapIntervalExt``." + ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37. Also see ``axis.mapIntervalExt``." ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1525,7 +1538,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in Table 2.37 on page 102 are treated as positional. Such +form(s) listed in Table 2.37 are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. From 10b352374ff2727d88cc089cb8980d7240eda101 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 7 Mar 2018 14:54:37 -0800 Subject: [PATCH 054/239] Some changes made to Chapters 1, 2 and 4 --- docs/source/conf.py | 4 ++-- docs/source/manual/cdms_1.rst | 2 +- docs/source/manual/cdms_2.rst | 12 ++++++++++-- docs/source/manual/cdms_4.rst | 8 ++++---- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index a5ae037c..248c3b80 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -158,10 +158,10 @@ #html_theme = 'alabaster' #html_theme = 'sphinxdoc' #html_theme = 'nature' -#html_theme = 'agogo' +html_theme = 'agogo' #html_theme = 'pyramid' #html_theme = 'epub' -html_theme = 'haiku' +#html_theme = 'haiku' #html_theme = "sphinx_rtd_theme" #html_theme = 'classic' diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index cde9f460..0d2bb35d 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -133,7 +133,7 @@ system(s) of the variable(s). Often in climate applications an axis is a one-dimensional variable whose values are floating-point and strictly monotonic. In some cases an -axis can be multidimensional (see `Grids <#1.9>`__). If an axis is +axis can be multidimensional (see `Grids <#grids>`__). If an axis is associated with one of the canonical types latitude, longitude, level, or time, then the axis is called temporal . diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index b83bfae9..0f3aed6e 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -129,7 +129,6 @@ Rather, they are called as module functions, e.g., .. doctest:: file = cdms2.open('sample.nc') -: @@ -311,7 +310,7 @@ Axis objects. :widths: 20, 20, 80 "``Dictionary``", "``attributes``", "External attribute dictionary." - "``String``", "``id``", "CoordinateAxis identifer." + "``String``", "``id``", "CoordinateAxis identifier." "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." @@ -1139,10 +1138,19 @@ Table 2.29 HorizontalGrid Internal Attribute "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." "Tuple", "``shape``", "The shape of the grid, a 2-tuple" :: + + + + .. _RectGrid_Constructors: :: + + + + + See :ref:`RectGrid_Constructors` diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 13d5a2cc..e9f56784 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -475,11 +475,11 @@ SCRIP Regridder functions "CurveGrid or Generic-Grid", "``getOutputGrid()``", "Return the output grid." "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid" -4.4 Examples -^^^^^^^^^^^^ +Examples +^^^^^^^^ -4.4.1 CDMS regridder -~~~~~~~~~~~~~~~~~~~~ +CDMS regridder +~~~~~~~~~~~~~~ **Example:** From 33c90fd5ad8809e08c52a40893034d6fba643f7c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 7 Mar 2018 16:01:53 -0800 Subject: [PATCH 055/239] Some changes to Chapter 2 --- docs/source/manual/cdms_2.rst | 43 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 0f3aed6e..ebf81b3a 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -3,7 +3,7 @@ =============================================== Overview -======== +^^^^^^^^ .. highlight:: python :linenothreshold: 3 @@ -61,7 +61,7 @@ return an instance of a CDMS class, or one of the Python types: "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``" A first example -=============== +^^^^^^^^^^^^^^^ The following Python script reads January and July monthly temperature data from an input dataset, averages over time, and writes the results @@ -111,9 +111,8 @@ latitude, longitude). - Cdms module -=========== +^^^^^^^^^^^ The cdms module is the Python interface to CDMS. The objects and methods in this chapter are made accessible with the command: @@ -235,7 +234,7 @@ Table 2.3 Class Tags CdmsObj -======= +^^^^^^^ A CdmsObj is the base class for all CDMS database objects. At the application level, CdmsObj objects are never created and used directly. @@ -279,7 +278,7 @@ Table 2.5 Getting and setting attributes CoordinateAxis -============== +^^^^^^^^^^^^^^ A CoordinateAxis is a variable that represents coordinate information. It may be contained in a file or dataset, or may be transient @@ -437,7 +436,7 @@ equivalent to the two contiguous index intervals ``2 <= n < 0`` and CdmsFile -======== +^^^^^^^^ A ``CdmsFile`` is a physical file, accessible via the ``cdunif`` interface. netCDF files are accessible in read-write mode. All other formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. @@ -522,7 +521,7 @@ Cdms-Files. See “cu Module”. Database -======== +^^^^^^^^ A Database is a collection of datasets and other CDMS objects. It consists of a hierarchical collection of objects, with the database being at the root, or top of the hierarchy. A database is used to: @@ -551,7 +550,8 @@ The figure below illustrates several important points: Figure 1 -2.7.1 Overview +Overview +-------------- To access a database: @@ -660,7 +660,8 @@ To access a database: .. highlight:: python :linenothreshold: 0 -2.7.2 Searching a database +Searching a database +-------------------------- The ``searchFilter`` method is used to search a database. The result is called a search result, and consists of a sequence of result entries. @@ -808,7 +809,8 @@ Table 2.21 ResultEntry Methods ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." -2.7.3 Accessing data +Accessing data +-------------------- To access data via CDMS: @@ -826,7 +828,8 @@ In the next example, a portion of variable ‘ua’ is read from dataset data = ua[0,0] -2.7.4 Examples of database searches +Examples of database searches +----------------------------------- In the following examples, db is the database opened with @@ -906,7 +909,7 @@ This defaults to the database defined in environment variable Dataset -======= +^^^^^^^ A Dataset is a virtual file. It consists of a metafile, in CDML/XML representation, and one or more data files. @@ -989,7 +992,7 @@ Table 2.25 Dataset Methods MV module -========= +^^^^^^^^^ The fundamental CDMS data object is the variable. A variable is comprised of: @@ -1103,7 +1106,7 @@ Table 2.27 MV functions HorizontalGrid -============== +^^^^^^^^^^^^^^ A HorizontalGrid represents a latitude-longitude coordinate system. In addition, it optionally describes how lat-lon space is partitioned into @@ -1244,7 +1247,7 @@ Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods Variable -======== +^^^^^^^^ A Variable is a multidimensional data object, consisting of: @@ -1454,7 +1457,8 @@ Table 2.37 Index and Coordinate Intervals -2.11.1 Selectors +Selectors +---------------- A selector is a specification of a region of data to be selected from a variable. For example, the statement @@ -1622,7 +1626,8 @@ the call: -2.11.2 Selector examples +Selector examples +------------------------ CDMS provides a variety of ways to select or slice data. In the following examples, variable hus is contained in file sample.nc, and is @@ -1681,7 +1686,7 @@ remove the singleton level dimension from the result array. Examples -======== +^^^^^^^^ Example 1 From 368d88ddd1259547e807c5abb93f7263f9680b78 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 8 Mar 2018 15:23:18 -0800 Subject: [PATCH 056/239] Some Changes made to Chapter 2 --- docs/source/manual/cdms_2.rst | 147 ++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 61 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index ebf81b3a..ce178c60 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -195,7 +195,7 @@ Table Cdms module functions , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. (See `Open Modes <#id25>`__" + , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" @@ -214,13 +214,13 @@ Table Cdms module functions , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." -:: - +: -Table 2.3 Class Tags +Table Class Tags +-------------------- .. csv-table:: Class Tags :header: "Tag", "Class" :widths: 20, 20 @@ -263,8 +263,8 @@ external attributes are written, but not the internal attributes. "Dictionary", "attributes", "External attribute dictionary for this object." -Table 2.5 Getting and setting attributes - +Table Getting and setting attributes +------------------------------------ .. csv-table:: Getting and setting attributes :header: "Type", "Definition" :widths: 20, 80 @@ -286,12 +286,13 @@ It may be contained in a file or dataset, or may be transient file, and referencing a file CoordinateAxis slice reads data from the file. Axis objects are also used to define the domain of a Variable. -CDMS defines several different types of CoordinateAxis objects. See `MV module <#mv-module>`_ +CDMS defines several different types of CoordinateAxis objects. See `MV module <#id3>`_ documents methods that are common to all CoordinateAxis -types. See `HorizontalGrid <#horizontalgrid>`_ specifies methods that are unique to 1D +types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D Axis objects. - +Table CoordinateAxis Types +-------------------------- .. csv-table:: CoordinateAxis types :header: "Type", "Definition" @@ -302,7 +303,8 @@ Axis objects. "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." - +Table CoordinateAxis Internal Attributes +---------------------------------------- .. csv-table:: CoordinateAxis Internal Attributes :header: "Type", "Name", "Definition" @@ -313,6 +315,9 @@ Axis objects. "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." +Table Axis Constructors +----------------------- + .. csv-table:: Axis Constructors :header: "Constructor", "Description" :widths: 20, 80 @@ -332,14 +337,14 @@ Axis objects. , "* See `A First Example`_ ." -CoordinateAxis Methods ----------------------- +Table CoordinateAxis Methods +---------------------------- .. csv-table:: CoordinateAxis Methods :header: "Type", "Method", "Definition" :widths: 20, 20, 80 - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See Table 2.11 for a description of slice operators." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." @@ -445,6 +450,8 @@ As of CDMS V3, the legacy cuDataset interface is also supported by Cdms-Files. See “cu Module”. +Table CdmsFile Internal Attributes +---------------------------------- .. csv-table:: CdmsFile Internal Attributes :header: "Type", "Name", "Definition" @@ -456,16 +463,19 @@ Cdms-Files. See “cu Module”. "``String``", "``id``", "File pathname." "``Dictionary``", "``variables``", "Variables contained in the file." - +Table CdmsFile Constructors +--------------------------- .. csv-table:: CdmsFile Constructors :header: "Constructor", "Description" :widths: 20, 80 "Constructor", "Description" - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in 'See `Open Modes <#id25>`_.'" + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." +Table CdmsFile Methods +---------------------- .. csv-table:: CdmsFile Methods :header: "Type", "Method", "Definition" @@ -508,6 +518,9 @@ Cdms-Files. See “cu Module”. ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." +Table CDMS Datatypes +-------------------- + .. csv-table:: CDMS Datatypes :header: "CDMS Datatype", "Definition" :widths: 20, 30 @@ -597,6 +610,9 @@ To access a database: ``db.close()`` +Table Database Internal Attributes +---------------------------------- + .. csv-table:: Database Internal Attributes :header: "Type", "Name", "Summary" @@ -608,7 +624,9 @@ To access a database: "``String``", "``path``", "path name" "``String``", "``uri``", "Uniform Resource Identifier" ------------- + +Table Database Constructors +--------------------------- .. csv-table:: Database Constructors :header: "Constructor", "Description" @@ -618,7 +636,8 @@ To access a database: ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" ------------- +Table Database Methods +---------------------- .. csv-table:: Database Methods :header: "Type", "Method", "Definition" @@ -769,7 +788,8 @@ variables defined on a 94x192 grid: -Table 2.19 SearchResult Methods +Table SearchResult Methods +-------------------------- .. csv-table:: SearchResult Methods :header: "Type", "Method", "Definition" @@ -789,7 +809,8 @@ information defined for the associated CDMS object, which is retrieved with the ``getObject`` method. -Table 2.20 ResultEntry Attributes +Table ResultEntry Attributes +---------------------------- .. csv-table:: ResultEntry Attributes :header: "Type", "Method", "Definition" @@ -799,7 +820,8 @@ Table 2.20 ResultEntry Attributes "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" -Table 2.21 ResultEntry Methods +Table ResultEntry Methods +------------------------- .. csv-table:: ResultEntry Methods :header: "Type", "Method", "Definition" @@ -917,7 +939,8 @@ As of CDMS V3, the legacy cuDataset interface is supported by Datasets. See “cu Module". -Table 2.22 Dataset Internal Attributes +Table Dataset Internal Attributes +--------------------------------- .. csv-table:: Dataset Internal Attributes :header: "Type", "Name", "Description" @@ -933,16 +956,18 @@ Table 2.22 Dataset Internal Attributes "Dictionary", "``variables``", "Variables contained in the dataset." "Dictionary", "``xlinks``", "External links contained in the dataset." -Table 2.23 Dataset Constructors +Table Dataset Constructors +-------------------------- .. csv-table:: Dataset Internal Attributes :header: "Constructor", "Description" :widths: 50, 80 - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table `Open Modes <#id25>`__ . ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" -Table 2.24 Open Modes +Table Open Modes +---------------- .. csv-table:: Open Modes :header: "Mode", "Definition" @@ -954,7 +979,8 @@ Table 2.24 Open Modes "‘w’", " Create a new file, read-write" -Table 2.25 Dataset Methods +Table Dataset Methods +--------------------- .. csv-table:: Dataset Methods :header: "Type", "Definition", "Description" @@ -1023,7 +1049,7 @@ The command allows use of MV commands without any prefix. -Table 2.26 lists the constructors in MV. All functions return +Table `Variable Constructors in module MV <#table-variable-constructors-in-module-mv>`_, lists the constructors in MV. All functions return a transient variable. In most cases the keywords axes, attributes, and id are available. axes is a list of axis objects which specifies the domain of the variable. attributes is a dictionary. id is a special @@ -1049,7 +1075,8 @@ corresponding MV2 function: ``allclose``, ``allequal``, http://numpy.sourceforge.net for a description of these functions. -Table 2.26 Variable Constructors in module MV +Table Variable Constructors in module MV +---------------------------------------- .. csv-table:: Variable Constructors in module MV :header: "Constructor", "Description" @@ -1070,7 +1097,8 @@ The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. -Table 2.27 MV functions +Table MV functions +------------------ .. csv-table:: MV functions :header: "Function", "Description" @@ -1120,7 +1148,8 @@ cells. Specifically, a HorizontalGrid: CDMS supports several types of HorizontalGrids: -Table 2.28 +Table Grids +----------- .. csv-table:: Grids :header: "Grid Type", "Definition" @@ -1130,7 +1159,8 @@ Table 2.28 "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" -Table 2.29 HorizontalGrid Internal Attribute +Table HorizontalGrid Internal Attribute +--------------------------------------- .. csv-table:: HorizontalGrid Internal Attribute :header: "Type", "Name", "Definition" @@ -1142,24 +1172,11 @@ Table 2.29 HorizontalGrid Internal Attribute "Tuple", "``shape``", "The shape of the grid, a 2-tuple" :: - - - - -.. _RectGrid_Constructors: - -:: - - - - - - -See :ref:`RectGrid_Constructors` -Table 2.30 RectGrid Constructors +Table RectGrid Constructors +--------------------------- .. csv-table:: RectGrid Constructors :header: "Constructor", "Description" @@ -1177,7 +1194,8 @@ Table 2.30 RectGrid Constructors -Table 2.31 HorizontalGrid Methods +Table HorizontalGrid Methods +---------------------------- .. csv-table:: HorizontalGrid Methods @@ -1216,7 +1234,8 @@ Table 2.31 HorizontalGrid Methods ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." -Table 2.32 RectGrid Methods, additional to HorizontalGrid Methods +Table RectGrid Methods, additional to HorizontalGrid Methods +------------------------------------------------------------ .. csv-table:: RectGrid Methods, additional to HorizontalGrid Methods :header: "Type", "Method", "Description" @@ -1274,7 +1293,8 @@ advantage of the attribute, domain, and mask information in a transient variable. -Table 2.33 Variable Internal Attributes +Table Variable Internal Attributes +---------------------------------- .. csv-table:: Variable Internal Attributes :header: "Type", "Name", "Definition" @@ -1287,7 +1307,8 @@ Table 2.33 Variable Internal Attributes "Tuple", "``shape``", "The length of each axis of the variable" -Table 2.34 Variable Constructors +Table Variable Constructors +--------------------------- .. csv-table:: Variable Constructors :header: "Constructor", "Description" @@ -1300,7 +1321,8 @@ Table 2.34 Variable Constructors -Table 2.35 Variable Methods +Table Variable Methods +---------------------- .. csv-table:: Variable Methods :header: "Type", "Method", "Definition" @@ -1419,7 +1441,8 @@ Read all data for March, 1980: -Table 2.36 Variable Slice Operators +Table Variable Slice Operators +------------------------------ .. csv-table:: Variable Slice Operators :header: "Operator", "Description" @@ -1437,7 +1460,8 @@ Table 2.36 Variable Slice Operators -Table 2.37 Index and Coordinate Intervals +Table Index and Coordinate Intervals +------------------------------------ .. csv-table:: Index and Coordinate Intervals :header: "Interval Definition", "Example Interval Definition", "Example" @@ -1458,7 +1482,7 @@ Table 2.37 Index and Coordinate Intervals Selectors ----------------- +^^^^^^^^^ A selector is a specification of a region of data to be selected from a variable. For example, the statement @@ -1514,29 +1538,30 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in See `Index and Coordinate Intervals <#36>`_. +ranges as defined in See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example: - +Table Selector keywords +----------------------- .. csv-table:: Selector keywords :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#36>`_ + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#36>`_ - "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#36>`_ - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#36>`_ + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#36>`_ + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For @@ -1627,7 +1652,7 @@ the call: Selector examples ------------------------- +----------------- CDMS provides a variety of ways to select or slice data. In the following examples, variable hus is contained in file sample.nc, and is From 27603b71530e27e6830710b8bee225490da464b4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 9 Mar 2018 12:07:18 -0800 Subject: [PATCH 057/239] Some changes to Chapters 2, 3 and 4 --- docs/source/manual/cdms_2.rst | 6 ++--- docs/source/manual/cdms_3.rst | 16 ++++++++----- docs/source/manual/cdms_4.rst | 42 ++++++++++++++++++----------------- docs/source/manual/cdms_5.rst | 14 +++++++----- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index ce178c60..dbe8bce9 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -1328,7 +1328,7 @@ Table Variable Methods :header: "Type", "Method", "Definition" :widths: 30, 30, 180 - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table 2.36" + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table `Variable Slice Operators <#table-variable-slice-operators>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21. (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." @@ -1397,7 +1397,7 @@ Table Variable Methods "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table 2.37. Also see ``axis.mapIntervalExt``." + ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1575,7 +1575,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in Table 2.37 are treated as positional. Such +form(s) listed in Table `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 5ac605ef..ec04adc6 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -77,9 +77,11 @@ Time Constructors ^^^^^^^^^^^^^^^^^ The following table describes the methods for creating time types. + +Table Time Constructors +~~~~~~~~~~~~~~~~~~~~~~~ - -.. csv-table:: Time Constructors +.. csv-table:: Table Time Constructors :header: "Type", "Constructor", "Defintion" :widths: 10, 40, 80 @@ -102,7 +104,7 @@ Relative Time A relative time type has two members, value and units. Both can be set. -Table 3.2 Relative Time Members +Table Relative Time Members ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------+---------+-------------------------------------------------------+ @@ -118,7 +120,9 @@ Component Time A component time type has six members, all of which are settable. -.. csv-table:: Table 3.3 Component Time +Table Component Time +~~~~~~~~~~~~~~~~~~~~ +.. csv-table:: Table Component Time :header: "Type", "Name", "Summary" :widths: 15, 15, 50 @@ -134,7 +138,9 @@ Time Methods The following methods apply both to relative and component times. -.. csv-table:: Table 3.4 Time Methods +Table Time Methods +~~~~~~~~~~~~~~~~~~ +.. csv-table:: Table Time Methods :header: "Type", "Method", "Definition" :widths: 20, 75, 80 diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index e9f56784..c7a26731 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -12,7 +12,7 @@ CDMS provides several methods for interpolating gridded data: - from one vertical (lat/level) cross-section to another vertical cross-section. -CDMS horizontal regrider +CDMS Horizontal Regrider ^^^^^^^^^^^^^^^^^^^^^^^^ .. highlight:: python :linenothreshold: 3 @@ -110,7 +110,7 @@ Notes **Line #11** Reads all data for variable cltf, and calls the regridder function on that data, resulting in a transient variable cltnew. -SCRIP horizontal regridder +SCRIP Horizontal Regridder ^^^^^^^^^^^^^^^^^^^^^^^^^^ To interpolate between grids where one or both grids is non-rectangular, @@ -138,7 +138,7 @@ Figure 3 illustrates the process: additional arguments for the gradients of the variable. -FIGURE 3. Regridding data with SCRIP +Regridding Data with SCRIP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Example:** @@ -231,7 +231,7 @@ has shape (12, 64, 128), then the input grid must have shape (64,128). Similarly if the variable had a generic grid with shape (8092,), the last dimension of the variable would have length 8092. -Pressure-level regridder +Pressure-Level Regridder ^^^^^^^^^^^^^^^^^^^^^^^^ To regrid a variable which is a function of latitude, longitude, @@ -253,7 +253,7 @@ returns a new variable ``d`` regridded to that dimension. >>> result.shape (11, 1, 73, 144) -Cross-section regridder +Cross-Section Regridder ^^^^^^^^^^^^^^^^^^^^^^^ To regrid a variable which is a function of latitude, height, and @@ -281,14 +281,14 @@ regridded to those axes. (2, 10, 144) -regrid module +Regrid Module ^^^^^^^^^^^^^ The ``regrid`` module implements the CDMS regridding functionality as well as the SCRIP interface. Although this module is not strictly a part of CDMS, it is designed to work with CDMS objects. -CDMS horizontal regridder +CDMS Horizontal Regridder ^^^^^^^^^^^^^^^^^^^^^^^^^ .. doctest:: @@ -299,10 +299,10 @@ makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. -CDMS Regridder Constructor +Table CDMS Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: REgridder Constructure +.. csv-table:: Regridder Constructure :header: "Constructor", "Description" :widths: 50, 90 @@ -314,10 +314,10 @@ SCRIP Regridder SCRIP regridder functions are created with the ``regrid.readRegridder`` function: -SCRIP Regridder Constructor +Table SCRIP Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: +.. csv-table:: SCRIP Regridder Constructor :header: "Constructor", "Description" :widths: 80, 90 @@ -343,7 +343,7 @@ convexity, and ‘repaired’ if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees. -_`CDMS regridder functions` +_`CDMS Regridder Functions` ^^^^^^^^^^^^^^^^^^^^^^^^^^^ A CDMS regridder function is an instance of the CDMS ``Regridder`` @@ -396,10 +396,10 @@ data value, or 1.0e20 if undefined. The result array or transient variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values -CDMS Regridder function +Table CDMS Regridder Function ~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: +.. csv-table:: CDMS Regridder Function :header: "Type", "Function", "Description" :widths: 40, 40, 80 @@ -415,7 +415,7 @@ CDMS Regridder function , , "``dataArray`` is the result data array." , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." -SCRIP Regridder functions +SCRIP Regridder Functions ^^^^^^^^^^^^^^^^^^^^^^^^^ A SCRIP regridder function is an instance of the ScripRegridder class. @@ -456,10 +456,10 @@ following fields: In addition, a conservative regridder has the associated grid cell areas for source and target grids. -SCRIP Regridder functions +Table SCRIP Regridder Functions ~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: +.. csv-table:: SCRIP Regridder Functions :header: "Return Type", "Method", "Description" :widths: 40, 40, 80 @@ -478,7 +478,7 @@ SCRIP Regridder functions Examples ^^^^^^^^ -CDMS regridder +CDMS Regridder ~~~~~~~~~~~~~~ **Example:** @@ -498,8 +498,10 @@ Regrid data to a uniform output grid. >>> newrls = regridFunc(cltf) >>> f.close() +Table Regridder Constructure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: REgridder Constructure +.. csv-table:: Regridder Constructure :header: "Line", "Notes" :widths: 8, 90 @@ -627,7 +629,7 @@ of the result. | 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | +--------+----------------------------------------------------------------------------------------------------------+ -SCRIP regridder +SCRIP Regridder ~~~~~~~~~~~~~~~ **Example:** diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 17050141..d15f9a24 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -20,7 +20,7 @@ In the following examples, it is assumed that variable ``psl`` is dimensioned (time, latitude, longitude). ``psl`` is contained in the dataset named ``'sample.xml'``. -plotting a gridded variable +Plotting a Gridded Variable ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. highlight:: python :linenothreshold: 3 @@ -72,7 +72,7 @@ What if the units are not explicitly defined for ``clt``, or a different description is desired? ``plot`` has a number of other keywords which fill in the extra plot information. -using aplot keywords. +Using A Plot Keywords ^^^^^^^^^^^^^^^^^^^^^ .. doctest:: @@ -89,7 +89,7 @@ using aplot keywords. **Note:** Keyword arguments can be listed in any order. -plotting a time-latitude slice +Plotting a Time-Latitude Slice ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``, @@ -112,7 +112,7 @@ this example selects and plots a time-latitude slice: "4", "``samp`` is a slice of ``clt``, at index ``0`` of the last dimension. Since ``samp`` was obtained from the slice operator, it is a transient variable, which includes the latitude and time information." "6", "The ``name`` keyword defines the identifier, default is the name found in the file." -plotting subsetted data +Plotting Subsetted Data ^^^^^^^^^^^^^^^^^^^^^^^ Calling the variable ``clt`` as a function reads a subset of the @@ -130,8 +130,8 @@ variable. The result variable ``samp`` can be plotted directly: >>> f.close() -``plot`` method -~~~~~~~~~~~~~~~ +Plot Method +~~~~~~~~~~~ The ``plot`` method is documented in the UV-CDAT Reference Manual. This section augments the documentation with a description of the optional @@ -176,6 +176,8 @@ where: - ``key=value``, ... are optional keyword/value pairs, listed in any order. These are defined in the table below. +Table Plot Keywords +^^^^^^^^^^^^^^^^^^^ .. csv-table:: "plot keywords" :header: "Key", "Type", "Value" From 62832f78510f38d5049a0c6cffe7a7b48ecf9167 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 12 Mar 2018 15:02:42 -0700 Subject: [PATCH 058/239] Some changes made to 1 through Appendix --- docs/source/manual/cdms_2.rst | 109 +- docs/source/manual/cdms_3.rst | 6 +- docs/source/manual/cdms_4.rst | 18 +- docs/source/manual/cdms_5.rst | 7 +- docs/source/manual/cdms_6.rst | 1508 ++------------------------ docs/source/manual/cdms_7.rst | 6 +- docs/source/manual/cdms_appendix.rst | 8 +- 7 files changed, 191 insertions(+), 1471 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index dbe8bce9..1e947920 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -45,8 +45,9 @@ the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: - -.. csv-table:: Python types used in CDMS +Table PythonTypes used in CDMS +------------------------------- +.. csv-table:: :header: "Type", "Description" :widths: 10, 80 @@ -60,7 +61,7 @@ return an instance of a CDMS class, or one of the Python types: "Reltime", "Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime" "Tuple", "An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``" -A first example +A First Example ^^^^^^^^^^^^^^^ The following Python script reads January and July monthly temperature @@ -111,7 +112,7 @@ latitude, longitude). -Cdms module +Cdms Module ^^^^^^^^^^^ The cdms module is the Python interface to CDMS. The objects and methods @@ -131,10 +132,10 @@ Rather, they are called as module functions, e.g., -Table Cdms module functions +Table Cdms Module Functions --------------------------- -.. csv-table:: Cdms module functions +.. csv-table:: :header: "Type", "Definition" :widths: 10, 80 @@ -221,7 +222,7 @@ Table Cdms module functions Table Class Tags -------------------- -.. csv-table:: Class Tags +.. csv-table:: :header: "Tag", "Class" :widths: 20, 20 @@ -263,9 +264,9 @@ external attributes are written, but not the internal attributes. "Dictionary", "attributes", "External attribute dictionary for this object." -Table Getting and setting attributes +Table Getting and Setting Attributes ------------------------------------ -.. csv-table:: Getting and setting attributes +.. csv-table:: :header: "Type", "Definition" :widths: 20, 80 @@ -294,7 +295,7 @@ Axis objects. Table CoordinateAxis Types -------------------------- -.. csv-table:: CoordinateAxis types +.. csv-table:: :header: "Type", "Definition" :widths: 20, 80 @@ -306,7 +307,7 @@ Table CoordinateAxis Types Table CoordinateAxis Internal Attributes ---------------------------------------- -.. csv-table:: CoordinateAxis Internal Attributes +.. csv-table:: :header: "Type", "Name", "Definition" :widths: 20, 20, 80 @@ -318,7 +319,7 @@ Table CoordinateAxis Internal Attributes Table Axis Constructors ----------------------- -.. csv-table:: Axis Constructors +.. csv-table:: :header: "Constructor", "Description" :widths: 20, 80 @@ -340,7 +341,7 @@ Table Axis Constructors Table CoordinateAxis Methods ---------------------------- -.. csv-table:: CoordinateAxis Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 20, 80 @@ -409,8 +410,10 @@ Table CoordinateAxis Methods ,,"* see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." +Table Axis Slice Operators +-------------------------- -.. csv-table:: axis slice operators +.. csv-table:: :header: "Slice", "Definition" :widths: 20, 80 @@ -453,7 +456,7 @@ Cdms-Files. See “cu Module”. Table CdmsFile Internal Attributes ---------------------------------- -.. csv-table:: CdmsFile Internal Attributes +.. csv-table:: :header: "Type", "Name", "Definition" :widths: 20, 20, 80 @@ -466,7 +469,7 @@ Table CdmsFile Internal Attributes Table CdmsFile Constructors --------------------------- -.. csv-table:: CdmsFile Constructors +.. csv-table:: :header: "Constructor", "Description" :widths: 20, 80 @@ -477,7 +480,7 @@ Table CdmsFile Constructors Table CdmsFile Methods ---------------------- -.. csv-table:: CdmsFile Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 20, 80 @@ -521,7 +524,7 @@ Table CdmsFile Methods Table CDMS Datatypes -------------------- -.. csv-table:: CDMS Datatypes +.. csv-table:: :header: "CDMS Datatype", "Definition" :widths: 20, 30 @@ -614,7 +617,7 @@ Table Database Internal Attributes ---------------------------------- -.. csv-table:: Database Internal Attributes +.. csv-table:: :header: "Type", "Name", "Summary" :widths: 20, 20, 80 @@ -628,7 +631,7 @@ Table Database Internal Attributes Table Database Constructors --------------------------- -.. csv-table:: Database Constructors +.. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 @@ -639,7 +642,7 @@ Table Database Constructors Table Database Methods ---------------------- -.. csv-table:: Database Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 30, 80 @@ -679,7 +682,7 @@ Table Database Methods .. highlight:: python :linenothreshold: 0 -Searching a database +Searching a Database -------------------------- The ``searchFilter`` method is used to search a database. The result is @@ -791,7 +794,7 @@ variables defined on a 94x192 grid: Table SearchResult Methods -------------------------- -.. csv-table:: SearchResult Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 30, 80 @@ -812,7 +815,7 @@ with the ``getObject`` method. Table ResultEntry Attributes ---------------------------- -.. csv-table:: ResultEntry Attributes +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 30, 80 @@ -823,7 +826,7 @@ Table ResultEntry Attributes Table ResultEntry Methods ------------------------- -.. csv-table:: ResultEntry Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 30, 80 @@ -850,7 +853,7 @@ In the next example, a portion of variable ‘ua’ is read from dataset data = ua[0,0] -Examples of database searches +Examples of Database Searches ----------------------------------- In the following examples, db is the database opened with @@ -942,7 +945,7 @@ See “cu Module". Table Dataset Internal Attributes --------------------------------- -.. csv-table:: Dataset Internal Attributes +.. csv-table:: :header: "Type", "Name", "Description" :widths: 20, 30, 80 @@ -959,7 +962,7 @@ Table Dataset Internal Attributes Table Dataset Constructors -------------------------- -.. csv-table:: Dataset Internal Attributes +.. csv-table:: :header: "Constructor", "Description" :widths: 50, 80 @@ -969,7 +972,7 @@ Table Dataset Constructors Table Open Modes ---------------- -.. csv-table:: Open Modes +.. csv-table:: :header: "Mode", "Definition" :widths: 50, 80 @@ -982,7 +985,7 @@ Table Open Modes Table Dataset Methods --------------------- -.. csv-table:: Dataset Methods +.. csv-table:: :header: "Type", "Definition", "Description" :widths: 30, 30, 80 @@ -1017,7 +1020,7 @@ Table Dataset Methods "None", "``sync()``", "Write any pending changes to the dataset." -MV module +MV Module ^^^^^^^^^ The fundamental CDMS data object is the variable. A variable is @@ -1075,10 +1078,10 @@ corresponding MV2 function: ``allclose``, ``allequal``, http://numpy.sourceforge.net for a description of these functions. -Table Variable Constructors in module MV +Table Variable Constructors in Module MV ---------------------------------------- -.. csv-table:: Variable Constructors in module MV +.. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 @@ -1097,10 +1100,10 @@ The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. -Table MV functions +Table MV Functions ------------------ -.. csv-table:: MV functions +.. csv-table:: :header: "Function", "Description" :widths: 30, 80 @@ -1151,7 +1154,7 @@ CDMS supports several types of HorizontalGrids: Table Grids ----------- -.. csv-table:: Grids +.. csv-table:: :header: "Grid Type", "Definition" :widths: 30, 80 @@ -1162,7 +1165,7 @@ Table Grids Table HorizontalGrid Internal Attribute --------------------------------------- -.. csv-table:: HorizontalGrid Internal Attribute +.. csv-table:: :header: "Type", "Name", "Definition" :widths: 30, 30, 80 @@ -1178,14 +1181,14 @@ Table HorizontalGrid Internal Attribute Table RectGrid Constructors --------------------------- -.. csv-table:: RectGrid Constructors +.. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See `A First Example`_" - "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See Table 2.14" - "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See Table 2.25" - "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See `A First Example`_ " + "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file." + "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset." + "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See `A First Example`_" "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See `A First Example`_" "``cdms.createGlobalMeanGrid(grid)``", "See `A First Example`_" "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "See `A First Example`_" @@ -1198,7 +1201,7 @@ Table HorizontalGrid Methods ---------------------------- -.. csv-table:: HorizontalGrid Methods +.. csv-table:: :header: "Type", "Method", "Description" :widths: 30, 30, 80 @@ -1234,10 +1237,10 @@ Table HorizontalGrid Methods ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." -Table RectGrid Methods, additional to HorizontalGrid Methods +Table RectGrid Methods, Additional to HorizontalGrid Methods ------------------------------------------------------------ -.. csv-table:: RectGrid Methods, additional to HorizontalGrid Methods +.. csv-table:: :header: "Type", "Method", "Description" :widths: 30, 30, 80 @@ -1296,7 +1299,7 @@ variable. Table Variable Internal Attributes ---------------------------------- -.. csv-table:: Variable Internal Attributes +.. csv-table:: :header: "Type", "Name", "Definition" :widths: 30, 30, 80 @@ -1310,7 +1313,7 @@ Table Variable Internal Attributes Table Variable Constructors --------------------------- -.. csv-table:: Variable Constructors +.. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 @@ -1324,7 +1327,7 @@ Table Variable Constructors Table Variable Methods ---------------------- -.. csv-table:: Variable Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 30, 30, 180 @@ -1415,7 +1418,7 @@ Table Variable Methods ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." ,,"String ``typecode()`` The Numpy datatype identifier." -Example Get a region of data. +Example Get a Region of Data. ----------------------------- Variable ta is a function of (time, latitude, longitude). Read data @@ -1444,7 +1447,7 @@ Read all data for March, 1980: Table Variable Slice Operators ------------------------------ -.. csv-table:: Variable Slice Operators +.. csv-table:: :header: "Operator", "Description" :widths: 30, 80 @@ -1463,7 +1466,7 @@ Table Variable Slice Operators Table Index and Coordinate Intervals ------------------------------------ -.. csv-table:: Index and Coordinate Intervals +.. csv-table:: :header: "Interval Definition", "Example Interval Definition", "Example" :widths: 30, 80, 80 @@ -1545,10 +1548,10 @@ components is the positional form, where the component order corresponds to the axis order of a variable. For example: -Table Selector keywords +Table Selector Keywords ----------------------- -.. csv-table:: Selector keywords +.. csv-table:: :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 @@ -1651,7 +1654,7 @@ the call: -Selector examples +Selector Examples ----------------- CDMS provides a variety of ways to select or slice data. In the diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index ec04adc6..1c3a3f73 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -81,7 +81,7 @@ The following table describes the methods for creating time types. Table Time Constructors ~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: Table Time Constructors +.. csv-table:: :header: "Type", "Constructor", "Defintion" :widths: 10, 40, 80 @@ -122,7 +122,7 @@ A component time type has six members, all of which are settable. Table Component Time ~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: Table Component Time +.. csv-table:: :header: "Type", "Name", "Summary" :widths: 15, 15, 50 @@ -140,7 +140,7 @@ The following methods apply both to relative and component times. Table Time Methods ~~~~~~~~~~~~~~~~~~ -.. csv-table:: Table Time Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 75, 80 diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index c7a26731..e3f150df 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -302,7 +302,7 @@ input to output grids. Table CDMS Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: Regridder Constructure +.. csv-table:: :header: "Constructor", "Description" :widths: 50, 90 @@ -317,7 +317,7 @@ function: Table SCRIP Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: SCRIP Regridder Constructor +.. csv-table:: :header: "Constructor", "Description" :widths: 80, 90 @@ -396,10 +396,10 @@ data value, or 1.0e20 if undefined. The result array or transient variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values -Table CDMS Regridder Function -~~~~~~~~~~~~~~~~~~~~~~~ +Table CDMS Regridder Function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: CDMS Regridder Function +.. csv-table:: :header: "Type", "Function", "Description" :widths: 40, 40, 80 @@ -457,9 +457,9 @@ In addition, a conservative regridder has the associated grid cell areas for source and target grids. Table SCRIP Regridder Functions -~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: SCRIP Regridder Functions +.. csv-table:: :header: "Return Type", "Method", "Description" :widths: 40, 40, 80 @@ -501,7 +501,7 @@ Regrid data to a uniform output grid. Table Regridder Constructure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. csv-table:: Regridder Constructure +.. csv-table:: :header: "Line", "Notes" :widths: 8, 90 @@ -672,4 +672,4 @@ comparison. -a + diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index d15f9a24..4872feaa 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -56,7 +56,7 @@ Plotting a Gridded Variable **Notes:** -.. csv-table:: LineNotes +.. csv-table:: :header: "Line", "Notes" :widths: 10, 90 @@ -105,7 +105,8 @@ this example selects and plots a time-latitude slice: >>> w.plot(samp, name='Total Cloudiness') -.. csv-table:: LineNotes + +.. csv-table:: Line Notes :header: "Line", "Notes" :widths: 10, 90 @@ -179,7 +180,7 @@ where: Table Plot Keywords ^^^^^^^^^^^^^^^^^^^ -.. csv-table:: "plot keywords" +.. csv-table:: :header: "Key", "Type", "Value" :widths: 20, 20, 80 diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index c29835e8..39a0f235 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -50,8 +50,8 @@ where The CDML elements are: -Table 6.1 CDML Tags - +Table CDML Tags +^^^^^^^^^^^^^^^^^^^ +------------+---------------------------------------+ | Tag | Description | @@ -77,7 +77,8 @@ Special Characters XML reserves certain characters for markup. If they appear as content, they must be encoded to avoid confusion with markup: -Table 6.2 Special Character Encodings +Table Special Character Encodings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------+------------+ @@ -163,7 +164,7 @@ defined. ``dataset-content ::= (axis-element | grid-element | variable-element)* extra-attribute-element+`` -Table 6.3 Dataset Attributes +Dataset Attributes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Attribute", "Required", "CF", "GDT", "Notes" @@ -235,8 +236,8 @@ length). ``linear-element ::=`` ** ** -Table 6.4 -^^^^^^^^^ +Table Axis Elements +^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Attribute", "Required?", "CF", "GDT", "Notes" @@ -365,1429 +366,144 @@ the length. start=\ **"``Integer``" **\ length=\ **"``Integer``" **\ partition\_length=\ **"``Integer``"**/>\*\* -Table 6.6 Variable Attributes - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - -.. raw:: html +.. csv-table:: + :header: "Attribute", "Required?", "CF", "GDT", "Notes" + :widths: 15,1,1,1,80 - +Attributes which are not explicitly defined by the GDT convention are +represented as extra attribute elements. Any dataset, axis, grid, or +variable element can have an extra attribute as part of its content. +This representation is also useful if the attribute value has non-blank +whitespace characters (carriage returns, tabs, linefeeds) which are +significant. -.. raw:: html +The datatype is one of: **Char**, **Short**, **Long**, **Float**, +**Double**, or **String**. - +``extra-attribute-element ::=`` **** ``attribute-value`` +**** -.. raw:: html +A Sample CDML Document +~~~~~~~~~~~~~~~~~~~~~~ - +Dataset "sample" has two variables, and six axes. -.. raw:: html +**Note:** - + .. raw:: html - + [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] -.. raw:: html +:: - + 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 -.. raw:: html + 303.75 315. 326.25 337.5 348.75] + - + + + + + + + -.. raw:: html + {% endhighlight %} - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - - - -.. raw:: html - -
- -Attribute - -.. raw:: html - - - -Required? - -.. raw:: html - - - -CF - -.. raw:: html - - - -GDT - -.. raw:: html - - - -Notes - -.. raw:: html - -
- -id - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Variable identifier. Also, the name of the variable in the underlying -file(s), if name\_in\_file is undefined. - -.. raw:: html - -
- -add\_offset - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Additive offset for packing data. See scale\_factor. - -.. raw:: html - -
- -associate - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html +Table Variable Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^ - + "``id``", "Y", "N", "N", "Variable identifier. Also, the name of the variable in the underlying file(s), if name_in_file is undefined." + "``ad_offset``", "N", "Y", "Y", "Additive offset for packing data. See scale_factor." + "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates Spatio-temporal dimensions." + "``axis``", "N", "N", "Y", "Example: TYX for a variable with domain (time, latitude, longitude) Note: for CF, applies to axes only." + "``cell_methods``", "N", "Y", "N", "The method used to derive data that represents cell values, e.g., maximum,mean,variance, etc." + "``comments``", "N", "N", "N", "Comment string" + "``coordinates``", "N", "Y", "N", "IDs of variables containing coordinate data." + "``datatype``", "Y", "N", "N", "Char, Short, Long, Float, Double, or String" + "``grid_name``", "N", "N", "N", "Id of the grid." + "``grid_type``", "N", "N", "N", "gaussian, uniform, equalarea, generic" + "``long_name``", "N", "Y", "Y", "Long description of a physical quantity." + "``missing_value``", "N", "Y", "Y", "Value used for data that are unknown or missing." + "``name_in_file``", "N", "N", "N", "Name of the variable in the underlying file(s). See id." + "``scale_factor``", "N", "Y", "Y", "Multiplicative factor for packing data. See add_offset." + "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." + "``subgrid``", "N", "N", "Y", "Records how data values represent subgrid variation." + "``template``", "N", "N", "N", "Name of the file template to use for this variable. Overrides the dataset value." + "``units``", "N", "Y", "Y", "Units of a physical quantity." + "``valid_max``", "N", "Y", "Y", "Largest valid value of a variable." + "``valid_min``", "N", "Y", "Y", "Smallest valid value of a variable." + "``valid_range``", "N", "Y", "Y", "Largest and smallest valid values of a variable." -IDs of variables containing alternative sets of coordinates -.. raw:: html +Attribute Element +^^^^^^^^^^^^^^^^^ -
+- The file is indented for readability. This is not required; the added + whitespace is ignored. +- The dataset contains three axes and two variables. Variables u and v + are functions of time, latitude, and longitude. +- The global attribute cdms\_filemap describes the mapping between + variables and files. The entry + ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` + indicates that variable ``u`` is contained in file u\_2000.nc for + time index 0, u\_2001.nc for time index 1, etc. -axis +{% highlight xml %} .. raw:: html - - -N - -.. raw:: html + - + -N + [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. -.. raw:: html + 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 - + -Y + [ 0. 366. 731.] + -.. raw:: html + + + + + + + - - -.. raw:: html - -

- -Spatio-temporal dimensions. - -.. raw:: html - -

- -.. raw:: html - -

- -Example: "TYX" for a variable with domain (time, latitude, longitude) - -.. raw:: html - -

- -.. raw:: html - -

- -Note: for CF, applies to axes only. - -.. raw:: html - -

- -.. raw:: html - -
- -cell\_methods - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -The method used to derive data that represents cell values, e.g., -"maximum", "mean", "variance", etc. - -.. raw:: html - -
- -comments - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Comment string - -.. raw:: html - -
- -coordinates - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -IDs of variables containing coordinate data. - -.. raw:: html - -
- -datatype - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Char, Short, Long, Float, Double, or String - -.. raw:: html - -
- -grid\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Id of the grid - -.. raw:: html - -
- -grid\_type - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -"gaussian" \| "uniform" \| "equalarea" \| "generic" - -.. raw:: html - -
- -long\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Long description of a physical quantity. - -.. raw:: html - -
- -missing\_value - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Value used for data that are unknown or missint. - -.. raw:: html - -
- -name\_in\_file - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Name of the variable in the underlying file(s). See id. - -.. raw:: html - -
- -scale\_factor - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Multiplicative factor for packing data. See add\_offset. - -.. raw:: html - -
- -standard\_name - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -N - -.. raw:: html - - - -Reference to an entry in the standard name table. - -.. raw:: html - -
- -subgrid - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Records how data values represent subgrid variation. - -.. raw:: html - -
- -template - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -N - -.. raw:: html - - - -Name of the file template to use for this variable. Overrides the -dataset value. - -.. raw:: html - -
- -units - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Units of a physical quantity. - -.. raw:: html - -
- -valid\_max - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Largest valid value of a variable - -.. raw:: html - -
- -valid\_min - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Smallest valid value of a variable - -.. raw:: html - -
- -valid\_range - -.. raw:: html - - - -N - -.. raw:: html - - - -Y - -.. raw:: html - - - -Y - -.. raw:: html - - - -Largest and smallest valid values of a variable - -.. raw:: html - -
- -6.6.6 Attribute Element -^^^^^^^^^^^^^^^^^^^^^^^ - -Attributes which are not explicitly defined by the GDT convention are -represented as extra attribute elements. Any dataset, axis, grid, or -variable element can have an extra attribute as part of its content. -This representation is also useful if the attribute value has non-blank -whitespace characters (carriage returns, tabs, linefeeds) which are -significant. - -The datatype is one of: **Char**, **Short**, **Long**, **Float**, -**Double**, or **String**. - -``extra-attribute-element ::=`` **** ``attribute-value`` -**** - -A Sample CDML Document -~~~~~~~~~~~~~~~~~~~~~~ - -Dataset "sample" has two variables, and six axes. - -**Note:** - -- The file is indented for readability. This is not required; the added - whitespace is ignored. -- The dataset contains three axes and two variables. Variables u and v - are functions of time, latitude, and longitude. -- The global attribute cdms\_filemap describes the mapping between - variables and files. The entry - ``[[u],[[0,1,-,-,u_2000.nc],[1,2,-,-,u_2001.nc],[2,3,,-,u_2002.nc] ]`` - indicates that variable ``u`` is contained in file u\_2000.nc for - time index 0, u\_2001.nc for time index 1, etc. - -{% highlight xml %} - -.. raw:: html - - - -.. raw:: html - - - - [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] - -:: - - - - [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. - - 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 - - 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 - - 303.75 315. 326.25 337.5 348.75] - - - - - [ 0. 366. 731.] - - - - - - - - - - - - - - - - - - - {% endhighlight %} - c + diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index c2a3bb25..0e311778 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -1,7 +1,7 @@ CDMS Utilities -------------- -cdscan: Importing datasets into CDMS +CdScan: Importing datasets into CDMS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Overview @@ -60,8 +60,8 @@ where Output is written to standard output by default. Use the -x option to specify an output filename. -Table 7.1 cdscan command options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Table CDScan Command Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Option:, "Description" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index c311f0db..44be97a9 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -189,11 +189,11 @@ in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. Slab ~~~~ -Table C.1 Slab Methods +Table Slab Methods ^^^^^^^^^^^^^^^^^^^^^^ -.. csv-table:: Slab Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20,50,80 @@ -210,10 +210,10 @@ Table C.1 Slab Methods cuDataset ~~~~~~~~~ -Table C.2 cuDataset Methods +Table cuDataset Methods ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. csv-table:: cuDataset_Methods +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 50, 80 From 5e30a188a0d052916f601672bc70ddc55ccc2a48 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 13 Mar 2018 15:54:02 -0700 Subject: [PATCH 059/239] Some Changes made to Chapter 2 --- docs/source/manual/cdms_2.rst | 52 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 1e947920..09d5423b 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -255,7 +255,8 @@ external attributes are written, but not the internal attributes. extatts = obj.attributes.keys() - +Table Attributes Common to All CDMS Objects +------------------------------------------- .. csv-table:: Attributes common to all CDMS objects :header: "Type", "Name", "Definition" @@ -375,9 +376,10 @@ Table CoordinateAxis Methods "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." +Table Axis Methods, Additional to CoordinateAxis +------------------------------------------------ - -.. csv-table:: Axis Methods, additional to CoordinateAxis +.. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 20, 80 @@ -415,7 +417,7 @@ Table Axis Slice Operators .. csv-table:: :header: "Slice", "Definition" - :widths: 20, 80 + :widths: 20, 100 "``[i]``", "the ``ith`` element, starting with index ``0``" "``[i:j]``", "the ``ith`` element through, but not including, element ``j``" @@ -424,16 +426,18 @@ Table Axis Slice Operators "``[:]``", "the entire array" "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." + , " **Example:** a longitude axis has value" + , " * ``[0.0, 2.0, ..., 358.0]``" + , " * of length ``180``" + , " * map the coordinate interval:" + , " * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval" + , " * ``-2 <= n < 3`` wraps around, since" + , " * ``-2 < 0``, and has a stride of ``1``" + , " * this is equivalent to the two contiguous index intervals" + , " * ``2 <= n < 0`` and ``0 <= n < 3``" -**example:** - -a longitude axis has value ``[0.0, 2.0, ..., 358.0]``, of length -``180``. map the coordinate interval ``-5.0 <= x < 5.0`` to index -interval(s), with wraparound. the result index interval ``-2 <= n < 3`` -wraps around, since ``-2 < 0``, and has a stride of ``1``. this is -equivalent to the two contiguous index intervals ``2 <= n < 0`` and -``0 <= n < 3`` - +Example 1 +''''''''''' .. doctest:: >>> axis.isCircular() @@ -501,12 +505,12 @@ Table CdmsFile Methods "``None``", "``close()``", "Close the file." "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." - "``Axis``", "``createAxis(id, ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid, String datatype, Listaxes, fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self, whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." "``Variable``", "``write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." @@ -966,7 +970,7 @@ Table Dataset Constructors :header: "Constructor", "Description" :widths: 50, 80 - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Table `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" Table Open Modes @@ -1186,8 +1190,8 @@ Table RectGrid Constructors :widths: 30, 80 "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See `A First Example`_" - "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file." - "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset." + "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See `CdmsFile Constructors <#table-cdmsfile-constructors>`_" + "``Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a dataset. See `Dataset Constructors <#table-dataset-constructors>`_ " "``cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx')``", "See `A First Example`_" "``cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``", "See `A First Example`_" "``cdms.createGlobalMeanGrid(grid)``", "See `A First Example`_" @@ -1331,8 +1335,8 @@ Table Variable Methods :header: "Type", "Method", "Definition" :widths: 30, 30, 180 - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in Table `Variable Slice Operators <#table-variable-slice-operators>`_ " - "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in Table 2.21. (Variables in CdmsFiles only)" + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " + "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." @@ -1400,7 +1404,7 @@ Table Variable Methods "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in Table `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." + ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1578,7 +1582,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in Table `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ are treated as positional. Such +form(s) listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. From 1d7d2596199f429fe2717406442d012c165872b4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 14 Mar 2018 15:51:56 -0700 Subject: [PATCH 060/239] Some Changes to Chapters 1, 2, 3, 6 and Appendix --- docs/source/manual/cdms_1.rst | 9 ++++--- docs/source/manual/cdms_2.rst | 35 ++++++++++++------------- docs/source/manual/cdms_3.rst | 4 +-- docs/source/manual/cdms_6.rst | 7 +++-- docs/source/manual/cdms_appendix.rst | 38 ++++++++++++++-------------- 5 files changed, 50 insertions(+), 43 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 0d2bb35d..1492028f 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -298,7 +298,7 @@ with a corresponding mask value of one are set to the value of the variables ``missing_value`` attribute. The data and ``missing_value`` attribute are then written to the file. -Masking is covered in `Section 2.9 `__. See also the +Masking is covered in `Section 2.9 `__. See also the documentation of the Python Numpy and MA modules, on which ``cdms.MV`` is based, at @@ -541,7 +541,9 @@ grid. Note that: .. figure:: images/curvilinear_grid.jpg :alt: curvilinear grid - Figure1: Curvilinear Grid + Figure 1: Curvilinear Grid + + Example: a generic grid ''''''''''''''''''''''' @@ -848,4 +850,5 @@ Protocol (LDAP). .. >>> f.variables.keys() # List the variables in the dataset. .. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] -Databases are discussed further in `Section 2.7 `__. + +Databases are discussed further in `Section 2.7 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 09d5423b..b107b6ef 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -512,7 +512,7 @@ Table CdmsFile Methods ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var, attributes=None, axes=None, extbounds=None, id=None, extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." ,,"* ``var`` is a Variable, masked array, or Numpy array." ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." @@ -804,7 +804,7 @@ Table SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." - "SearchResult", " ``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." + "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string @@ -1005,7 +1005,7 @@ Table Dataset Methods ,, "**Example:**" ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." + "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." ,,"``lat`` is a latitude axis in the dataset." ,,"``lon`` is a longitude axis in the dataset." ,,"``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." @@ -1018,7 +1018,7 @@ Table Dataset Methods "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." ,,"``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-or Generic-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``." ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1081,22 +1081,23 @@ corresponding MV2 function: ``allclose``, ``allequal``, ``set_print_limit``, ``shape``, ``size``. See the documentation at http://numpy.sourceforge.net for a description of these functions. + -Table Variable Constructors in Module MV ----------------------------------------- +Table Variable Constructors in Module MV +--------------------------- .. csv-table:: :header: "Constructor", "Description" - :widths: 30, 80 + :widths: 30, 80 - "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. **Synonym:** ``arange``" - "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." - "``masked_object(data, value, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." - "``masked_values(data, value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) > atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked_object instead." - "``ones(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." - "``reshape(a, newshape, axes=none, attributes=none, id=none)``", "copy of a with a new shape." - "``resize(a, newshape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size." - "``zeros(shape, typecode='l', savespace=0, axes=none, attributes=none, id=none)``", "an array of all zeros of the given length or shape" + "``arrayrange(start, stop=None, step=1,typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. **Synonym:** ``arange``" + "``masked_array(a,mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." + "``masked_object(data,value, copy=1,savespace=0,axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." + "``masked_values(data,value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) > atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked_object instead." + "``ones(shape, typecode='l',savespace=0,axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." + "``reshape(a,newshape, axes=none, attributes=none, id=none)``", "copy of a with a new shape." + "``resize(a,newshape, axes=none, attributes=none, id=none)``", "return a new array with the specified shape. the original arrays total size can be any size." + "``zeros(shape,typecode='l',savespace=0, axes=none, attributes=none, id=none)``", "an array of all zeros of the given length or shape" @@ -1107,7 +1108,7 @@ exception of argsort, all functions return a transient variable. Table MV Functions ------------------ -.. csv-table:: +.. csv-table:: :header: "Function", "Description" :widths: 30, 80 @@ -1324,7 +1325,7 @@ Table Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." ,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", " Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 1c3a3f73..75093b96 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -144,14 +144,14 @@ Table Time Methods :header: "Type", "Method", "Definition" :widths: 20, 75, 80 - "Comptime or Reltime", "``t.add(value, intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." + "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." ,, "``value`` is the Float number of interval units." ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" ,, "``calendar`` is the calendar type." "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." ,, "``t2`` is the time to compare." ,, "``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value, intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." + "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." ,, "``value`` is the Float number of interval units." ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" ,, "``calendar`` is the calendar type. " diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 39a0f235..926784f3 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -315,6 +315,7 @@ rectilinear in topology, ``extra-attribute-element*`` **** Table 6.5 RectGrid Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. raw:: html @@ -332,11 +333,13 @@ Table 6.5 RectGrid Attributes :: idYNGrid identifier - typeYN

Grid classification

"gaussian" | "uniform" | "equalarea" |"generic"

Default: "generic"

+ typeYN

Grid classification

"gaussian" | "uniform" + | "equalarea" |"generic"

Default: "generic"

latitudeYNLatitude axis name longitudeYNLongitude axis name maskNNName of associated mask variable - orderYN

Grid ordering "yx" | "xy"

Default: “yx”, axis order is latitude, longitude

+ orderYN

Grid ordering "yx" + | "xy"

Default: “yx”, axis order is latitude, longitude

.. raw:: html diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 44be97a9..ebfc6f76 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -86,7 +86,7 @@ major changes were: the portability of the code. Details -******* +^^^^^^^ AbstractVariable '''''''''''''''' @@ -217,35 +217,35 @@ Table cuDataset Methods :header: "Type", "Method", "Definition" :widths: 20, 50, 80 - "None", "cleardefault()", "Clear the default variable name." - "None", "default_variable(vname)", "Set the default variable name." + "None", "``cleardefault()``", "Clear the default variable name." + "None", "``default_variable(vname``)", "Set the default variable name." ,,"vname is the string variable name." - "Array", "dimensionarray(dname, vname=None)", "Values of the axis named dname." + "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname." ,,"dname is the string axis name." ,,"vname is the string variable name. The default is the variable name set by default_variable." - "Axis", "dimensionobject(dname, vname=None)", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." - "Various", "getattribute (vname, attribute)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." - "String", "getdimensionunits (dname,vname=None)", "Get the units for the given dimension." + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." + "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." + "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension." ,,"dname is the string name of an axis." ,,"vname is a string variable name. The default is the variable name set by default_variable." - "Various", "getglobal (attribute)", "Get the value of the global attribute. attribute is the string attribute name." - "Variable", "getslab (vname, \*args)", "Read data for a variable." + "Various", "``getglobal (attribute)``", "Get the value of the global attribute. attribute is the string attribute name." + "Variable", "``getslab (vname, \*args)``", "Read data for a variable." ,, "vname is the string name of the variable." ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" ,, "- ':' or None -- select the entire dimension" ,, "- Ellipsis -- select entire dimensions between the ones given." ,, "- a pair of successive arguments giving an interval in world coordinates." ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" - "List", "listall (vname=None, all=None)", "Get info about data from the file." + "List", "``listall (vname=None, all=None)``", "Get info about data from the file." ,, "vname is the string name of the variable." ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" - "List", "listattribute (vname=None )", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." - "List", "listdimension (vname=None)", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." - "List", "listglobal ()", "Return a list of the global attribute names." - "List", "listvariable ()", "Return a list of the variables in the file." - "None", "showall (vname=None, all=None, device=sys.stdout)", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." - "None", "showattribute (vname=None, device=sys.stdout)", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." - "None", "showdimension (vname=None, device=sys.stdout)", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." - "None", "showglobal (device=sys.stdout)", "Print the global file attributes. Output is sent to device." - "None", "showvariable (device=sys.stdout)", "Print the list of variables in the file." + "List", "``listattribute (vname=None )``", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "List", "``listglobal ()``", "Return a list of the global attribute names." + "List", "``listvariable ()``", "Return a list of the variables in the file." + "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." + "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "``showglobal (device=sys.stdout)``", "Print the global file attributes. Output is sent to device." + "None", "``showvariable (device=sys.stdout)``", "Print the list of variables in the file." From a40269de05d8b24ebf8751d0234f91f05f28c24f Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 15 Mar 2018 15:42:53 -0700 Subject: [PATCH 061/239] Some changes made to Chapters 1 thru 7 and appendix --- docs/source/manual/cdms_1.rst | 4 +-- docs/source/manual/cdms_2.rst | 45 +++++++++++++++++++--------- docs/source/manual/cdms_3.rst | 2 ++ docs/source/manual/cdms_4.rst | 28 ++++++++++++----- docs/source/manual/cdms_5.rst | 10 +++---- docs/source/manual/cdms_6.rst | 4 +-- docs/source/manual/cdms_appendix.rst | 2 ++ 7 files changed, 65 insertions(+), 30 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 1492028f..72f95d71 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -469,7 +469,7 @@ CDMS supports two types of nonrectangular grid: However, it is more difficult to determine adjacency relationships between grid points. -Example: a curvilinear grid +Example: A Curvilinear Grid ''''''''''''''''''''''''''' In this example, variable sample is defined on a 128x192 curvilinear @@ -545,7 +545,7 @@ grid. Note that: -Example: a generic grid +Example: A Generic Grid ''''''''''''''''''''''' In this example variable zs is defined on a generic grid. Figure 2 diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index b107b6ef..7bb2ff40 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -50,6 +50,7 @@ Table PythonTypes used in CDMS .. csv-table:: :header: "Type", "Description" :widths: 10, 80 + :align: left "Array", "Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules." "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" @@ -138,6 +139,8 @@ Table Cdms Module Functions .. csv-table:: :header: "Type", "Definition" :widths: 10, 80 + :align: left + "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" @@ -345,11 +348,13 @@ Table CoordinateAxis Methods .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 20, 80 + :align: left + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." - "``Axis``", "``clone(copyData=1)``", " Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." + "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." @@ -382,6 +387,8 @@ Table Axis Methods, Additional to CoordinateAxis .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 20, 80 + :align: left + "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." @@ -417,7 +424,7 @@ Table Axis Slice Operators .. csv-table:: :header: "Slice", "Definition" - :widths: 20, 100 + :widths: 50, 110 "``[i]``", "the ``ith`` element, starting with index ``0``" "``[i:j]``", "the ``ith`` element through, but not including, element ``j``" @@ -475,7 +482,8 @@ Table CdmsFile Constructors .. csv-table:: :header: "Constructor", "Description" - :widths: 20, 80 + :widths: 50, 80 + :align: left "Constructor", "Description" "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." @@ -486,7 +494,9 @@ Table CdmsFile Methods .. csv-table:: :header: "Type", "Method", "Definition" - :widths: 20, 20, 80 + :widths: 10, 30, 80 + :align: left + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." @@ -653,7 +663,7 @@ Table Database Methods "None", "``close()``", "Close a database" "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." - , "* ``dsetid``"," is the string dataset identifier" + , "* ``dsetid``","is the string dataset identifier" , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." , "* ``openDataset``", "is a synonym for ``open``." "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." @@ -969,6 +979,7 @@ Table Dataset Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 50, 80 + :align: left "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" @@ -979,11 +990,12 @@ Table Open Modes .. csv-table:: :header: "Mode", "Definition" :widths: 50, 80 + :align: left - "‘r’", " read-only" + "‘r’", "read-only" "‘r+’", "read-write" "‘a’", "read-write. Open the file if it exists, otherwise create a new file" - "‘w’", " Create a new file, read-write" + "‘w’", "Create a new file, read-write" Table Dataset Methods @@ -1084,14 +1096,18 @@ http://numpy.sourceforge.net for a description of these functions. Table Variable Constructors in Module MV ---------------------------- +----------------------------------------- + +.. tabularcolumns:: |l|r| + .. csv-table:: :header: "Constructor", "Description" - :widths: 30, 80 + :widths: 50, 80 + :align: left - "``arrayrange(start, stop=None, step=1,typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. **Synonym:** ``arange``" - "``masked_array(a,mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." + "``arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None)``", "Just like ``MV2.arange()`` except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. **Synonym:** ``arange``" + "``masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None)``", "Same as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape." "``masked_object(data,value, copy=1,savespace=0,axes=None, attributes=None, id=None)``", "Create variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id." "``masked_values(data,value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None)``", "Constructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where ``abs(data - value) > atol + rtol * abs(data)``. This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked_object instead." "``ones(shape, typecode='l',savespace=0,axes=none, attributes=none, id=none)``", "return an array of all ones of the given length or shape." @@ -1107,10 +1123,10 @@ exception of argsort, all functions return a transient variable. Table MV Functions ------------------ - .. csv-table:: :header: "Function", "Description" - :widths: 30, 80 + :widths: 50, 80 + :align: left "``argsort(x, axis=-1, fill_value=None)``", "Return a Numpy array of indices for sorting along a given axis." "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function." @@ -1161,7 +1177,8 @@ Table Grids .. csv-table:: :header: "Grid Type", "Definition" - :widths: 30, 80 + :widths: 50, 80 + :align: left "``RectGrid``", "Associated latitude an longitude are 1-D axes, with strictly monotonic values." "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 75093b96..08d7592d 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -84,6 +84,7 @@ Table Time Constructors .. csv-table:: :header: "Type", "Constructor", "Defintion" :widths: 10, 40, 80 + :align: left "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." ,, "``value`` is an integer or floating point value." @@ -143,6 +144,7 @@ Table Time Methods .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 75, 80 + :align: left "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." ,, "``value`` is the Float number of interval units." diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index e3f150df..d16f72dd 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -300,13 +300,14 @@ instance of Regridder is a function which regrids data from rectangular input to output grids. Table CDMS Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" :widths: 50, 90 + :align: left - "regridFunction = Regridder(inputGrid, outputGrid)", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "``regridFunction = Regridder(inputGrid, outputGrid)``", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -315,13 +316,14 @@ SCRIP regridder functions are created with the ``regrid.readRegridder`` function: Table SCRIP Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" :widths: 80, 90 + :align: left - "regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)", "Read a regridder from an open CDMS file object." + "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object." "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." "", "``mapMethod`` is one of:" "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." @@ -402,6 +404,7 @@ Table CDMS Regridder Function .. csv-table:: :header: "Type", "Function", "Description" :widths: 40, 40, 80 + :align: left "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." , , "``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4." @@ -462,6 +465,7 @@ Table SCRIP Regridder Functions .. csv-table:: :header: "Return Type", "Method", "Description" :widths: 40, 40, 80 + :align: left "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable." @@ -557,13 +561,23 @@ Get a mask from a separate file, and set as the input grid mask. the input array sof are four-dimensional. This is the n-dimensional case. + **Example:** Generate an array of zonal mean values. -1 f = cdms.open(‘rls\_ccc\_per.nc’) 2 rlsf = f.variables[‘rls’] 3 ingrid -= rlsf.getGrid() 4 outgrid = cdms.createZonalGrid(ingrid) 5 regridFunc = -Regridder(ingrid,outgrid) 6 mean = regridFunc(rlsf) 7 f.close() + +.. doctest:: + + >>> f = cdms.open(‘rls_ccc_per.nc’) + >>> rlsf = f.variables[‘rls’] + >>> ingrid = rlsf.getGrid() + >>> outgrid = cdms.createZonalGrid(ingrid) + >>> regridFunc = Regridder(ingrid,outgrid) + >>> mean = regridFunc(rlsf) + >>> f.close() + + +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Line | Notes | diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 4872feaa..915817d6 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -193,20 +193,20 @@ Table Plot Keywords "``hms``", "string", "Hour, minute, second" "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" - "``name``", "string", "Variable name, defaults to `variable.id``" + "``name``", "string", "Variable name, defaults to ``variable.id``" "``time``", "cdtime relative or absolute", "Time associated with the data." ,,"Example:" ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" "``units``", "string", "Data units. Defaults to ``variable.units``" "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." - "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to xaxis[:\] (y|z|t|waxis[:])" + "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" - "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the x-axis (y-axis). Defaults to 0, with the following exceptions:" - ,,"- If the y-axis is latitude, and has decreasing values, ``yrev`` defaults to 1" - ,,"- If the y-axis is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions:" + ,,"- If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1" + ,,"- If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 926784f3..2bc9e8fc 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -241,7 +241,7 @@ Table Axis Elements .. csv-table:: :header: "Attribute", "Required?", "CF", "GDT", "Notes" - :widths: 15,1,1,1,80 + :widths: 18,1,1,1,80 "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates." "``axis``", "N", "Y", "Y", "The spatial type of the axis:" @@ -271,7 +271,7 @@ Table Axis Elements "``month_lengths``", "N", "Y", "N", "Length of each month in a non-leap year for a user-defined calendar." "``name_in_file``", "N", "N", "N", "Name of the axis in the underlying file(s). See id." "``partition``", "N", "N", "N", "How the axis is split across files." - "``partition_lengt h``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." + "``partition_length``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." "``positive``", "N", "Y", "Y", "Direction of positive for a vertical axis" "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." "``topology``", "N", "N", "Y", "- Axis topology." diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index ebfc6f76..a555dbc2 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -196,6 +196,7 @@ Table Slab Methods .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20,50,80 + :align: left "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." @@ -216,6 +217,7 @@ Table cuDataset Methods .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 50, 80 + :align: left "None", "``cleardefault()``", "Clear the default variable name." "None", "``default_variable(vname``)", "Set the default variable name." From 074fcfb1e3a724b7a00631f3fa5510653fdba7ea Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 19 Mar 2018 15:45:57 -0700 Subject: [PATCH 062/239] Some changes to Chpaters 1, 2 and 3 --- docs/source/manual/cdms_1.rst | 4 ++-- docs/source/manual/cdms_2.rst | 18 +++++++++--------- docs/source/manual/cdms_3.rst | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 72f95d71..49dfc9f3 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -26,7 +26,7 @@ be sliced to obtain a portion of the data, and can be used in arithmetic computations. For example, if ``u`` and ``v`` are variables representing the eastward and northward components of wind speed, respectively, and both variables are functions of time, latitude, and longitude, then the -velocity for time 0 (first index) can be calculated as +velocity for time 0 (first index) can be calculated as: .. highlight:: python @@ -549,7 +549,7 @@ Example: A Generic Grid ''''''''''''''''''''''' In this example variable zs is defined on a generic grid. Figure 2 -illustrates the grid, in this case a geodesic grid. +illustrates the grid, in this case a geodesic grid: .. doctest:: diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 7bb2ff40..5391f0d3 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -585,9 +585,9 @@ Overview To access a database: -#. Open a connection. The connect method opens a database connection. - connect takes a database URI and returns a database object: - ``db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` +#. Open a connection. The connect method opens a database connection. Connect takes a database URI and returns a database object: + ``db=cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` + #. Search the database, locating one or more datasets, variables, and/or other objects. @@ -870,7 +870,7 @@ In the next example, a portion of variable ‘ua’ is read from dataset Examples of Database Searches ----------------------------------- -In the following examples, db is the database opened with +In the following examples, db is the database opened with: :: @@ -937,7 +937,7 @@ This defaults to the database defined in environment variable for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): print entry.name, len(entry.getObject().getTime()) -**Example:** Find the total number of each type of object in the database +**Example:** Find the total number of each type of object in the database: :: @@ -1510,7 +1510,7 @@ Selectors ^^^^^^^^^ A selector is a specification of a region of data to be selected from a -variable. For example, the statement +variable. For example, the statement: :: @@ -1521,7 +1521,7 @@ means ‘select the values of variable v for time ‘1979-1-1’ and levels 1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are generally used to represent regions of space and time. -The form for using a selector is +The form for using a selector is: :: @@ -1529,7 +1529,7 @@ The form for using a selector is result = v(s) -where v is a variable and s is the selector. An equivalent form is +where v is a variable and s is the selector. An equivalent form is: :: @@ -1540,7 +1540,7 @@ where f is a file or dataset, and ‘varid’ is the string ID of a variable. A selector consists of a list of selector components. For example, the -selector +selector: :: diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 08d7592d..0b24defa 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -1,7 +1,7 @@ -Module: cdtime +Module: CdTime -------------- -Time types +Time Types ^^^^^^^^^^ .. highlight:: python :linenothreshold: 3 From f2e7feffa259f21b29dcc5cb8798880b864fa160 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 20 Mar 2018 15:44:51 -0700 Subject: [PATCH 063/239] Changes made to Chapters 1, 4, 5 and Appendix --- docs/source/conf.py | 4 +- docs/source/manual/cdms_1.rst | 19 +-- docs/source/manual/cdms_4.rst | 36 ++-- docs/source/manual/cdms_5.rst | 8 +- docs/source/manual/cdms_appendix.rst | 4 +- docs/source/manual/sample_data.rst | 244 +++++++++++++-------------- 6 files changed, 157 insertions(+), 158 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 248c3b80..2715fb80 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -102,9 +102,9 @@ # built documents. # # The short X.Y version. -version = '2.12' +version = '3.0' # The full version, including alpha/beta/rc tags. -release = '2.12' +release = '3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 49dfc9f3..e14bec95 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -8,8 +8,8 @@ The Community Data Management System is an object-oriented data management system, specialized for organizing multidimensional, gridded data used in climate analysis and simulation. -CDMS is implemented as part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT), which uses the Python language. The examples in +CDMS is implemented as part of the Climate Data +Analysis Tool (CDAT), which uses the Python language. The examples in this chapter assume some familiarity with the language and the Python Numpy module (http://www.numpy.org). A number of excellent tutorials on Python are available in books or on the Internet. For example, see @@ -33,7 +33,7 @@ velocity for time 0 (first index) can be calculated as: .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f1=cdms2.open("clt.nc") >>> u = f1('u') >>> v = f1('v') @@ -64,7 +64,7 @@ A variable can be obtained from a file or collection of files, or can be generated as the result of a computation. Files can be in any of the self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS control file), or PCMDI DRS. (HDF and DRS support is optional, and is -configured at the time UV-CDAT is installed.) For instance, to read data +configured at the time CDAT is installed.) For instance, to read data from file sample.nc into variable u: .. testsetup:: * @@ -81,7 +81,7 @@ from file sample.nc into variable u: largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + url = 'http://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -95,7 +95,7 @@ from file sample.nc into variable u: .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f = cdms2.open('clt.nc') >>> u = f('u') @@ -661,9 +661,9 @@ SCRIP Regridder To interpolate between any lat-lon grid types, the SCRIP regridder may be used. The SCRIP package was developed at [Los Alamos National -Laboratory](http://oceans11.lanl.gov/drupal/Models/OtherSoftware). +Laboratory] (http://oceans11.lanl.gov/drupal/Models/OtherSoftware). SCRIP is written in Fortran 90, and must be built and installed -separately from the UV-CDAT/CDMS installation. +separately from the CDAT/CDMS installation. The steps to regrid a variable are: @@ -789,8 +789,7 @@ Plotting data ^^^^^^^^^^^^^ Data read via the CDMS Python interface can be plotted using the vcs -module. This module, part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT) is documented in the VCS reference manual. The +module. This module, part of the Climate Data Analysis Tool (CDAT) is documented in the VCS reference manual. The vcs module provides access to the functionality of the VCS visualization program. diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index d16f72dd..5c734391 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -22,7 +22,7 @@ CDMS Horizontal Regrider import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + url = 'http://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -40,8 +40,8 @@ variable regridded to the target grid: .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" >>> import cdms2 >>> import cdat_info >>> f1=cdms2.open("clt.nc") @@ -73,8 +73,8 @@ is generated at line 9, and the regridding is performed at line 10: .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/clt.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" >>> import cdms2 >>> from regrid2 import Regridder >>> f = cdms2.open("clt.nc") @@ -198,15 +198,15 @@ generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ Total number of links = 63112 -Next, run UV-CDAT and create the regridder: +Next, run CDAT and create the regridder: .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" >>> # Import regrid package for regridder functions >>> import regrid2, cdms2 >>> # Read the regridder from the remapper file @@ -242,7 +242,7 @@ returns a new variable ``d`` regridded to that dimension. .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") >>> ta=f('ta') >>> ta.shape @@ -264,7 +264,7 @@ regridded to those axes. .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") >>> ta=f('ta') >>> ta.shape @@ -524,8 +524,8 @@ Get a mask from a separate file, and set as the input grid mask. .. doctest:: - >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/clt.nc - >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc + >>> # wget http://cdat.llnl.gov/cdat/sample_data/clt.nc + >>> # wget http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc >>> import cdms2 >>> from regrid2 import Regridder >>> # @@ -654,9 +654,9 @@ comparison. .. doctest:: - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" - >>> # wget http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc - >>> # wget "http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" >>> import cdms2, regrid2, MV2 >>> # Open the SCRIP remapping file and data file >>> fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc') diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 915817d6..9abdfc73 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -5,8 +5,8 @@ Overview ~~~~~~~~ Data read via the CDMS Python interface can be plotted using the ``vcs`` -module. This module, part of the Ultrascale Visualization Climate Data -Analysis Tool (UV-CDAT) is documented in the UV-CDAT reference manual. +module. This module, part of the Climate Data +Analysis Tool (CDAT) is documented in the CDAT reference manual. The ``vcs`` module provides access to the functionality of the VCS visualization program. @@ -134,7 +134,7 @@ variable. The result variable ``samp`` can be plotted directly: Plot Method ~~~~~~~~~~~ -The ``plot`` method is documented in the UV-CDAT Reference Manual. This +The ``plot`` method is documented in the CDAT Reference Manual. This section augments the documentation with a description of the optional keyword arguments. The general form of the plot command is: @@ -171,7 +171,7 @@ where: ``graphics_name``: the name of the specific graphics method ('default') - See the UV-CDAT Reference Manual and VCS Reference Manual for a + See the CDAT Reference Manual and VCS Reference Manual for a detailed description of these arguments. - ``key=value``, ... are optional keyword/value pairs, listed in any diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index a555dbc2..747ccd1b 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -62,7 +62,7 @@ Release 3.0 Overview CDMS version 3.0 is a significant enhancement of previous versions. The major changes were: -- UV-CDAT/CDMS was integrated with the Numpyal Python masked array +- CDAT/CDMS was integrated with the Numpyal Python masked array class MV2.MaskedVariable. The MV submodule was added as a wrapper around MV. - Methods that read data, such as subRegion, subSlice, and the slice @@ -179,7 +179,7 @@ APPENDIX C Module `cu` ~~~~~~~~~~~ -The ``cu`` module is the original UV-CDAT I/O interface. As of version 3 +The ``cu`` module is the original CDAT I/O interface. As of version 3 it is emulated in the ``cdms`` module. It is maintained for backward compatibility. diff --git a/docs/source/manual/sample_data.rst b/docs/source/manual/sample_data.rst index 649b0c14..7ab72453 100644 --- a/docs/source/manual/sample_data.rst +++ b/docs/source/manual/sample_data.rst @@ -1,125 +1,125 @@ CDMS Sample Dataset ------------------- -* http://uvcdat.llnl.gov/cdat/sample_data/161122_RobertPincus_multiple_input4MIPs_radiation_RFMIP_UColorado-RFMIP-20161122_none.nc -* http://uvcdat.llnl.gov/cdat/sample_data/20160520.A_WCYCL1850.ne30_oEC.edison.alpha6_01_ANN_climo_Q.nc -* http://uvcdat.llnl.gov/cdat/sample_data/area_weights.nc -* http://uvcdat.llnl.gov/cdat/sample_data/BlueMarble.ppm -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.001 -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.002 -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.003 -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.004 -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.005 -* http://uvcdat.llnl.gov/cdat/sample_data/CCTM_CONC.D1.001 -* http://uvcdat.llnl.gov/cdat/sample_data/cdtest10.xml -* http://uvcdat.llnl.gov/cdat/sample_data/cdtest13.xml -* http://uvcdat.llnl.gov/cdat/sample_data/cdtest14.xml -* http://uvcdat.llnl.gov/cdat/sample_data/clt2.nc -* http://uvcdat.llnl.gov/cdat/sample_data/clt.nc -* http://uvcdat.llnl.gov/cdat/sample_data/dar.meteo.mod.cam3.era.v31.h0.l3.nrstpt.cp.2000070100.2000080100.tau.12.36.nc -* http://uvcdat.llnl.gov/cdat/sample_data/dvtest1.dat -* http://uvcdat.llnl.gov/cdat/sample_data/dvtest1.dic -* http://uvcdat.llnl.gov/cdat/sample_data/era15_tas_sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/era40_sst_sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/era40_tas_sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/genutil_statistics.nc -* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.ctl -* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.gmp -* http://uvcdat.llnl.gov/cdat/sample_data/geo.1deg.grb -* http://uvcdat.llnl.gov/cdat/sample_data/geos5-sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.ctl -* http://uvcdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.data -* http://uvcdat.llnl.gov/cdat/sample_data/GPCP_ANN_climo.nc -* http://uvcdat.llnl.gov/cdat/sample_data/gpcp_cdr_v23rB1_y2016_m08.nc -* http://uvcdat.llnl.gov/cdat/sample_data/GRIDCRO2D_D1.001 -* http://uvcdat.llnl.gov/cdat/sample_data/hadcrut2_sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/junk.nc -* http://uvcdat.llnl.gov/cdat/sample_data/MERRA_ANN_climo_SHUM.nc -* http://uvcdat.llnl.gov/cdat/sample_data/meshfill.nc -* http://uvcdat.llnl.gov/cdat/sample_data/model_ANN_climo.nc -* http://uvcdat.llnl.gov/cdat/sample_data/navy_land.nc -* http://uvcdat.llnl.gov/cdat/sample_data/netcdf4_compressed_example.nc -* http://uvcdat.llnl.gov/cdat/sample_data/obs_timeseries.nc -* http://uvcdat.llnl.gov/cdat/sample_data/prcp_1951.nc -* http://uvcdat.llnl.gov/cdat/sample_data/psl_6h.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.0E.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.180E.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.180W.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ps.wrap.test.60E.nc -* http://uvcdat.llnl.gov/cdat/sample_data/readonly.nc -* http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc -* http://uvcdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc -* http://uvcdat.llnl.gov/cdat/sample_data/rlut_CERES_000001-000012_ac.nc -* http://uvcdat.llnl.gov/cdat/sample_data/rmp_C02562_to_T42_conserv.nc -* http://uvcdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc -* http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc -* http://uvcdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sampleCurveGrid4.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sampleGenGrid3.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sample.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sample_polar.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sftbyrgn.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_10x10.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_ccsr.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_dnm.nc -* http://uvcdat.llnl.gov/cdat/sample_data/sftlf_visus.nc -* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_ACCESS1-0_historical_r1i1p1_185001-185412_2timesteps.nc -* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_GISS-E2-R_historicalNat_r5i1p1_185001-187512_2timesteps.nc -* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_HadGEM2-CC_historical_r1i1p1_185912-186911_2timesteps.nc -* http://uvcdat.llnl.gov/cdat/sample_data/so_Omon_MPI-ESM-LR_1pctCO2_r1i1p1_185001-185912_2timesteps.nc -* http://uvcdat.llnl.gov/cdat/sample_data/stereographic.nc -* http://uvcdat.llnl.gov/cdat/sample_data/swan.four.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dat -* http://uvcdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dic -* http://uvcdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_6h.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1979.01-1979.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1980.01-1980.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1981.01-1981.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1982.01-1982.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1983.01-1983.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1984.01-1984.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ccsr-95a.xml -* http://uvcdat.llnl.gov/cdat/sample_data/tas_cru_1979.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1979.01-1979.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1980.01-1980.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1981.01-1981.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1982.01-1982.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1983.01-1983.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1984.01-1984.12.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_dnm-95a.xml -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ecm_1979.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_gavg_rnl_ecm.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_GFDL-ESM2G_Amon_historical_r1i1p1_198501-200512-clim.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_mo_clim.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_mo.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tas_ukmo_con.nc -* http://uvcdat.llnl.gov/cdat/sample_data/taylor.nc -* http://uvcdat.llnl.gov/cdat/sample_data/tdata.hdf -* http://uvcdat.llnl.gov/cdat/sample_data/test.2.bin -* http://uvcdat.llnl.gov/cdat/sample_data/test_anim.nc -* http://uvcdat.llnl.gov/cdat/sample_data/test.bin -* http://uvcdat.llnl.gov/cdat/sample_data/test.cdms -* http://uvcdat.llnl.gov/cdat/sample_data/test_col.asc -* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.ctl -* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.grib2 -* http://uvcdat.llnl.gov/cdat/sample_data/testgrib2.idx -* http://uvcdat.llnl.gov/cdat/sample_data/test_mesa_leak.nc -* http://uvcdat.llnl.gov/cdat/sample_data/testpp.pp -* http://uvcdat.llnl.gov/cdat/sample_data/test.xml -* http://uvcdat.llnl.gov/cdat/sample_data/thermo.nc -* http://uvcdat.llnl.gov/cdat/sample_data/th_yr.nc -* http://uvcdat.llnl.gov/cdat/sample_data/ts_da.nc -* http://uvcdat.llnl.gov/cdat/sample_data/u_2000.nc -* http://uvcdat.llnl.gov/cdat/sample_data/u_2001.nc -* http://uvcdat.llnl.gov/cdat/sample_data/u_2002.nc -* http://uvcdat.llnl.gov/cdat/sample_data/v_2000.nc -* http://uvcdat.llnl.gov/cdat/sample_data/v_2001.nc -* http://uvcdat.llnl.gov/cdat/sample_data/v_2002.nc -* http://uvcdat.llnl.gov/cdat/sample_data/vertical.nc -* http://uvcdat.llnl.gov/cdat/sample_data/vmro3_input4MIPs_ozone_DAMIP_CCMI-hist-stratO3-1-0_gr_185001_nco.nc -* http://uvcdat.llnl.gov/cdat/sample_data/wk_data.nc -* http://uvcdat.llnl.gov/cdat/sample_data/wk_results.nc -* http://uvcdat.llnl.gov/cdat/sample_data/wspd.coads.nc -* http://uvcdat.llnl.gov/cdat/sample_data/wspd.nc -* http://uvcdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc +* http://cdat.llnl.gov/cdat/sample_data/161122_RobertPincus_multiple_input4MIPs_radiation_RFMIP_UColorado-RFMIP-20161122_none.nc +* http://cdat.llnl.gov/cdat/sample_data/20160520.A_WCYCL1850.ne30_oEC.edison.alpha6_01_ANN_climo_Q.nc +* http://cdat.llnl.gov/cdat/sample_data/area_weights.nc +* http://cdat.llnl.gov/cdat/sample_data/BlueMarble.ppm +* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.001 +* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.002 +* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.003 +* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.004 +* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.005 +* http://cdat.llnl.gov/cdat/sample_data/CCTM_CONC.D1.001 +* http://cdat.llnl.gov/cdat/sample_data/cdtest10.xml +* http://cdat.llnl.gov/cdat/sample_data/cdtest13.xml +* http://cdat.llnl.gov/cdat/sample_data/cdtest14.xml +* http://cdat.llnl.gov/cdat/sample_data/clt2.nc +* http://cdat.llnl.gov/cdat/sample_data/clt.nc +* http://cdat.llnl.gov/cdat/sample_data/dar.meteo.mod.cam3.era.v31.h0.l3.nrstpt.cp.2000070100.2000080100.tau.12.36.nc +* http://cdat.llnl.gov/cdat/sample_data/dvtest1.dat +* http://cdat.llnl.gov/cdat/sample_data/dvtest1.dic +* http://cdat.llnl.gov/cdat/sample_data/era15_tas_sample.nc +* http://cdat.llnl.gov/cdat/sample_data/era40_sst_sample.nc +* http://cdat.llnl.gov/cdat/sample_data/era40_tas_sample.nc +* http://cdat.llnl.gov/cdat/sample_data/genutil_statistics.nc +* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.ctl +* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.gmp +* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.grb +* http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc +* http://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.ctl +* http://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.data +* http://cdat.llnl.gov/cdat/sample_data/GPCP_ANN_climo.nc +* http://cdat.llnl.gov/cdat/sample_data/gpcp_cdr_v23rB1_y2016_m08.nc +* http://cdat.llnl.gov/cdat/sample_data/GRIDCRO2D_D1.001 +* http://cdat.llnl.gov/cdat/sample_data/hadcrut2_sample.nc +* http://cdat.llnl.gov/cdat/sample_data/junk.nc +* http://cdat.llnl.gov/cdat/sample_data/MERRA_ANN_climo_SHUM.nc +* http://cdat.llnl.gov/cdat/sample_data/meshfill.nc +* http://cdat.llnl.gov/cdat/sample_data/model_ANN_climo.nc +* http://cdat.llnl.gov/cdat/sample_data/navy_land.nc +* http://cdat.llnl.gov/cdat/sample_data/netcdf4_compressed_example.nc +* http://cdat.llnl.gov/cdat/sample_data/obs_timeseries.nc +* http://cdat.llnl.gov/cdat/sample_data/prcp_1951.nc +* http://cdat.llnl.gov/cdat/sample_data/psl_6h.nc +* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.0E.nc +* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180E.nc +* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180W.nc +* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.60E.nc +* http://cdat.llnl.gov/cdat/sample_data/readonly.nc +* http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc +* http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc +* http://cdat.llnl.gov/cdat/sample_data/rlut_CERES_000001-000012_ac.nc +* http://cdat.llnl.gov/cdat/sample_data/rmp_C02562_to_T42_conserv.nc +* http://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc +* http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc +* http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc +* http://cdat.llnl.gov/cdat/sample_data/sampleCurveGrid4.nc +* http://cdat.llnl.gov/cdat/sample_data/sampleGenGrid3.nc +* http://cdat.llnl.gov/cdat/sample_data/sample.nc +* http://cdat.llnl.gov/cdat/sample_data/sample_polar.nc +* http://cdat.llnl.gov/cdat/sample_data/sftbyrgn.nc +* http://cdat.llnl.gov/cdat/sample_data/sftlf_10x10.nc +* http://cdat.llnl.gov/cdat/sample_data/sftlf_ccsr.nc +* http://cdat.llnl.gov/cdat/sample_data/sftlf_dnm.nc +* http://cdat.llnl.gov/cdat/sample_data/sftlf_visus.nc +* http://cdat.llnl.gov/cdat/sample_data/so_Omon_ACCESS1-0_historical_r1i1p1_185001-185412_2timesteps.nc +* http://cdat.llnl.gov/cdat/sample_data/so_Omon_GISS-E2-R_historicalNat_r5i1p1_185001-187512_2timesteps.nc +* http://cdat.llnl.gov/cdat/sample_data/so_Omon_HadGEM2-CC_historical_r1i1p1_185912-186911_2timesteps.nc +* http://cdat.llnl.gov/cdat/sample_data/so_Omon_MPI-ESM-LR_1pctCO2_r1i1p1_185001-185912_2timesteps.nc +* http://cdat.llnl.gov/cdat/sample_data/stereographic.nc +* http://cdat.llnl.gov/cdat/sample_data/swan.four.nc +* http://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dat +* http://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dic +* http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_6h.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1979.01-1979.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1980.01-1980.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1981.01-1981.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1982.01-1982.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1983.01-1983.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1984.01-1984.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a.xml +* http://cdat.llnl.gov/cdat/sample_data/tas_cru_1979.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1979.01-1979.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1980.01-1980.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1981.01-1981.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1982.01-1982.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1983.01-1983.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1984.01-1984.12.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a.xml +* http://cdat.llnl.gov/cdat/sample_data/tas_ecm_1979.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_gavg_rnl_ecm.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_GFDL-ESM2G_Amon_historical_r1i1p1_198501-200512-clim.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_mo_clim.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_mo.nc +* http://cdat.llnl.gov/cdat/sample_data/tas_ukmo_con.nc +* http://cdat.llnl.gov/cdat/sample_data/taylor.nc +* http://cdat.llnl.gov/cdat/sample_data/tdata.hdf +* http://cdat.llnl.gov/cdat/sample_data/test.2.bin +* http://cdat.llnl.gov/cdat/sample_data/test_anim.nc +* http://cdat.llnl.gov/cdat/sample_data/test.bin +* http://cdat.llnl.gov/cdat/sample_data/test.cdms +* http://cdat.llnl.gov/cdat/sample_data/test_col.asc +* http://cdat.llnl.gov/cdat/sample_data/testgrib2.ctl +* http://cdat.llnl.gov/cdat/sample_data/testgrib2.grib2 +* http://cdat.llnl.gov/cdat/sample_data/testgrib2.idx +* http://cdat.llnl.gov/cdat/sample_data/test_mesa_leak.nc +* http://cdat.llnl.gov/cdat/sample_data/testpp.pp +* http://cdat.llnl.gov/cdat/sample_data/test.xml +* http://cdat.llnl.gov/cdat/sample_data/thermo.nc +* http://cdat.llnl.gov/cdat/sample_data/th_yr.nc +* http://cdat.llnl.gov/cdat/sample_data/ts_da.nc +* http://cdat.llnl.gov/cdat/sample_data/u_2000.nc +* http://cdat.llnl.gov/cdat/sample_data/u_2001.nc +* http://cdat.llnl.gov/cdat/sample_data/u_2002.nc +* http://cdat.llnl.gov/cdat/sample_data/v_2000.nc +* http://cdat.llnl.gov/cdat/sample_data/v_2001.nc +* http://cdat.llnl.gov/cdat/sample_data/v_2002.nc +* http://cdat.llnl.gov/cdat/sample_data/vertical.nc +* http://cdat.llnl.gov/cdat/sample_data/vmro3_input4MIPs_ozone_DAMIP_CCMI-hist-stratO3-1-0_gr_185001_nco.nc +* http://cdat.llnl.gov/cdat/sample_data/wk_data.nc +* http://cdat.llnl.gov/cdat/sample_data/wk_results.nc +* http://cdat.llnl.gov/cdat/sample_data/wspd.coads.nc +* http://cdat.llnl.gov/cdat/sample_data/wspd.nc +* http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc From 65943ffa4f53a23afc4686a86fdd4d3bc2022e47 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 23 Mar 2018 09:45:46 -0700 Subject: [PATCH 064/239] Some changes to Chapter 2 and 4 --- docs/source/manual/cdms_2.rst | 14 ++++++++++++-- docs/source/manual/cdms_4.rst | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 5391f0d3..9afc9328 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -5,6 +5,7 @@ Overview ^^^^^^^^ + .. highlight:: python :linenothreshold: 3 @@ -648,6 +649,8 @@ Table Database Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 + :align: left + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." @@ -989,7 +992,7 @@ Table Open Modes .. csv-table:: :header: "Mode", "Definition" - :widths: 50, 80 + :widths: 50, 70 :align: left "‘r’", "read-only" @@ -1189,7 +1192,8 @@ Table HorizontalGrid Internal Attribute .. csv-table:: :header: "Type", "Name", "Definition" - :widths: 30, 30, 80 + :widths: 30, 30, 100 + :align: left "Dictionary","``attributes``", "External attribute dictionary." "String", "``id``", "The grid identifier." @@ -1206,6 +1210,8 @@ Table RectGrid Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 + :align: left + "``cdms.createRectGrid(lat, lon, order, type='generic', mask=None)``", "Create a grid not associated with a file or dataset. See `A First Example`_" "``CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None)``", "Create a grid associated with a file. See `CdmsFile Constructors <#table-cdmsfile-constructors>`_" @@ -1338,6 +1344,8 @@ Table Variable Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 30, 80 + :align: left + "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." @@ -1352,6 +1360,8 @@ Table Variable Methods .. csv-table:: :header: "Type", "Method", "Definition" :widths: 30, 30, 180 + :align: left + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 5c734391..62655945 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -1,6 +1,7 @@ Regridding Data --------------- + Overview ^^^^^^^^ @@ -507,7 +508,7 @@ Table Regridder Constructure .. csv-table:: :header: "Line", "Notes" - :widths: 8, 90 + :widths: 8, 45 "3", "Open a netCDF file for input." "6", "Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset." From 08ca15c5665c7f2f0947c0ab671747306fe7f6a4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 26 Mar 2018 14:29:26 -0700 Subject: [PATCH 065/239] Some Changes to Images, Chapter 3 and Appendix --- docs/source/manual/cdms_3.rst | 2 +- docs/source/manual/cdms_appendix.rst | 20 ++++++++++++++++++ docs/source/manual/docs/cdms_quick_start.pdf | Bin 0 -> 7727 bytes .../source/manual/images/cdms_quick_start.jpg | Bin 0 -> 529184 bytes 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 docs/source/manual/docs/cdms_quick_start.pdf create mode 100644 docs/source/manual/images/cdms_quick_start.jpg diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 0b24defa..8c2f973d 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -24,7 +24,7 @@ Time Types The ``cdtime`` module implements the CDMS time types, methods, and -calendars. These are made available with the command +calendars. These are made available with the command: .. doctest:: diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 747ccd1b..af76da90 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -35,9 +35,29 @@ as identical. FIGURE 1. CDMS Classes + + APPENDIX B ---------- +Quick Start (Cheat Sheet) +~~~~~~~~~~~~~~~~~~~~~~~~~ +.. figure:: /manual/images/cdms_quick_start.jpg + :scale: 25% + :alt: cheat sheet + +:download:`cdms quick start ` + + +VCS Quick Reference (Cheat Sheet) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. figure:: /manual/images/vcs_quick_ref.jpg + :scale: 25% + :alt: VCS Cheat Sheet + + + Release Notes ~~~~~~~~~~~~~ diff --git a/docs/source/manual/docs/cdms_quick_start.pdf b/docs/source/manual/docs/cdms_quick_start.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b87cbcf9b1af84374c5a199a60748b341611a6dc GIT binary patch literal 7727 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%0Dadg548Hw3Bc5#us<51;z|)jVxrQ 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%0AqU9A5;b@ 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 FW1yzE(n+W-j|Th)LsZhO`Kn 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≪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 M27bao#E&=s0w-^i Date: Wed, 28 Mar 2018 12:29:04 -0700 Subject: [PATCH 066/239] update logo --- docs/source/conf.py | 2 +- docs/source/manual/cdms_2.rst | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2715fb80..1421ad32 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -182,7 +182,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'manual/images/uvcdat.png' +html_logo = 'manual/images/cdms_logo2_nocube.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 9afc9328..a6e1fb21 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -219,7 +219,6 @@ Table Cdms Module Functions , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." -: @@ -1199,8 +1198,6 @@ Table HorizontalGrid Internal Attribute "String", "``id``", "The grid identifier." "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." "Tuple", "``shape``", "The shape of the grid, a 2-tuple" -:: - From a62a8fa480b5fc3d8920dff7b288768347f36bc9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 28 Mar 2018 12:36:57 -0700 Subject: [PATCH 067/239] add my logo --- docs/source/manual/images/cdms_logo2_nocube.png | Bin 0 -> 17386 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/manual/images/cdms_logo2_nocube.png diff --git a/docs/source/manual/images/cdms_logo2_nocube.png b/docs/source/manual/images/cdms_logo2_nocube.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba6a2a2dd3c2893154b04919c66443c22a147b4 GIT binary patch literal 17386 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 Date: Wed, 28 Mar 2018 12:49:15 -0700 Subject: [PATCH 068/239] fix chapter 1 test --- docs/source/manual/cdms_1.rst | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index e14bec95..33a2d191 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -681,27 +681,27 @@ The steps to regrid a variable are: Steps 1 and 2 need only be done once. The regridder can be used as often as necessary. -#For example, suppose the source data on a T42 grid is to be mapped to a -#POP curvilinear grid. Assume that SCRIP generated a remapping file named -#rmp_T42_to_POP43_conserv.nc: -# -#.. doctest:: -# -# >>> # Import regrid package for regridder functions -# >>> import regrid2, cdms2 -# -# >>> # Get the source variable -# >>> f = cdms2.open('sampleT42Grid.nc') -# >>> dat = f('src_array') -# >>> f.close() -# -# >>> # Read the regridder from the remapper file -# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') -# >>> regridf = regrid2.readRegridder(remapf) -# >>> remapf.close() -# -# >>> # Regrid the source variable -# >>> popdat = regridf(dat) +For example, suppose the source data on a T42 grid is to be mapped to a +POP curvilinear grid. Assume that SCRIP generated a remapping file named +rmp_T42_to_POP43_conserv.nc: + +.. doctest:: + + >>> # Import regrid package for regridder functions + >>> import regrid2, cdms2 + + >>> # Get the source variable + >>> f = cdms2.open('sampleT42Grid.nc') + >>> dat = f('src_array') + >>> f.close() + + >>> # Read the regridder from the remapper file + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> remapf.close() + + >>> # Regrid the source variable + >>> popdat = regridf(dat) Regridding is discussed in `Chapter 4 `__. From 56c41b6a4e4d7afbd40e9919a16489d8ea77c372 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 28 Mar 2018 15:51:27 -0700 Subject: [PATCH 069/239] Some changes made to Chapters 2, 3 and 5 --- docs/source/manual/cdms_2.rst | 6 +++--- docs/source/manual/cdms_3.rst | 2 +- docs/source/manual/cdms_5.rst | 2 +- docs/source/manual/cdms_appendix.rst | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 9afc9328..f4f509a4 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -14,7 +14,7 @@ Overview import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + url = 'http://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -531,7 +531,7 @@ Table CdmsFile Methods ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." ,,"* ``id`` is the variable name in the file. Default is ``var.id``." ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." - ,," * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." + ,,"* The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." ,,"* ``fill_value`` is the missing value flag." ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." @@ -1593,7 +1593,7 @@ Table Selector Keywords "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" - "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." + "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); = 1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 8c2f973d..bfe61522 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -11,7 +11,7 @@ Time Types import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + url = 'http://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 9abdfc73..0f96d4ec 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -30,7 +30,7 @@ Plotting a Gridded Variable import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://uvcdat.llnl.gov/cdat/sample_data/'+file + url = 'http://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index af76da90..39d14d18 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -56,7 +56,7 @@ VCS Quick Reference (Cheat Sheet) :scale: 25% :alt: VCS Cheat Sheet - +:download:`vcs quick ref ` Release Notes ~~~~~~~~~~~~~ From 35c14371f99d6a10ed29edef272ceae8a56a3082 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 29 Mar 2018 15:42:51 -0700 Subject: [PATCH 070/239] Some Changes to Chapters 1 and 2 --- docs/source/manual/cdms_1.rst | 375 ++++++++++---------- docs/source/manual/cdms_2.rst | 641 +++++++++++++++++----------------- 2 files changed, 515 insertions(+), 501 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index e14bec95..2e9c402a 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -31,8 +31,10 @@ velocity for time 0 (first index) can be calculated as: .. highlight:: python -.. doctest:: + +.. doctest:: + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f1=cdms2.open("clt.nc") >>> u = f1('u') @@ -103,7 +105,7 @@ Data can be read by index or by world coordinate values. The following reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k such that i <= k < j): -.. doctest:: +.. doctest:: >>> n = 0 >>> u0 = f('u',time=slice(n,n+1)) @@ -116,11 +118,11 @@ To read ``u`` at time 1.: A variable can be written to a file with the write function: -.. doctest:: +.. >>> g = cdms2.open('sample2.nc','w') >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >> >> g.close() Coordinate Axes @@ -144,52 +146,52 @@ latitude, longitude). This indicates the order of the dimensions, with the slowest-varying dimension listed first (time). The domain may be accessed with the ``getAxisList()`` method: -.. doctest:: +.. >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - [ id: time1 - Designated a time axis. - units: months since 1978-12 - Length: 1 - First: 1.0 - Last: 1.0 - Other axis attributes: - calendar: gregorian - axis: T - Python id: ... - , id: plev - Designated a level axis. - units: hPa - Length: 2 - First: 200.0 - Last: 850.0 - Other axis attributes: - axis: Z - realtopology: linear - Python id: ... - , id: latitude1 - Designated a latitude axis. - units: degrees_north - Length: 80 - First: -88.2884 - Last: 88.2884 - Other axis attributes: - axis: Y - realtopology: linear - Python id: ... - , id: longitude1 - Designated a longitude axis. - units: degrees_east - Length: 97 - First: -180.0 - Last: 180.0 - Other axis attributes: - axis: X - topology: circular - modulo: 360.0 - realtopology: linear - Python id: ... - ] + >>> [ id: time1 + >>> Designated a time axis. + >>> units: months since 1978-12 + >>> Length: 1 + >>> First: 1.0 + >>> Last: 1.0 + >>> Other axis attributes: + >>> calendar: gregorian + >>> axis: T + >>> Python id: ... + >>> , id: plev + >>> Designated a level axis. + >>> units: hPa + >>> Length: 2 + >>> First: 200.0 + >>> Last: 850.0 + >>> Other axis attributes: + >>> axis: Z + >>> realtopology: linear + >>> Python id: ... + >>> , id: latitude1 + >>> Designated a latitude axis. + >>> units: degrees_north + >>> Length: 80 + >>> First: -88.2884 + >>> Last: 88.2884 + >>> Other axis attributes: + >>> axis: Y + >>> realtopology: linear + >>> Python id: ... + >>> , id: longitude1 + >>> Designated a longitude axis. + >>> units: degrees_east + >>> Length: 97 + >>> First: -180.0 + >>> Last: 180.0 + >>> Other axis attributes: + >>> axis: X + >>> topology: circular + >>> modulo: 360.0 + >>> realtopology: linear + >>> Python id: ... + >>> ] In the above example, the domain elements are axes that are also @@ -208,13 +210,13 @@ associated with a variable. The methods getLatitude, getLongitude, getLevel, and getTime return the associated coordinate axes. For example: -.. doctest:: +.. >>> t = u.getTime() >>> print t[:] - [ 1.] + >>> [ 1.] >>> print t.units - months since 1978-12 + >>> months since 1978-12 Attributes ^^^^^^^^^^ @@ -223,11 +225,10 @@ As mentioned above, variables can have associated attributes , name-value pairs. In fact, nearly all CDMS objects can have associated attributes, which are accessed using the Python dot notation: -.. doctest:: - - >>> u.units='m/s' - >>> print u.units - m/s +.. + >>> u.units='m/s' + >>> print u.units + >>> m/s Attribute values can be strings, scalars, or 1-D Numpy arrays. @@ -239,17 +240,17 @@ written to an output file along with the variable. By default, when an attribute is set, it is treated as external. Every variable has a field attributes, a Python dictionary that defines the external attributes: -.. doctest:: +.. >>> print u.attributes.keys() - ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] + >>> ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] The Python dir command lists the internal attribute names: -.. doctest:: +.. >>> dir(u) - ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] + >>> ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] In general internal attributes should not be modified directly. One exception is the id attribute, the name of the variable. It is used in @@ -266,25 +267,24 @@ corresponding data array element is missing or invalid. Arithmetic operations in CDMS take missing data into account. The same is true of the functions defined in the cdms2.MV2 module. For example: -.. doctest:: +.. >>> a = MV2.array([1,2,3]) # Create array a, with no mask >>> b = MV2.array([4,5,6]) # Same for b >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - variable_... - masked_array(data = [5 7 9], - mask = False, - fill_value = 999999) - - + >>> variable_... + >>> masked_array(data = [5 7 9], + >>> mask = False, + >>> fill_value = 999999) + >>> >>> a[1]=MV2.masked # Mask the second value of a a.mask() >>> a.mask - array([False, True, False], dtype=bool) + >>> array([False, True, False], dtype=bool) >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - variable_... - masked_array(data = [5 -- 9], - mask = [False True False], - fill_value = 999999) + >>> variable_... + >>> masked_array(data = [5 -- 9], + >>> mask = [False True False], + >>> fill_value = 999999) @@ -327,11 +327,11 @@ passing the name of the variable, or by calling the getVariable function. Note that obtaining a file variable does not actually read the data array: -.. doctest:: +.. >>> u = f.getVariable('u') # or u=f['u'] >>> u.shape - (1, 2, 80, 97) + >>> (1, 2, 80, 97) File variables are also useful for fine-grained I/O. They behave like transient variables, but operations on them also affect the associated @@ -344,21 +344,21 @@ file. Specifically: - and calling a file variable like a function reads data associated with the variable: -.. doctest:: - +.. + >>> import os >>> os.system("cp clt.nc /tmp") - 0 + >>> 0 >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write >>> uvar = f['u'] # Note square brackets >>> uvar.shape - (1, 2, 80, 97) + >>>(1, 2, 80, 97) >>> u0 = uvar[0] # Reads data from sample.nc >>> u0.shape - (2, 80, 97) + >>> (2, 80, 97) >>> uvar[1]=u0 # Writes data to sample.nc >>> uvar.units # Reads the attribute 'm/s' - 'm/s' + >>> 'm/s' >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data >>> f.close() # Save changes to clt.nc (I/O may be buffered) @@ -367,40 +367,42 @@ For transient variables, the data is printed only if the size of the array is le than the print limit . This value can be set with the function MV.set_print_limit to force the data to be printed: -.. doctest:: +.. + >>> MV2.get_print_limit() # Current limit 1000 - 1000 + >>> 1000 >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - small variable - masked_array(data = - [[ 0. 1. 2. 3. 4.] - [ 5. 6. 7. 8. 9.] - [ 10. 11. 12. 13. 14.] - [ 15. 16. 17. 18. 19.]], - mask = - False, - fill_value = 999999.0) + >>> small variable + >>> masked_array(data = + >>> [[ 0. 1. 2. 3. 4.] + >>> [ 5. 6. 7. 8. 9.] + >>> [ 10. 11. 12. 13. 14.] + >>> [ 15. 16. 17. 18. 19.]], + >>> mask = + >>> False, + >>> fill_value = 999999.0) >>> MV2.set_print_limit(100) >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - large variable - masked_array(data = - [[ 0. 1. 2. ..., 17. 18. 19.] - [ 20. 21. 22. ..., 37. 38. 39.] - [ 40. 41. 42. ..., 57. 58. 59.] - ..., - [ 340. 341. 342. ..., 357. 358. 359.] - [ 360. 361. 362. ..., 377. 378. 379.] - [ 380. 381. 382. ..., 397. 398. 399.]], - mask = False, - fill_value = 999999.0) + >>> large variable + >>> masked_array(data = + >>> [[ 0. 1. 2. ..., 17. 18. 19.] + >>> [ 20. 21. 22. ..., 37. 38. 39.] + >>> [ 40. 41. 42. ..., 57. 58. 59.] + >>> ..., + >>> [ 340. 341. 342. ..., 357. 358. 359.] + >>> [ 360. 361. 362. ..., 377. 378. 379.] + >>> [ 380. 381. 382. ..., 397. 398. 399.]], + >>> mask = False, + >>> fill_value = 999999.0) The datatype of the variable is determined with the typecode function: -.. doctest:: +.. + - >>> u.typecode() - 'f' + >>> u.typecode() + >>> 'f' Dataset Variables ^^^^^^^^^^^^^^^^^ @@ -428,15 +430,15 @@ A metafile can be generated with the command: The metafile **cdsample.xml** is then used like an ordinary data file: -.. doctest:: +.. >>> import os >>> os.system("cdscan -x cdsample.xml [uv]*.nc") - 0 + >>> 0 >>> f = cdms2.open('cdsample.xml') >>> u = f('u') >>> u.shape - (3, 16, 32) + >>> (3, 16, 32) Grids ^^^^^^^^ @@ -481,64 +483,64 @@ grid. Note that: lon ), each a two-dimensional coordinate axis. - lat and lon each have domain ( y , x ) -.. doctest:: +.. >>> f = cdms2.open('sampleCurveGrid4.nc') - - + >>> >>> # lat and lon are coordinate axes, but are grouped with data variables >>> f.variables.keys() - ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] - + >>> ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + >>> >>> # y and x are index coordinate axes >>> f.axes.keys() - ['nvert', 'x', 'y'] - + >>> ['nvert', 'x', 'y'] + >>> >>> # Read data for variable sample >>> sample = f('sample') - + >>> >>> # The associated grid g is curvilinear >>> g = sample.getGrid() - + >>> >>> # The domain of the variable consfigists of index axes >>> sample.getAxisIds() - ['y', 'x'] - + >>> ['y', 'x'] + >>> >>> # Get the coordinate axes associated with the grid >>> lat = g.getLatitude() # or sample.getLatitude() >>> lon = g.getLongitude() # or sample.getLongitude() - + >>> >>> # lat and lon have the same domain, a subset of the domain of 'sample' >>> lat.getAxisIds() - ['y', 'x'] - + >>> ['y', 'x'] + >>> >>> # lat and lon are variables ... >>> lat.shape - (32, 48) - + >>> (32, 48) + >>> >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - lat - masked_array(data = - [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 - -76.08465554] - [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 - -73.92641847] - [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 - -71.44420823] - ..., - [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 - 42.32854943] - [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 - 42.70106429] - [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 - 43.0307341 ]], - mask = - False, - fill_value = 1e+20) - + >>> lat + >>> masked_array(data = + >>> [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 + >>> -76.08465554] + >>> [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 + >>> -73.92641847] + >>> [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 + >>> -71.44420823] + >>> ..., + >>> [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 + >>> 42.32854943] + >>> [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 + >>> 42.70106429] + >>> [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 + >>> 43.0307341 ]], + >>> mask = + >>> False, + >>> fill_value = 1e+20) + >>> >>> lat_in_radians = lat*MV2.pi/180.0 -.. figure:: images/curvilinear_grid.jpg + + .. figure:: images/curvilinear_grid.jpg :alt: curvilinear grid Figure 1: Curvilinear Grid @@ -551,38 +553,42 @@ Example: A Generic Grid In this example variable zs is defined on a generic grid. Figure 2 illustrates the grid, in this case a geodesic grid: -.. doctest:: +.. >>> f.variables.keys() - ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + >>> ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] >>> f.axes.keys() - ['nvert', 'x', 'y'] + >>> ['nvert', 'x', 'y'] >>> zs = f('sample') >>> g = zs.getGrid() >>> g - + >>> >>> lat = g.getLatitude() >>> lon = g.getLongitude() >>> lat.shape - (32, 48) + >>> (32, 48) >>> lon.shape # variable zs is defined in terms of a single index coordinate - (32, 48) + >>> (32, 48) >>> # axis, 'cell' >>> zs.shape - (32, 48) + >>> (32, 48) >>> zs.getAxisIds() - ['y', 'x'] - + >>> ['y', 'x'] + >>> >>> # lat and lon are also defined in terms of the cell axis >>> lat.getAxisIds() - ['y', 'x'] - + >>> ['y', 'x'] + >>> >>> # lat and lon are one-dimensional, 'auxiliary' coordinate >>> # axes: values are not monotonic >>> lat.__class__ - + + + + + .. figure:: images/generic_grid.jpg :alt: generic grid @@ -594,18 +600,20 @@ representation. Similarly, a rectangular grid can be represented as curvilinear. The method toCurveGrid is used to convert a non-generic grid to curvilinear representation: -.. doctest:: * +.. >>> f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc') >>> clt = f('clt') >>> rectgrid = clt.getGrid() >>> rectgrid.shape - (46, 72) + >>> (46, 72) >>> curvegrid = rectgrid.toCurveGrid() >>> curvegrid - + >>> >>> genericgrid = curvegrid.toGenericGrid() >>> genericgrid + + Regridding @@ -634,27 +642,27 @@ a rectangular grid) to a 96x192 rectangular Gaussian grid: >>> f = cdms2.open('clt.nc') >>> u = f('u') >>> u.shape - (1, 2, 80, 97) + >>> (1, 2, 80, 97) >>> t63_grid = cdms2.createGaussianGrid(96) >>> u63 = u.regrid(t63_grid) >>> u63.shape - (1, 2, 96, 192) + >>> (1, 2, 96, 192) To regrid a variable ``uold`` to the same grid as variable ``vnew``: -.. doctest:: +.. doctest:: >>> f = cdms2.open('clt.nc') >>> uold = f('u') >>> unew = f2('uwnd') >>> uold.shape - (1, 2, 80, 97) + >>> (1, 2, 80, 97) >>> unew.shape - (1, 14, 181, 360) + >>> (1, 14, 181, 360) >>> t63_grid = unew.getGrid() # Obtain the grid for vnew >>> u63 = u.regrid(t63_grid) >>> u63.shape - (1, 2, 181, 360) + >>> (1, 2, 181, 360) SCRIP Regridder ''''''''''''''' @@ -684,24 +692,25 @@ as necessary. #For example, suppose the source data on a T42 grid is to be mapped to a #POP curvilinear grid. Assume that SCRIP generated a remapping file named #rmp_T42_to_POP43_conserv.nc: -# -#.. doctest:: -# -# >>> # Import regrid package for regridder functions -# >>> import regrid2, cdms2 -# -# >>> # Get the source variable -# >>> f = cdms2.open('sampleT42Grid.nc') -# >>> dat = f('src_array') -# >>> f.close() -# -# >>> # Read the regridder from the remapper file -# >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') -# >>> regridf = regrid2.readRegridder(remapf) -# >>> remapf.close() -# -# >>> # Regrid the source variable -# >>> popdat = regridf(dat) + + +.. doctest:: + + >>> # Import regrid package for regridder functions + >>> import regrid2, cdms2 + >>> + >>> # Get the source variable + >>> f = cdms2.open('sampleT42Grid.nc') + >>> dat = f('src_array') + >>> f.close() + >>> + >>> # Read the regridder from the remapper file + >>> remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc') + >>> regridf = regrid2.readRegridder(remapf) + >>> remapf.close() + >>> + >>> # Regrid the source variable + >>> popdat = regridf(dat) Regridding is discussed in `Chapter 4 `__. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index f4f509a4..285ccc7f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -71,7 +71,7 @@ data from an input dataset, averages over time, and writes the results to an output file. The input temperature data is ordered (time, latitude, longitude). -.. doctest:: +.. >>> import cdms2, cdat_info >>> from cdms2 import MV @@ -87,9 +87,9 @@ latitude, longitude). >>> julyavg.long_name = "mean July surface temperature" >>> out = cdms2.open('janjuly.nc','w') >>> out.write(janavg) - >> >> out.write(julyavg) - >> >> out.comment = "Average January/July from Jones dataset" >>> jones.close() >>> out.close() @@ -120,17 +120,17 @@ Cdms Module The cdms module is the Python interface to CDMS. The objects and methods in this chapter are made accessible with the command: -.. doctest:: +.. - import cdms2 + >>> import cdms2 The functions described in this section are not associated with a class. Rather, they are called as module functions, e.g., -.. doctest:: +.. - file = cdms2.open('sample.nc') + >>> fle = cdms2.open('sample.nc') @@ -255,9 +255,9 @@ external attributes are written, but not the internal attributes. **Example**: get a list of all external attributes of obj. -.. doctest:: +.. - extatts = obj.attributes.keys() + >>> extatts = obj.attributes.keys() Table Attributes Common to All CDMS Objects ------------------------------------------- @@ -446,12 +446,12 @@ Table Axis Slice Operators Example 1 ''''''''''' -.. doctest:: +.. >>> axis.isCircular() - 1 + >>> 1 >>> axis.mapIntervalExt((-5.0,5.0,'co')) - (-2,3,1) + >>> (-2,3,1) @@ -713,14 +713,14 @@ For example: :: - (id = ncep*) - (project = AMIP2) + >>> id= ncep*) + >>> (project = AMIP2) **Note** Simple filters can be combined with the logical operators '&', '|', '!'. For example, :: - (&(id = bmrc*)(project = AMIP2)) + >>> (&(id = bmrc*)(project = AMIP2)) matches all objects with id starting with bmrc, and a project attribute @@ -730,23 +730,23 @@ Formally, search filters are strings defined as follows: :: - filter ::= "(" filtercomp ")" - - filtercomp ::= "&" filterlist | # and - "|" filterlist | # or - "!" filterlist | # not - simple - - filterlist ::= filter | filter filterlist - simple ::= tag op value - op ::= "=" | # equality - - "~=" | # approximate equality - "<=" | # lexicographically less than or equal to - ">=" # lexicographically greater than or equal to - - tag ::= string attribute name - value ::= string attribute value, may include '*' as a wild card + >>> filter ::= "(" filtercomp ")" + >>> + >>> filtercomp ::= "&" filterlist | # and + >>> "|" filterlist | # or + >>> "!" filterlist | # not + >>> simple + >>> + >>> filterlist ::= filter | filter filterlist + >>> simple ::= tag op value + >>> op ::= "=" | # equality + >>> + >>> "~=" | # approximate equality + >>> "<=" | # lexicographically less than or equal to + >>> ">=" # lexicographically greater than or equal to + >>> + >>> tag ::= string attribute name + >>> value ::= string attribute value, may include '*' as a wild card Attribute names are defined in the chapter on “Climate Data Markup @@ -777,9 +777,9 @@ several ways: :: - result = db.searchFilter('(&(category=obs*)(id=ncep*))') - for entry in result: - print entry.name + >>> result = db.searchFilter('(&(category=obs*)(id=ncep*))') + >>> for entry in result: + >>> print entry.name Search results can be narrowed using ``searchPredicate``. In the following example, the result of one search is itself searched for all @@ -789,22 +789,22 @@ variables defined on a 94x192 grid: >>> result = db.searchFilter('parentid=ncep*',tag="variable") >>> len(result) - 65 + >>> 65 >>> result2 = result.searchPredicate(lambda x: - - x.getGrid().shape==(94,192)) + >>> + >>> x.getGrid().shape==(94,192)) >>> len(result2) - 3 + >>> 3 >>> for entry in result2: print entry.name - variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US - variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US - variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, - - o=LLNL, c=US + >>> variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + >>> + >>> o=LLNL, c=US + >>> variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + >>> + >>> o=LLNL, c=US + >>> variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + >>> + >>> o=LLNL, c=US @@ -865,9 +865,9 @@ In the next example, a portion of variable ‘ua’ is read from dataset :: - dset = db.open('ncep_reanalysis_mo') - ua = dset.variables['ua'] - data = ua[0,0] + >>> dset = db.open('ncep_reanalysis_mo') + >>> ua = dset.variables['ua'] + >>> data = ua[0,0] Examples of Database Searches @@ -877,7 +877,7 @@ In the following examples, db is the database opened with: :: - db = cdms.connect() + >>> db = cdms.connect() This defaults to the database defined in environment variable ``CDMSROOT``. @@ -886,68 +886,68 @@ This defaults to the database defined in environment variable :: - for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): - print entry.name + >>> for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): + >>> print entry.name **Example:** Find all axes with bounds defined: :: - for entry in db.searchFilter(filter="bounds=*",tag="axis"): - print entry.name + >>> for entry in db.searchFilter(filter="bounds=*",tag="axis"): + >>> print entry.name **Example:** Locate all GDT datasets: :: - for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): - print entry.name + >>> for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + >>> print entry.name **Example:** Find all variables with missing time values, in observed datasets: :: - def missingTime(obj): - time = obj.getTime() - return time.length != time.partition_length + >>> def missingTime(obj): + >>> time = obj.getTime() + >>> return time.length != time.partition_length - result = db.searchFilter(filter="category=observed") - for entry in result.searchPredicate(missingTime): - print entry.name + >>> result = db.searchFilter(filter="category=observed") + >>> for entry in result.searchPredicate(missingTime): + >>> print entry.name **Example:** Find all CMIP2 datasets having a variable with id “hfss”: :: - for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): - print entry.getObject().parent.id + >>> for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): + >>> print entry.getObject().parent.id **Example:** Find all observed variables on 73x144 grids: :: - result = db.searchFilter(category='obs*') - for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): - print entry.name + >>> result = db.searchFilter(category='obs*') + >>> for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): + >>> print entry.name **Example:** Find all observed variables with more than 1000 timepoints: :: - result = db.searchFilter(category='obs*') - for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): - print entry.name, len(entry.getObject().getTime()) + >>> result = db.searchFilter(category='obs*') + >>> for entry in result.searchPredicate(lambda x: len(x.getTime())>1000, tag = "variable"): + >>> print entry.name, len(entry.getObject().getTime()) **Example:** Find the total number of each type of object in the database: :: - print len(db.searchFilter(tag="database")),"database" - print len(db.searchFilter(tag="dataset")),"datasets" - print len(db.searchFilter(tag="variable")),"variables" - print len(db.searchFilter(tag="axis")),"axes" + >>> print len(db.searchFilter(tag="database")),"database" + >>> print len(db.searchFilter(tag="dataset")),"datasets" + >>> print len(db.searchFilter(tag="variable")),"variables" + >>> print len(db.searchFilter(tag="axis")),"axes" Dataset @@ -1060,13 +1060,13 @@ MV can be imported with the command: :: - import MV + >>> import MV The command :: - from MV import * + >>> from MV import * allows use of MV commands without any prefix. @@ -1082,7 +1082,7 @@ attribute, it can also be set like any attribute: :: - var.id = 'temperature' + >>> var.id = 'temperature' For completeness MV provides access to all the MV2 functions. The functions not listed in the following tables are identical to the @@ -1459,20 +1459,20 @@ including+45.0, longitudes 0.0 through and including longitude 180.0: :: - data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) + >>> data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) or equivalently: :: - data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, + >>> data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0, 180.0) Read all data for March, 1980: :: - data = ta.subRegion(time=('1980-3','1980-4','co')) + >>> data = ta.subRegion(time=('1980-3','1980-4','co')) @@ -1524,7 +1524,7 @@ variable. For example, the statement: :: - x = v(time='1979-1-1', level=(1000.0,100.0)) + >>> x = v(time='1979-1-1', level=(1000.0,100.0)) means ‘select the values of variable v for time ‘1979-1-1’ and levels @@ -1536,14 +1536,14 @@ The form for using a selector is: :: - result = v(s) + >>> result = v(s) where v is a variable and s is the selector. An equivalent form is: :: - result = f('varid', s) + >>> result = f('varid', s) where f is a file or dataset, and ‘varid’ is the string ID of a @@ -1555,7 +1555,7 @@ selector: :: - time='1979-1-1', level=(1000.0,100.0) + >>> time='1979-1-1', level=(1000.0,100.0) has two components: time=’1979-1-1’, and level=(1000.0,100.0). This @@ -1565,7 +1565,7 @@ the form: :: - keyword=value + >>> keyword=value Note that for the keywords time, level, latitude, and longitude, the @@ -1605,7 +1605,7 @@ example: :: - x9 = hus(('1979-1-1','1979-2-1'),1000.0) + >>> x9 = hus(('1979-1-1','1979-2-1'),1000.0) reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and @@ -1622,10 +1622,10 @@ takes an argument list of selector components. For example: :: - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x1 = v1(sel) - x2 = v2(sel) + >>> from cdms.selectors import Selector + >>> sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + >>> x1 = v1(sel) + >>> x2 = v2(sel) For convenience CDMS provides several predefined selectors, which can be @@ -1636,8 +1636,8 @@ to their keyword counterparts. For example: :: - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + >>> from cdms import time, level + >>> x = hus(time('1979-1-1','1979-2-1'), level(1000.)) and @@ -1645,7 +1645,7 @@ and :: - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000.) are equivalent. Additionally, the predefined selectors @@ -1655,8 +1655,8 @@ take arguments ``(startindex, stopindex[, stride])``: :: - from cdms import timeslice, levelslice - x = v(timeslice(0,2), levelslice(16,17)) + >>> from cdms import timeslice, levelslice + >>> x = v(timeslice(0,2), levelslice(16,17)) Finally, a collection of selectors is defined in module cdutil.region: @@ -1664,12 +1664,12 @@ Finally, a collection of selectors is defined in module cdutil.region: :: - from cdutil.region import * - NH=NorthernHemisphere=domain(latitude=(0.,90.) - SH=SouthernHemisphere=domain(latitude=(-90.,0.)) - Tropics=domain(latitude=(-23.4,23.4)) - NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) - SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) + >>> from cdutil.region import * + >>> NH=NorthernHemisphere=domain(latitude=(0.,90.) + >>> SH=SouthernHemisphere=domain(latitude=(-90.,0.)) + >>> Tropics=domain(latitude=(-23.4,23.4)) + >>> NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) + >>> SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) Selectors can be combined using the & operator, or by refining them in @@ -1677,12 +1677,12 @@ the call: :: - from cdms.selectors import Selector - from cdms import level - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x1 = hus(sel3) - x2 = hus(sel2, level=1000.0) + >>> from cdms.selectors import Selector + >>> from cdms import level + >>> sel2 = Selector(time=('1979-1-1','1979-2-1')) + >>> sel3 = sel2 & level(1000.0) + >>> x1 = hus(sel3) + >>> x2 = hus(sel2, level=1000.0) @@ -1699,50 +1699,50 @@ remove the singleton level dimension from the result array. :: - import cdms - f = cdms.open('sample.nc') - hus = f.variables['hus'] - - # Keyword selection - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) - - # Interval indicator (see mapIntervalExt) - x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) - - # Axis ID (plev) as a keyword - x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) - - # Positional - x9 = hus(('1979-1-1','1979-2-1'),1000.0) - - # Predefined selectors - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) - - from cdms import timeslice, levelslice - x = hus(timeslice(0,2), levelslice(16,17)) - - # Call file as a function - x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) - - # Python slices - x = hus(time=slice(0,2), level=slice(16,17)) - - # Selector objects - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x = hus(sel) - - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x = hus(sel3) - x = hus(sel2, level=1000.0) - - # Squeeze singleton dimension (level) - x = hus[0:2,16] - x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) - - f.close() + >>> import cdms + >>> f = cdms.open('sample.nc') + >>> hus = f.variables['hus'] + >>> + >>> # Keyword selection + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + >>> + >>> # Interval indicator (see mapIntervalExt) + >>> x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) + >>> + >>> # Axis ID (plev) as a keyword + >>> x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + >>> + >>> # Positional + >>> x9 = hus(('1979-1-1','1979-2-1'),1000.0) + >>> + >>> # Predefined selectors + >>> from cdms import time, level + >>> x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + >>> + >>> from cdms import timeslice, levelslice + >>> x = hus(timeslice(0,2), levelslice(16,17)) + >>> + >>> # Call file as a function + >>> x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + >>> + >>> # Python slices + >>> x = hus(time=slice(0,2), level=slice(16,17)) + >>> + >>> # Selector objects + >>> from cdms.selectors import Selector + >>> sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + >>> x = hus(sel) + >>> + >>> sel2 = Selector(time=('1979-1-1','1979-2-1')) + >>> sel3 = sel2 & level(1000.0) + >>> x = hus(sel3) + >>> x = hus(sel2, level=1000.0) + >>> + >>> # Squeeze singleton dimension (level) + >>> x = hus[0:2,16] + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) + >>> + >>> f.close() Examples @@ -1767,79 +1767,83 @@ results are written to a netCDF file. For brevity, the functions :: - 1. import cdms - import MV - - # Calculate variance, slope, and correlation of - # surface air temperature with upper air temperature - # by level, and save to a netCDF file. 'pathTa' is the location of - # the file containing 'ta', 'pathTas' is the file with contains 'tas'. - # Data is extracted from January of year1 through December of year2. - def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): - - # Open the files for ta and tas - fta = cdms.open(pathTa) - ftas = cdms.open(pathTas) - - 2. #Get upper air temperature - taObj = fta['ta'] - levs = taObj.getLevel() - - #Get the surface temperature for the closed interval [time1,time2] - tas = ftas('tas', time=(month1,month2,'cc')) - - # Allocate result arrays - newaxes = taObj.getAxisList(omit='time') - newshape = tuple([len(a) for a in newaxes]) - cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') - b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') - v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') - - # Remove seasonal cycle from surface air temperature - tas = removeSeasonalCycle(tas) - - # For each level of air temperature, remove seasonal cycle - # from upper air temperature, and calculate statistics - 5. for ilev in range(len(levs)): - - ta = taObj(time=(month1,month2,'cc'), \ - level=slice(ilev, ilev+1), squeeze=1) - ta = removeSeasonalCycle(ta) - cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) - v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) - - # Write slope, correlation, and variance variables - 6. f = cdms.open('CC_B_V_ALL.nc','w') - f.title = filtered - f.write(b) - f.write(cc) - f.write(v) - f.close() - - 7. if __name__=='__main__': - pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' - pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' - # Process Jan80 through Dec81 - ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') + >>> import cdms + >>> import MV + >>> + >>> # Calculate variance, slope, and correlation of + >>> # surface air temperature with upper air temperature + >>> # by level, and save to a netCDF file. 'pathTa' is the location of + >>> # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + >>> # Data is extracted from January of year1 through December of year2. + >>> def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): + >>> + >>> # Open the files for ta and tas + >>> fta = cdms.open(pathTa) + >>> ftas = cdms.open(pathTas) + >>> + >>> #Get upper air temperature + >>> taObj = fta['ta'] + >>> levs = taObj.getLevel() + >>> + >>> #Get the surface temperature for the closed interval [time1,time2] + >>> tas = ftas('tas', time=(month1,month2,'cc')) + >>> + >>> # Allocate result arrays + >>> newaxes = taObj.getAxisList(omit='time') + >>> newshape = tuple([len(a) for a in newaxes]) + >>> cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + >>> b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + >>> v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + >>> + >>> # Remove seasonal cycle from surface air temperature + >>> tas = removeSeasonalCycle(tas) + >>> + >>> # For each level of air temperature, remove seasonal cycle + >>> # from upper air temperature, and calculate statistics + >>> for ilev in range(len(levs)): + >>> + >>> ta = taObj(time=(month1,month2,'cc'), \ + >>> level=slice(ilev, ilev+1), squeeze=1) + >>> ta = removeSeasonalCycle(ta) + >>> cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + >>> v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + >>> + >>> # Write slope, correlation, and variance variables + >>> f = cdms.open('CC_B_V_ALL.nc','w') + >>> f.title = filtered + >>> f.write(b) + >>> f.write(cc) + >>> f.write(v) + >>> f.close() + >>> + >>> if __name__=='__main__': + >>> pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' + >>> pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' + >>> # Process Jan80 through Dec81 + >>> ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') + +.. highlight:: python + :linenothreshold: 30 **Notes:** +:: -#. Two modules are imported, ``cdms``, and ``MV``. ``MV`` implements - arithmetic functions. -#. ``taObj`` is a file (persistent) variable. At this point, no data has - actually been read. This happens when the file variable is sliced, or - when the subRegion function is called. levs is an axis. -#. Calling the file like a function reads data for the given variable - and time range. Note that month1 and month2 are time strings. -#. In contrast to ``taObj``, the variables ``cc``, ``b``, and ``v`` are - transient variables, not associated with a file. The assigned names - are used when the variables are written. -#. Another way to read data is to call the variable as a function. The - squeeze option removes singleton axes, in this case the level axis. -#. Write the data. Axis information is written automatically. -#. This is the main routine of the script. ``pathTa`` and ``pathTas`` - pathnames. Data is processed from January 1980 through December 1981. + 1. Two modules are imported, "cdms", and "MV". "MV" implements + arithmetic functions. + 15. "taObj" is a file (persistent) variable. At this point, no data has + actually been read. This happens when the file variable is sliced, or + when the subRegion function is called. levs is an axis. + 20. Calling the file like a function reads data for the given variable + and time range. Note that month1 and month2 are time strings. + 25. In contrast to "taObj", the variables "cc:" b" and "v" are + transient variables, not associated with a file. The assigned names + are used when the variables are written. + 34. Another way to read data is to call the variable as a function. The + squeeze option removes singleton axes, in this case the level axis. + 43. Write the data. Axis information is written automatically. + 50. This is the main routine of the script. "pathTa" and "pathTas" + pathnames. Data is processed from January 1980 through December 1981. @@ -1851,111 +1855,112 @@ calculated, for all times in a dataset. The name of the dataset and variable are entered, then the variance is calculated and plotted via the vcs module. +.. highlight:: python + :linenothreshold: 3 :: - #!/usr/bin/env python - # - # Calculates gridpoint total variance - # from an array of interest - # - - import cdms - from MV import * - - # Wait for return in an interactive window - - def pause(): - print Hit return to continue: , - line = sys.stdin.readline() - - 1. # Calculate pointwise variance of variable over time - # Returns the variance and the number of points - # for which the data is defined, for each grid point - def calcVar(x): - # Check that the first axis is a time axis - firstaxis = x.getAxis(0) - if not firstaxis.isTime(): - raise 'First axis is not time, variable:', x.id - - n = count(x,0) - sumxx = sum(x*x) - sumx = sum(x) - variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) - - return variance, n - - if __name__=='__main__': - import vcs, sys - - print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', - path = string.strip(sys.stdin.readline()) - if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' - - 2. # Open the dataset - dataset = cdms.open(path) - - # Select a variable from the dataset - print 'Variables in file:',path - varnames = dataset.variables.keys() - varnames.sort() - for varname in varnames: - - var = dataset.variables[varname] - if hasattr(var,'long_name'): - long_name = var.long_name - elif hasattr(var,'title'): - long_name = var.title - else: - long_name = '?' - - print '%-10s: %s'%(varname,long_name) - print 'Select a variable: ', - 3. varname = string.strip(sys.stdin.readline()) - var = dataset(varname) - dataset.close() - - # Calculate variance, count, and set attributes - variance,n = calcVar(var) - variance.id = 'variance_%s'%var.id - n.id = 'count_%s'%var.id - if hasattr(var,'units'): - variance.units = '(%s)^2'%var.units - - # Plot variance - w=vcs.init() - 4. w.plot(variance) - pause() - w.clear() - w.plot(n) - pause() - w.clear() + >>> #!/usr/bin/env python + >>> # + >>> # Calculates gridpoint total variance + >>> # from an array of interest + >>> # + >>> import cdms + >>> from MV import * + >>> + >>> # Wait for return in an interactive window + >>> + >>> def pause(): + >>> print Hit return to continue: , + >>> line = sys.stdin.readline() + >>> + >>> 1. # Calculate pointwise variance of variable over time + >>> # Returns the variance and the number of points + >>> # for which the data is defined, for each grid point + >>> def calcVar(x): + >>> # Check that the first axis is a time axis + >>> firstaxis = x.getAxis(0) + >>> if not firstaxis.isTime(): + >>> raise 'First axis is not time, variable:', x.id + >>> + >>> n = count(x,0) + >>> sumxx = sum(x*x) + >>> sumx = sum(x) + >>> variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + >>> + >>> return variance, n + >>> + >>> if __name__=='__main__': + >>> import vcs, sys + >>> + >>> print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + >>> path = string.strip(sys.stdin.readline()) + >>> if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + >>> + >>> 2. # Open the dataset + >>> dataset = cdms.open(path) + >>> + >>> # Select a variable from the dataset + >>> print 'Variables in file:',path + >>> varnames = dataset.variables.keys() + >>> varnames.sort() + >>> for varname in varnames: + >>> + >>> var = dataset.variables[varname] + >>> if hasattr(var,'long_name'): + >>> long_name = var.long_name + >>> elif hasattr(var,'title'): + >>> long_name = var.title + >>> else: + >>> long_name = '?' + >>> + >>> print '%-10s: %s'%(varname,long_name) + >>> print 'Select a variable: ', + >>> 3. varname = string.strip(sys.stdin.readline()) + >>> var = dataset(varname) + >>> dataset.close() + >>> + >>> # Calculate variance, count, and set attributes + >>> variance,n = calcVar(var) + >>> variance.id = 'variance_%s'%var.id + >>> n.id = 'count_%s'%var.id + >>> if hasattr(var,'units'): + >>> variance.units = '(%s)^2'%var.units + >>> + >>> # Plot variance + >>> w=vcs.init() + >>> 4. w.plot(variance) + >>> pause() + >>> w.clear() + >>> w.plot(n) + >>> pause() + >>> w.clear() The result of running this script is as follows: :: - % calcVar.py - Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: - - Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml - albt : Albedo TOA [%] - albtcs : Albedo TOA clear sky [%] - rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] - rlut : LW radiation TOA (OLR) [W/m^2] - rlutcs : LW radiation upward TOA clear sky [W/m^2] - rscrft : SW Cloud Radiation Forcing TOA [W/m^2] - rsdt : SW radiation downward TOA [W/m^2] - rsut : SW radiation upward TOA [W/m^2] - rsutcs : SW radiation upward TOA clear sky [W/m^2] - Select a variable: albt - - - - Hit return to continue: - - + >>> % calcVar.py + >>> Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: + >>> + >>> Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml + >>> albt : Albedo TOA [%] + >>> albtcs : Albedo TOA clear sky [%] + >>> rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] + >>> rlut : LW radiation TOA (OLR) [W/m^2] + >>> rlutcs : LW radiation upward TOA clear sky [W/m^2] + >>> rscrft : SW Cloud Radiation Forcing TOA [W/m^2] + >>> rsdt : SW radiation downward TOA [W/m^2] + >>> rsut : SW radiation upward TOA [W/m^2] + >>> rsutcs : SW radiation upward TOA clear sky [W/m^2] + >>> Select a variable: albt + >>> + >>> + >>> + >>> Hit return to continue: + >>> + >>> **Notes:** From 12737a4ad6a58e92b7841433712347d255b3ddfa Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 3 Apr 2018 16:04:07 -0700 Subject: [PATCH 071/239] Some changes to Appendix --- docs/source/manual/cdms_appendix.rst | 6 +++--- docs/source/manual/docs/cdms_quick_start.pdf | Bin 7727 -> 280749 bytes .../source/manual/images/cdms_quick_start.jpg | Bin 529184 -> 560462 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 39d14d18..9a25d864 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -33,9 +33,8 @@ as identical. :alt: FIGURE 1. CDMS Classes - - - + + APPENDIX B ---------- @@ -48,6 +47,7 @@ Quick Start (Cheat Sheet) :download:`cdms quick start ` + VCS Quick Reference (Cheat Sheet) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/manual/docs/cdms_quick_start.pdf b/docs/source/manual/docs/cdms_quick_start.pdf index b87cbcf9b1af84374c5a199a60748b341611a6dc..1a7edd0cbb057d62b03b1100dac921536b25a58e 100644 GIT binary patch literal 280749 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%0AeT*B&TIC;ZzH=e9 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 literal 7727 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%0Dadg548Hw3Bc5#us<51;z|)jVxrQ ze~!f+ZRM*lRrV+I4U+UNCcE9p<8nD5m((_Y8OOVO5jw`!T!G z@f-c1pZRlL9$#PLk$5^+`8Cy4c;ykPi#LS?JwBt(`6l79m-4nk?dD^u1=Gn+k6zRf zoT=PmMX`K&$=+aGk;{K4$I}yYyk$f)1$xgzI)i6tzm>Ma~+Q}ZuV(BkL2$tT&?=ANe zFa2ioE+?I~w6WOsL4vC1G@+`hT5?{W3K23lkv-!PE3NY2u%*6*d|4@x_?}prpg026 zv=l}af;mtM{q6BYAV z4lmj`j#Q6^f}pv1PN^Z%Gs79!v*l_N2L(;&F0L7w^$)&0 zW={ZeQr>m`p?D#rz{XxlZj|Hra%*c~b=giiZo+=96S|B~4&~07d%aU`df28SUT5+2 zIUn`U%JBx>$gmcv#g?)kuV#loX6s$p77F!7b07ce9{>94qi_5Pi<$tyRWGss$ho3Y zKsr@s^}*cO5c>XQ59PIQmTz6<+A@*rqt%#l2so}dAk!!aS@dm9hTW*g}~wt z_Vr2J#aDZLFLXP`V#UwQP@~G>^v`3$=oA;kG&Bp=KmDxkhncXbrx>zle(~MMqw47s z8L*@lKI?VTjsEmiL_+XhsAFTbLT)q3x@gSBgt8@kP2MR*RB1%lZ4j1fQ8m?Ha`waC z68UY$MT6BI#uignmr6a|IlaHweu*Rf%7_waZ~mu*f?Zw7E>~j9)h|>K0t5VM6ZlJ# z0f4kT9gskfnu#S608&PpTboFuJb?OqSPv*a7zh&r8v?Ljosjk}K=74r0|03tol&k% zW=LnCs3PW=SZ97dAol%FARGw)a|H!L|5#xa zAM6Wyh;_$Sa0Xt9MH*M8Kau_s`lotyh4hcaAQclkFn)e4E&pkQ!r|B}^*?Mvuz%r$!UX#^~;J*MFA$54S+xZfY3YZ;q3!v0RS)WKz~zREsT}* z1q^Hu00VRYEg%B`j>G`pbLVx;0BX@ct&ItwcKVI~R(9V5)F%PJsDz#|2J^S}e+#h^ zeftfi9ucaRPw0k8ha2hnssKMwlpqkx^2@ zWAt1?F1rKG1@*}zK-5u0Pt6ue}4*K`#rZ9>Le@3C@CmN$VyVD|Bv!7 zZ~oEiUxVMg{cDdclfUo`#5M4@w!eM$Z*4vg0RX>4otw13wK?4ZfZ8|!Ku-Lv4VMo9 z%+~;*X6Wze;rcBv?ty{6%2HAxAt90;E=0-S6Z%K_Uv~JT=RXI3_ddzr@B3r!FsEEx z9fK|hVt!95(dV*HkUu8C*OBOgk@(L-{NMiI-wo^U#vyL%;_Bk>;!S;(1y#yCyxpkm z_ICCN^ziY=M{{#nkxM6-bYnz&3h(Z3rzcF=9{Jzit^Z+x! z0iXar01F5M5`ZkA2&e!Wz-izNU<8-})_^@g1l$2Hz#j+!B7kTh9!Lh#fGprHkOw>h zih(kq5~u~5fL5Rj=m&;@cfcet11tb5z&fxC`~-nOFc2e%9fSh$g9JcgAXyL|qy{<- zItwxdS%VxvZXj<^5GVo^3rYrMfbN1GfQmsCpn6a%s2B7G^Z_&rS_W-`et;oh1egQN z3l;=Rf$?BXumRW%YzKA&`+>v3*T5;@+u(=bQg98p72FSg2c7}1fOjAOgaN_@IS!G4 z;33)&Bgh4aE5siX2}y!vLmooPAPtai$S7n6@)fcVrG>IXF;EGp3RDkj4kbeUppj5A z^e(grS_AEXjzVXl>(E0QMjAAY7>zQGK8+QP8%+pJJWV#u6Pjw8PMUW#3pBg5w6t8b zLbQssdbHNGmuRohl4;(y`D9&?(ay(K*wF(WTNoqHCZVqFbQ*NzY0z zM6XJ3Mt_Mun*KI@8GR@H6#W(h1H%ahB?c1)4+av$ZHDIzJq)u9`v^9KC_)=yiwHub zAPNyJh!2P@Mn*^QnWC8PG1V}QFs(7uF$*wj zGTSqUGiNiuU>;)r%0kB?$fC{S$P&qNkENbvjAe(FomGa_h}Dag%=(nImvxB^#wN&i zn$4N*8e0KdI~#=^!j5IvW+$@8vOi+)WMAN*yJj21BUnQb=DYT&P57N|;etUD!|fq3~M~S`oa6r^tPgVNtNCyr{eAJ<%aCu$Y3F zhuD3wH{vwnO5)z)55>nM5E7aa!4f4BvyxnrXC-4KYbDpDa8ehf(xtkk4yEO#FH1j? zo|IveIU^Gz(;%}cD=JHry(jxtj!{lWE=sOWZsVlbNtctkC&%U4<Wmsj%|R_+ZASgLx}*9-^*If!hO@>KjYUln%}bi4nrm9pTK-zqTHm#m zwXbTooPwOvJ(YB7@HE?L^V4@vf7CglnU-0q*`&F!d60RV1+#^%MX|+q%TtyamNQmTR#&b1 zt&drISl3;EU9h#Qk!PXj(PhiaHg8Yw4j(?BP@gxxV!rXdGk(f`S$^yO z2L4Y1Kmm3Eb%7jIV`?BsI4CY?HdrnAUhrOsMaYX#)==-zfiTgq#IVJ1o$$w3pjU`j z+9HleL`TeC)x7#35)|na*%pP3x)!xS(j^r|(?@$ozmAcP$%xsGwTx}J#(Rx)jS{CD zR}#+@?;k&QUFCXS0yM!RVK7lH@lN7ll5`7Ip6O)-yg}<$Sup`%}dVvk?)Z|{y_IZ%|pS5*#)!(!3CcmSv=}~ zjDKAG$UE+Gj-N=Z|cv~w>79VR5waC7B(Gk zy7!XvW$G*XSJz%0HHSCvwD`7sZFOssxO|wjAe?)(L_(|kb`HaHM%h^-219Ru+ zCMiV9%6!25!NRrAjGwa?`4@|qWS5$jb(V*}*nC-7@m=}(HGY+KHD^tDt?HY`w}Ex5 z^@R=pjiXKS7HX?-`{Z`pj`7aNU9a7r-;?%Gdqw;B{q7%@KNf$69Ka54{}TDtaAww)bhHLAX*&Bjxd2r2nrc5BO#<2g0uJY)=Q+X3jT6P8c`!IJVPOnTL_k1BNp+)bg9?-vtDQKxt@Ua5{PhYKLkT z01Sdaz)%Pc4U}pmfv!^T15j2Pw&OCIwCpC1uoHe9veD@e;8?ASR!-A5>o_?l{}?)Y zE^Z|1n1G;=u!!hMc?CthlCt)x(>l6(`e)9YnOj&=tv8~xi>sTv$EAS4px}_uu<+Px zaq-s^5|c7AZ)RoRx_#&F!-7YTpA;4qKdpRGRb5kCSKrXq-qG3B-P7AQGWz!2`?2v4 z6SH%a`GwDmOUqw2Hn+BScE9iK|M*Q82!Q;RtUoCGPjskKc5Gd?7T_AACZ^Buj zG{I^2 z-{_hE5D+R0Si!7-Ia8vwp7@DFXCkWqiSFpU zWWXLVrTW8#>Bkd^PA-8;?Z**?Fc{SDJxTCkk}&YUuJLQjUaU{jX0fINzJ_3OX7tb* z;BM0ACW#I3r;e22HeNgKV4Sh6T#Tk^dyKAa5QQ)o#TnYijCgwTXJT5~13+k@%Ls=+ zr0g$7j{!Vy&3U=4Qmx`7X9s&}b#&mZm>5+}Xm~iAQpsDuv-$hVYAn&sr{vZ_As3Rij(|P8;Has4hx-$%toxWE##CKy|~G#q9iTW+uz9VX_8jh^K+#xH*`u1w5)uiE2D-|j%= z3!P5=({}Y}7Dd@yW?mJ)^w&Uem4#7!lL2?a!=Gn)YT`w;$He?7E!j-=f1n=;W?4~ldP zb;j7Gt%jX555t7=AsM0QF;vh-Mi-axLrVz1EQUUG_2tct(KK~YU~Q@Fyw=_wms06C z>kM75rkSRDF($Eyoi0tnmIfD92D+-5Qu*_IXW22% z^YghRfKF&h85|Bd@A2bWIN8&Wf%Zn1CjVlLGD{dN_BCMj4_8a2H^JP~M|qr(By`y^ z>`OS@Pt`QbO+$DaIK#+xJqZf zW{U}ko2kIBw8i+U zGr|ESq3GYTSNDr~F6&9TP+B8J#rlP?ah*xsCaQu&*W1!USVT<^AL#p(m8ibB4)>kn z#H!*Qn3#!VG{3gSu|P|y*{FozL)^{Dwn|zvaf3Jr5dGm^-ra`(8wKP4%$Q~m#X_H+ zV}r)CS?KpOwpSMMJP&B+ZHK`iIER@rf%Q+b4PRDvS6(?P!AWUWF=iE_ngENhEFD$| zh!{TbJOWaCj)0ZvsBI;&cM(EI0AKK@oo~#Cq$<#W=O?&?cY(SKt%!z7q^q+KnRd#G zLU!>Z&&PL(rSBP(_7{GPa#L8%_=dRAHFjDk7~X?7edIT(9!S62Pyki<>=wwnKO>x0 zbWs`%GVX{N#~|FEBbPO}B+EwLoUN>Uh;Ye?Gs%q32wkx?AL}weT0Km(MMU(FL?|`8 z=erFx4oXt@I?JkGkBvwBNYdCAx0rra^rn>ewFHdj1mS+b;tzQ*c=(Cxv+0YNe;g#V z*u0u<2b^adz&di78e9iTl#+8%3yB-YkAQ6di1JVQy^JkGeTFbwi>`mTJ0wLItUnEP z4SiDGhl>@3$hd^|^g=gbm=yiNaD=7foP@*5G1dkp@m>}u4U|ikc?t|EPRBQW{S5F$ z;=sd=AQ3KbQN*g)711nhH>u%3ho1-NRG&)7b-!1>m*8~AAU8TzP#*&@#6dGcA(_ke z=IhOEta~xmd^6rjoG9Z?eYe4nIWvF}6iq35ZMk=Ec05q*0cV|PDqGEnfkUv zGE6AriUYvx^ghDFtw1r0@U;BbFlyYF`8WuRA-kbgEw;TP89gHUJvdudQjq={eL1W- zXlKL@+LCiNH9mVH?%|YOeApUCkMkA}c3?qoi4KSfq1}Jci!2kGRUOqX(n<2gS##E* zNpTyieX-qzkAW*X|4f~f7ln=t8J)UoZEj(1VG=KH9xXZvh=aOKWpb6r7&e9u?V?s| z4@V1To7)?`&Wx?zGHB}Sc4z7X7mFRJgyHz+iOAO1K*$fFq-Q}*$sU|NgO*vB5dqaC z{Coh}jr_UDE<$f~)v9Z>7|ZWxHiL5Ix-;q2nG;eW()beFE7QHhs zeDJC|aijcD9eV_n2OR;!^ZCp!RSh;()&)xX9I`pAY3-Pqt&#fjJ!^|R&%@XI-}iIv zSDOXbZm%?ci>RL@Z{2TtUw-WfpbSnPzMQ2#fUC*!kf{Eh3!wFpT3ZoU?^`SM%Oh z>ftNyBS0ggLXCA#hfzoI<$W%#%FE_{SxDOq9p4Whl~ZKWhcuYVwe}u+l%A2e6)yK{ zRM_~@u5G-x(PfINavHNqQ9s&5<#novN%FimkA_O6w7<+GdMrM|bok+$wOtK`()8=1 zYD)sQSzwNvi@YzoXn`H2CmvNXYx=IwaT)&l((@TcrtT22+4lucYzGxsj+go7Mflv8Fx={t+1!nfkREURBnpmO)Hl^23S^I`bS%KsQN)y)EZTb zRnLi`J8m$Bw7n5AG_hQcOQzl+_;{FAy1Q zlC}I@lTy6cS6#CApy|pzwo{&xd%ecenv87}koMJK-RTyrQa-cgUPXB;V`(;GJoogC ztl(OVp3a{f>9O~zZRptqgP5z;ZY4|8Q%-vY z-j~2k3cN2xh0H6ZJ#rw%d@FpI@CA0KkxfCr2P{`l0+D)5(jcr$plA69MlaqwvxvA) zC(sKRE3)T;Oxp<|SR6^#^I7@*h=2f(puiEU4Oa6(ZYOUD?9vR240+xym@>-w&7QBp zv(a5JZDBrMfk=|I1_?n@sz47eD(=OFLNv7%W0D|*$Y}gFXh?Q;}_MBfC0Bd zs$XGGQoa~-EO#t-AbUT{+2jE0G0|NPU9+Ex?wv8&Xg)u+ZXNSUw2G{LZB4~&Xa2^s zNm3}`Zs!P9b6pFtwu*7In0Z*XmaJgT6t+~xOxVSrTqTAiR_7hRS((`3VsHdNb(v$k zK=iMp2lcy*j1f}I7pfm0u=Gf8OzV`&GST;dQ0SoY0@pi^rfVAJ&r1!aaVx|@A&PQ;ni=Ca1-RHBI9Akp6@S)~$$98- zRn7mpdc5kFkFgtSL)K{;j|+k^!dV(qhM_bDh>a<72GCo2|6lT9d67@4zN(?YLp(I$ z=^{ggA}F@n7mn=mmuvJ}P6EEa_OwdXja&OX*wbZ5tKSO%s`{8dz>u=NhdQ*4i#gVxOOk;RqB8!Ou|egZkUd@#jxA1kxl5G07T+S|dT*)N#T%KvD@! zQ6BjfNtS}zTg%G&#)1*S zE3Zwha%DdqPw!iEnygirqxEGny9E|#`2)j~o7G1~Bu>8oF6j4#a8mkH=qjSCxVS$X1IcP%gdf&v6m5|0QN zODov?F($GBIiJ~aEY{|@E1gi*F*Lw)+y+hg?DsZ@f@+~A)7p#@t`dvu;ze%OFCk@} zsWFf`V|^i#l3JG3fnauI)HvbYR;|}$eAlNeac zaeq4Cg^J%Kuiqzi`7rP69O;*&AAQ)eScS~5saz`vHZ(N6vUnHxp-}hw{M@@6$(JoW z4E5AZ=Mh&bj5WWSrT=if)ukF#Dlsx4+c$=oOz5H)-oKe!AaJYDBrSAiHsa*S_MW4n zWh%trI0jdC{Zed-NrMa~XKRy!?CpVhQrA+#Zun%FdnZl^(KUwQB(HxkQvx^^;%ecz)$=b_J_e!za&kF-Qg#w(z zwE!qXj_j9XOj~w`VxX#TZ}r$N-RtAvF?pU|hKyNVoVm@##A8=S;qQZ>i{DBfuFLf+ zlhoN)-#10gev7}=!R>@nfA{c~Uj`jDFF<2WZ^%$ChDnS#S9@)Bn=9_w&HS5q$GYeH z3Nr^CIrpcwQecoAQuwRdxe_~e@aNN7esK%;V1!j;Lp*_kq9_%d+AuGxP4_xckLufe z7M&9O9EMKuBX8u4(X4N^NMG7*+g(Rp(7x7RH<5lo^0mynnevE+fgE5PnRH$Eoheek zBP7yF2%05HRHC3njqrR09H4Dpzq^H?{YrcY%L9aJEnIqbU~n#rqbdkOIg_E^f|?4WaK5pdmUwt_1dY37okG`QlHsegOf}tf z2Kz*?cRLHz92`~{L^Nx?N2?>3m6X2v<+$N~@V=^?7)<$YdUdz@wxZz~u?OA&1m}jN z;PdGMFD3@xecCU0K|Wer@m>`hU6+Q1ldrGZV~ySuFOGm&f2(hs8WbDJFx0-^)}(S!#s(mdiQ}!K|1xIbpL`}(3BB!KJ$GOrMtm4-27|Ju;lot zE3JMP(KHN~`{;Wims~`N=yaE;6YRFi8 ztCA~zgt6PcAjj0iabRQ~w@g6S~+o>&u-YD;xH?;o|j=+@os} zY=Nh;KIqLC=>@Qui=7W6rcemqJ?uA0| z_Txx~=;$Hd_xDQ`QVSnXABO0%-D+{_#?!;SLvlzTTBdU~J~!2#-AgZWXF6UtHLJEA z5W^3R|JmU)sO;SXY-2gUY{4U3oVC~&rjAns#ih(plFpgB zlJ%J^;CiaKTn;MqfB=s4TroF23V^a_W^j$y@RNK6zB zzKRDCXDi<$wMu)jHSeq~p*em%;!WE?nmz?heoa}8WK@{YbM-1G$cYm@(f4n6X<+=@ z%fzma5yV{P3ata{AL`Rhyip*+E-m^$nQn<5W2oBnhbw(0*vy8OiR;%5R8H9FSNBV+ zT#KOQuH%XbpGk!7*~n(vME@<@nhxp8*y?*3OMY?CZQ7SZMsKlii8cvVC%t9iM*x9! zIJSqt=h?2ty~N@fBE{JEO_M>I=S~cY3k8V^>&Hr%eS3=Y0SQNUE&PtL1t|Fcz{VCw+*h?9y(_I<;-TM=+|WLUEeoF zAN6c+(JP&(e72MQJ}{&q^ILUkYlFXu9fL1`!s5G8one;kpBSYQBs*lIN={2saBQ>y z5IvQio8tyW8^fMoIM5qiyRGx0NJ#yv9d~rD^;^(ho_BSW4OLwyMhBdDfN$G;9h)0m zB!uSsi@LrUVX=PyRm^a8V$|T%T>sQ+yq7n)^Hp<|*NIjOkmeP=suT4zsZ`YsKtUt&c;7Hur-3d^r52nPZQ`tttou|1QtttduEewxEE9PkaVA13&xch}5e*|E-sPTm><%KBrN;`a!_RRAD2RHh?@s9%5fIVYC|0|G<%{Rc9!TgWI5b&=oCRFb$bbAY8tj zst*!RHxK4lfOU!#L-S`xmW~%|^zv6F_(iaVv5n1iqC^(DqxF$cJIlDHtzU6l~Kta7pT8|o}nAz#liTLy{XEEuJsoLh8PcPXKdw15% zIfup?KoPd{nTi(Xh2e_p)<=$!Su;d7-y=XrU7bwrEC)yE>2sGy=Ai!38NlQK_nU*k)PVxAO+>7q(Oi^ak#n zMHkt9K+ntvF7oZP9q6xnJ${^+EBszD)^#Kn8tFTCQ~=xk05fg6Yw znxz5bhwH5v^2S)~7z(u&6?=$|HP7%UG(ObRc-q3T|J^xDRd2E@6g4OpBetjf&P%>o zQ07{SXB^d5<8%g`sUDUpwv(S_^*~X$_Kvf750ZmkhYs5)r7l5T@@*?G4(C68?~B^# ztEF6IANM#fZkZNViEL$D(AhH`0Q%FyW4jGK^Qd0%Pn{zmPyOIl>=BTZ&wP4VzUuvq zK~F3+GZ;eRS#T=EJ**%w}ImM7Wue_d?J_gT-AXj>km@h&oc#^12QIjbRf{-- zg4}#^L_zxZ!!=bsJdPe1eRp6^d+V}14A;?0zuMyZiR>U_?;DU(2i+|T=nC(AQe4;_ z5SR&noE}U=Ul|+U?oczu3FGxgvW}+;k5+TNV)1yPWaFr&KTW2ik0)g03-_XZtrNd^ zjvmUkJsHE=teFRsHd%J z1Ih)jQNABj-lrC1Bx?Fpng`~|W*zCul)u$&tfAVL zW6=LIM?8N$a{c$;C3bf&^+}Yw)!BT>`HRwAs|)uBbYajU%vHY}b~_0U(C0j;RBgLz zjoN(D{?J7kKQggq$Ub0oh=1e6a<%93G}C;Ixjo5?-W(Ya6BRliveMlrraim!W6#q# zcS4tVth7%L=Itm@n+4rAyG+EnL5ho;81fYpFwG6=A-%F$+I5o7pG~FVkj2d*4AZo% zFl6{7Gt0M8cH?%Xl<8z2b-9zG+Rj_wlXAld^W+U%=2le+w_KZo7{}Ab@F7|DEyy_O z(Uo|@kI&1If}1CklL@c3WJS{=jVlj2!{@=+2(rW4x6IVjd*`2Ajc-N9Gs>O3rpRmf z4jbKS4hKm~+q?>B>-nsgophA5e4nkg)93Ohn#iZ1&#Vo(n%zARE z^knY{hnXo6cOnk8#o`7qh2|qZF@~14x7YAR&?(;ZrsthS#P!kkw$pSC!;s6P#e}Gs zS0~i6{QH9wqYs-a0`G9XwXFcXl^)8D#bdT!`{%){ zmde+r1y2XD$WWUHw^6OITz5#>UUHGuMQu;{iPwo{O|HE6NTS!`5q^V~Pr}gXpd~4S zrO)h7ykw1f+RCwqMKmOldd;b6QtSNI%KN&Z8^fhy?$m|FMgm%ZFb4ppA#$j81f}9%ns4n=oj>dE*-N>a-Ets>#&s^9gnD2Yl=-L@vqAr+BdJJ9=^?IDzM+n zb1Tqua2iq0K%UB9#iH3db;7&YZ_a^n5f~j*I6W3RslLafXa}=4|MuN;E07 zDb=EoU`}o!kDloa>fuMX?N6r$<@KMQj%A)Vc)JIh-7~Qes20zqbTaETV54U!;4To= z@r_e+4!`<@ly`FgWdj=fWiJaN@O7{;8|FtZH>ef!Wff`$sCeCwnCWfB_Z6W5BU2U2 z`w@=An2`w-<_1xA|6Yx6p}U6kOW65g#13K1Q{r{$v9p3dZ=Y*I8SA+oH_y_6EA{N~ z%KCy%f~Xq@L)p;J%&1QyM?kk&z7N{wp4`)7*F?WMVV+iTZVxC4E-p7@sH2J6GMEl$ z)cI&uGa426v`^4vOY%+HKtD5R!f$d*B!!r zb}wQ5;=NwnooD2XbiU0<3&!V{C2Gkja?vSbZ|`+y_qsO}tXVx0=iuzmHf{IjNTZwZ z%YYSgE*$cWKD>3oGx)Sj*mta>@p*b&%Ou&sfjIJ#r>om&R3byHuKOmxOec4bK|luh z=8QLPK6be~p(~ade&K@ykgmAmVLI1HB zX0aH*JYTUFd(`RR^N$*9k6L0KhB=n6cs$hjo)Is?H+2oD9ca~&)%bGNv#V+-A(dvo zDMSD6c&`ZSH=zZGN!qr_&>jjNIrs9_mp77cJ4H(#beXrf;FVCYlZEPxrrr!9vjv@FDX-X-jB|S6;y?#nvqguXe0{IBs6DJWl#3>E zRzK1-Ju#xtVO)|m86%DVxjI@F_Usc=g!+s6=QsGIFN9`IXs1fc75QXUwD4X(8w3-= z@LHrk(=OFroU9A%MWK+`A`D6MN6Kwgc*#4;MQGU_ZJ_1Vyf)QepB#-bX&ghk_VVhj zr08hiDLedZ9_v$0!P!o0)^^Di`|XP2XTZ3gg%_j(GMUWUXY>53sUXX}h^e-Sg1lSe zk9HVH;n5@jk9H!d#g+^0wa+D#!FH_}KX;1C;23YqWVQ|lY^Ain4DSqU?z*9jtFa*^ z33v>1(?il1nrSLB@ce1{2qWlTvXOzG+ew-ythU^K$DE6-c}Z7WH;MaK!rjng=hh#8 zO&X}tvW#JKKZ@8a% zByCjx*slue3F%Ex=KA?Vb!s|Hc`()4qm-Z9P`u&Qga_^?2BYAyk~)65EzHHJ)-Juy zuv@K0dk2|^FDH)x?UWZmJY9Jf+4?6G1>Dl$q@Qhsr)1HbIC{F7dFFdcCqc^%+?`_Q zoJ=k^zR6p=qZKDqIWOmb#SOLmmUM-FJ&M!%TxliYSYY;oCS#@I@dje_F_JEUB1G8c zT;=2YwChfo{^*v;x4J*w=rEnLm9sOXl+XD8;uog~D-{0ti66L^iT=ah%yB$5d?D;( zaNVMuTht*3L)RL*0 zbLrmE?6?`{`P@et`a)mA0cDT|pZrFYfv3%=Qm^$JE3^YR|G4dUth>;tFQtCx6XRY6 zHQOUs(5}<0fwup+dRsVOK1mPNrOQdQdgJ&WyD7<{?2JZ}S%+ibm|x6iQ?8BWPDe25 zI62k17)tX=ua4$CcY)a-qm+qjcoymGl?s4d+VBNxNMK7=j4%mVKW z=AVIY$$o#vbN5E;-D_!@UYgh#uoJ;kd(yhb+2nu?`)-67g^GRHw z)Tz=|#jmFMtaY3Vl>sCpje5d5J|A&0C2Di!2=Hp&y&rUuA!?o%_N(d$cvEh)F%*5P z(*P-poH#MA5(4HyA^WyA$><;J0bS+s+w#NDC@(C;v9Qks=L&H{6+~wAAS~cLiD2+Q zlPh+OHQFY1H!(w4DE*>0X6DBO)Dd*p_=absGYUuALy*5NZNJT zJ#%NUHuj9AkoPcn5rXoLBxdFr(kfL@m}yVX1)8N*HeIQa-4$2rA+V;=ErrgI?*eYu zg6fX7p_)4BI7|v&NE??veQK6TrEI4Mi%Hsero7{`bE@uaT=tF?WQ2CpKg09kwiZ;BSR!vxq(9Yg}b4^ zX=>^UfkM@uaa8SzE1+gug!NLh3>c|d2D*0KCb?wHvS2 zvF;OR*)GlFu+XpM)ZsNx!lUp=Nd2PFI1qM=n!0e1diZjTs%0}?LJl21eP^aBYR-%Q zLS&YXfC~1npFZsSNcC>MNN@CheP>W6=L%7^2-2%YAJsjdx3l)?2Ri84A6Z0Y$*t;4 z-0f^HTW|IZ+|&5*9MBWmyC)Q#a(l5XbbQ0@+S~@t{%n)%d_nY<$YK6>-d_n&!1X}% z&PBrnFx`0!20gP+_PxpkSJz^6IPiSaH2(0F$-rfk=k+QV(+q;?b!bETcU7IL_s~f# z{k{V^^EgMILZs6GOs)IJm>&hi`Xa|rBem~x2B@{WPs0i1H9jG$cG)3TgHND5H2a)4 zg8}DaA6euSW5&-U;VwPmb4h9C7oai7^!7Q4z#?q5trO0?hsR%Iq2fz7?q}|kCgQB% zjb9JK1s!kJnl6gfhwx|VghMjxLiR&<_*OJ%{!2>8^9Yw&^No|>@p`Q?q%==GkV4J; zq+3&J-Nm4S(m=v|S7~NBfs73S+YU!{x_{EF21bmHp2KXNVh^pZC zKG}0;E8EVd4A^8JGT#nzIsz2v=4n?(Y9mjsR6a^9EbcgWtP%7sDp zOJ<{k2EpW)xSAp9Rw!>&X3jM-Hjsj_CM}L10T;$Mgxaonoio-F?E|bID~nt&Bvgnm7OQTuVxM+W z`0kX)nqo)AQ^y}^`G7uhkvva?r6+CmzM?I5GM$O*ZIN+~9%n;4|D3r>1K98Nm-Rbx z1i#@e@%!w9{l?N5X}b#xQF}?<8-}j)GkeK<`h_XU%5l*^IL%vI21j^;X{o7P*ZYUZ z+!Wh?hLw(uMPeVEz{9RhNjH0Ey6y*mfRt! zdkMSE9<0_htf$#TWL8DHGw-+D?}mbnlwfMrtC381Tq+mUSnKeZgPA0u_cR*4<%fzv0HqyR@p+l@%k-` zkopykV?kR-z#mybOZ2nqv*v}9%~ehBCl|vS707FYUwwwoefqkHc2k!J{Eh(BcJm9n z$33><8|0it@f<$6E^apmb@ZEcqQTE|lT%rJt*F*P>7f=1VIgD}yU`hbk$k|HE0m!1 zy5db`8HWsSLN^Q=4D|;sA`4n`nT-&q94$VseQ*=y$Za8Jl2q8ja2q+su+%?tS{j?l z4PR?mb-h?8YWZ9@)ixMv7ls@{0#-(!XjUHq^v~3$e?9(O^GW6Phbp(=5MpGw_YvTR zrzq{0Jl>Fsf4ISM(KRo4xHVck9_sAu%sQOjqk7d>1D1P$-@D>bVw2q4n|}MbF!E^` z6K!zXx~jpJ$KVN(@Z!_PGs_pl!hry(M|bk;I`5NR_v~+L(HV5e9z1~ z!=LM|fh2veu1Ch#R{O+p-SQQv((Vuap?_l_;Ct=%bneuR!nIldN7TrxmC(jkH$?xlOjZt@U!o62>DCEVvZqZGMSDe;B zTF*#U?_?EF-_m81cYA(ulxkHeN&Rh?_1+WQDLv`vds~9T5&>Gy3WE>IbaOtSm|ml#^%bY12++o5aaZN9nEUx5bju`D~G2 z$XWRA*BLr$rn0AjfINt+@tCmQ)TvX5O^uIq-T6I3Z^Osr=Y(xE-klwVRM{rRzj?>- zje_r8U9Mxz6&sDLuRnni~|j7Ng9Ul1VWm5PS)hY%i{IoKIlORR8z#rfj)Z8Dq!W#`lt3E-Y;Rd zM7`@%Ra!$#HHp>gx(9rxtgYcETAkpny?tSs%E+JJ2kpi74O=t0%(S| za9Y4HlNm|1pS@cxpOfJDWa*H{?v-A~<>-ad5wJ44Vk(%-Co3D;(xvx>Z&m8#9l<0i z0lxQ6*a;3qi5mb&8)0UgS$yTJ8WdaIC2Xz^+>rj7ALco{h<7q_lC~^VqHQdBDI@9V zN$|Qsk(rg2ejGgG7acuHzCvB42fvdNd(~H_o44^RHk7=B2I~If^Q+K~J0=n>6)$il zRwVt7Li7s`W9J>XQywX&nL(dp6Yb zvL*G^!owTko8|k|U2RJH2=E-M+4Ir1qyMNP@6;w8N$fIU>!3WRCSJ{isCwR_#wslG zybnjVY<%v2{yHJos8Z3asu=Ym$1msLEy#f4nmyXeIo!+AC<3@80{e+yLB^{6OjiTc zc=n>sjpc7HoEwu_43+$%Cm#HqzJ&z@%=m`yK!0=$m-d;oh_=MQdob&oup;@z3x%zC zA+PtFRSp??E^JKUpuRL%y;JDoTW}%yN8&bmAU(9+GL5iv}(p4>Wn5;P?~_32M|Z!$}SqZbkSUv=oW z7cpZ&Ax{JbB;0OPG`SK4X*tTKs1CNWU+N`b;|Pe!+t?TSb*1+3I&V{kt?Pt+$a3jK;uJdEb0S}dJX`|u&EZ*c@{n_5i|Qc>~)E`Ip_@%Qw=KHh3Oin1Dv`ahe282 z9=qzB%eH567dp4`*n?NDiU!^+TbZ-ju^!rr{9d+3B4p0hREIp8?%FuBjJk0qPP{ma zn5J{4emPfd*;qGV=@rig?!vYK;cR14aUf&1R@Aj^RZSpGj+`Ru6{3}Fn=ol8`)oM1 zsqh74JoT`m2gk48u!kmhbo%z?I1n5s3zZ!DnAO^U3`5iuE^40W1Tcds-SMzXStx{D z>*Zn;FQ}DwSB-I^N>X)`fa$QmDve^Qv(2zsQsII8? zIJ=S`^<{SGHA`ChX10;2q#37o^g3vec99T}v=S)~zfpQ6fo;E82&mvO+~|c$Y3U8A zXrkvW|9RGN@GFtAsOMg}->EyFluv)7cZjroom%~}ZFa0$-UhTPv!z6t&rHQfEDn?` ze6EFvUi9HrMErpM`|=GT@7H_*7DLt=X1F_ z?>2W=C!=e4od9$j{U-6eQ^wY9YU`?oKy3hdaCR>JxIC+YVWhHEI zH6hsgIOC_Tj;35!n;(YJ{7aoH*!{1TGuMt$jIZJ3vjz87Tv{Ivy$#92F#C6G43%vA z#0+1k`FZD<;|Gn+u?K^`9l0G2<%a%@fS2loy@%{M4*N5zr5(Ce!YGSD>X}%sW=jud z#+90@{2x-~?OXrJ!e2OGU!RST5t~AtCHGb_-UFa9QHhnI$mNvqMG{lU-|1h=wom&o zO{(jyzU?`B5HRDiVcLa=S4gN~nr?~j(vfXCD1fOop*KoqUor-Yg?@dP3~&7(?7e4H zl--st`WC6kNkWxGEf6FJL2^(@f+QtpiIR()DL_!L$by6-C@3IVa!^2!oO8CI$O1}K zBzRxHKHd8}J$CQA$GxZfbdT};Uoxx$nKMXurFTPQ23r;yT?{-;_NItC#NnQy#l??6gojjgosf7_Apn?sBzoW zr8Il9rsw;s$LNSS59xEKidQHZu2s|9a z%$8vAoql37fPbT+K5D1AFM3ipF9f-!3}|3@ma1A$RIFpRxpS%Hf9NbZWkH8d?>ZmI zl(vY}`g|Q);2QTXIj3rS;nP@U(d>sBkak^s@`S1yEAHRDb5yPk&hy|CLqNw(U3JTj zcJ^CD8{KBb;o^PYH9a&JDU~%r=sU)xqfa$M$E9B&*9F?>!qw%lpK4=sEmsJKbjDzE ziAsQfNCUR7snp1ARHpS>Se={VM}m2G6B*0npZZTa+@A24RW#S~aFRvckEEnyrbd2m zd9sE@do=kUf~(qDE`um_`Y7#`cUrw+lO&rPhBC3@>#E=oUODIy+o1lT@yOUK!;4L{ zS_F-~?(2=t#{;*n>q@&+gcOvTl4iZ_THKIGsRQv?z@D7EX*HndVM7{HttB25thEn z^Frv2VIff2EtCCTYqG8|mx^cab9?&Yl7QEAih)CSY^q3EK@^aJkATh1)4KcL3<}J5 zl)ENu(nYMQpd35|??6kg2tO>Ol+a18$DY+}(rH7}{o0qT)!p!BP@{8iItg|bN#+e* zA415DDmOapSAo7|S<+vC$(U8GUvxu^-aJ_WPvI6D(lg0JG&yNT;!}VU9b`RvY3J6E zdidhpb#L<5F;8?7-w%prJq~J3&?II)_+(|~Cu*=K{mO#=LA-?Bem%K?4}ocNSR#f} z3O!Y!qde~j~?lD3v9H((E2kE#4q;nkmuu>KpqhOAmpHJsmY)+I9!tnw`C72j+dC zlD2fXkt{mt7{BFCHB5Y*FTy>4#~*<-CxPak5gP7=MwWSlb(Xyx3w-99tMhqG4{cr5 z04&DcX_z~g@;|hH^8bP9dyf|bd=n(@3*t<_5j#ghuuEg_z-70Lb8x=YDg%~&v+zHO z6XU1clD>C`=n@^y@datW0q@E>m;6UXE*Nak>7iC6(ZtNQ>+3p|t>WZvF6Jk-#%83)l6(=eEU|C88i26 zNm(9e#k4L7oJ*2pzaZJXKnd_$YrwMHH;i^IgZ0Rr`Aa7dnp*q#5)h=oNhPt#n6PQ5 z5Q=2OF{{d@YtdH_$dlVwT`ccLfgw(59LB&NeE#Ca(mmTeGyeD##~E@@nvY3FA2tO% z)Nm4#ZC5w>k?Wh@`cuAKQIVPz={`KY2T#`Bdh6$f^4=Zw$Xq@&21}kn z14K9JEfLZ#IY)pzD^B}hefeTnK4E1Amns39_fQzJ`ujR!7D)#fBsrNw#&4WXjywA_ z_;Yx(=h}Y8gug?c-66Msqe)2^us{d-fjNsBB8TFD$nZ%%`%C+}kt2gd~^#|1jP0Axqp0S=b9yvX2 zKOlih)+858j!d4`0fo2xgX;dbh4!8TY%vjOTOOB{bEFl!Mdm62)_VA;pdCwbdnfh# z7?p5_YJN%`SMTlp7C(E(uFW7bFO0C)MHGPCfIfU7sPhm^R z=lA}2xp8TB6Kukb?iVdv==JwFRaWehWVxux`Ih%_N($`udj3bZm+c?jURs4;%)`LF z5&H2LKxDS@LQt$fkosdU<)N$k%TD^}4GP1(C+%OtJkN{YRM4&nE8NPO$1`BRPA+12 z(>&yOn@SZt7K=~iJ1#%jGPB)BCnlTMfw7zm@^1lt z4-urb-+lTd!R}OiW(;IHxrYnA+(`P*KxzC3@2MYx2Z=uG@E}WAyY3FTa{D^IOyYjl zd|1{304p1e0rszlz#Nmhj(r;LGXT?e&)+b@n0&19@mW(Q{Fs(HLYUg~-Z}Q;_XFID+5*?QmQ= zLwp#wq40Gt0XmmQ?_$Xl0Lx|@5Q4#)W2)$p@xw<*&XU_Cmr+tSxFQL_CR?qGBUyjr zp8yy6lSC@TT8NCDT(3362S$=oem943{n1DY%H1R9Td~*I6EHiJ$oUIc29q?ACIz8G zY-iDezW_!vGdf6b=*QBrmi73HJ7E0eS>6S`YZh2cAG*)ca%Sf3r40p(H%RL=L8uD( z6IzQ4f%qSKjlO4K;GsL|7qI6&F`~d+aK^JBec|^DSWyf8(I~&9zxnw9w0u{=M!`>0 z27is=FFE|B4}a~8zwE^sGypEU?&7&nj#X3- zKT67rZ9`1<3| zpW+qz@!j9tky7c;mu@>bdsC~oM@nkYg7NIfaf&h#;gT$VZ-xB!Nfv1IEd&gRlhV4Q z(+&X)^NMwWb|CpMfyFzAZ$m4ufyA@U9ZO?ekiN-Z-s- z5D$QW?H_%JftVYttw7<$e6y|)sWp(TC<`kSt_Bg(+UOe;m|On;ExH*P=IH}#IsPOG z&@oH>lVb*6pFjuhA1ubW&R?VWS10u^S^Ujm|4SBs$>M)q|I< zD0|&kvX8AX?<-sGg?(49DYg#*qM`Rea z9c;22|HgC2bO8)Z)M_2Mqh!s%%wAmKMNQYncbb*XQyq8Vsi_7KKJj7M5VP%Bu80bk ztG55T;N-m zoQfP@sYQ)*0IgBx0bc7lZ)CU5L`$$z)V%@p?D72uEKBk90v}=tdPNx5V7)Xso?Yu| z*U-+Pqlc56YOC~NtWSV%i;r1Vv=vJn`(`r6a>TPVXJbB%$|wuWZI8w#hh-Ji9}h{g zbm@%SSWZsRBqcTSfqjU%e>Y+KZ&qUTGc7j(j_Q;S!vr;e5x*rE zSZtq76Z$zH^cWjltXPV!-O%IUmVQ7U3DarafZ`8($t!N`afkDI$+C6JZffzd4wo(Whem(azqDtmJ62FpMO7Z3f-tu3722}deH*j zDQ28r#!VpX5+4u+xmp5T4y`>~?o#%zsf}NM@ZmP=H>yR6bQLpubAffLte(FBAu4d! z%F`F%1ZfpZjLx%XI+9G)E?*7DxA&9e>7bS~wTa93kt`je^$XmYbhC1$x#==1Ttmbx zyrkIa9_U>vaihL;zCZC*lf5Sos*8(@gB+8s^&YSa?KioY4?V8&2%)b*DZ8vUWh^?F zrQj}=I8frg2ZYPI2do^j=iEExaXYAuJ@wgbU8s|s%dQ`i*vtq&PzgW$n#$pW5BJgs zVQ&)r)=FxNLPA2s zt*zKVy^Q}6?a2RZ`!dhR!?#CP0or&Y{{`t~Jr-+yGZ9gQM*vS;{?EX`?2qLJ(7?h_ z$3a{0FheF4$~M*E;=4)P>7(OVnfnVrbu-MA!v=)sw}V?@P*SL+ynN9bX!_wZN-nTj zIiHaCTDLKnDZ?jqC!n%jRBoCY#Jyg)`X*%S@D~vH3mBLGdDO0QBi1p7*p)#=)>UNQ z`sEhMIWTa~o-Z@JtB(~5*s?{>Z|>ELDtGXi*u_$&>~_AjL~2qU({cig-@nh6lluz8`uP(imhTxT4&b!sws z@OcWa_zh}8m{%a3eqxaYP9D=DBElUuShl7E4`tcCi+kP+h!-=x>is)1TuYl?YWd2h zomdxST$e35dhRn^Hz7 z`-_??*LjOS6P+*bkHf!?h_nG{ew0I}zLn!e*?p+uah#MsPr-SP6uxaVf7SS0%{|9^ zoUNenjEdgzJ&qbQbAN(m|LgUCCwb%}Zd7aIxzM@L)mUg(F^;@%vf+E$i<}}SmKgM3 zLvhV=&+L;}GwJnL$mY6FTq$1bI@wTW~R(ZK_Mo1NBFC54-oE7s(cM2ee>B~G(* zTJ|zisrk2L-o4$Av?s^GXL{+e37$hNv4D@X5|a{Aj%%`Pr@VAI=4#LB!rN=4*UqQ8 z5U;jnZ`#WiyJ_!Tnj>CTeYVgY)|}#fqO!*j+DOL=xwwY)Z6#V9Q64cgW{l4GX;4-F zv`vaT_;p0o?XY?Yfca9mysjet{rgQ$s= zd*}VQJh;5SyMXI=KVc&J4qJR&cjcW&u;-4+)WsE-t2U#hF8%omB`67Pyh;t)RxHrs zmz*5gsp)`U@LT9?IupD6qw+k{J$%nn6|cU119Xe9g2?ND2Sm2;+t;TpHO<}GqIBQH zIbs_+J*%Ty38*FH#|Ti);9AnR8waUotO?eXVxkD)iS2Pj%Ou(l+yHWnHIyAo(G~b$ zPa(|eR0^Ko2#f zU33t8hdhTe&5^<6qW3MT<<~uw?gYA24s73jwoWvwDs9_K z&deNJP#!Qo=^gmYfX2iG{z2Oa{p>Oba!OcL|II_1JYbk8Yofy^#x^m9+M2I}8!o|| zEj8Yxzd_P z)jH|JX1AZ$mFY|Fa?sFQyB%kUlh~5{Ug~1qI&3uCU+bW&!CR!ed-}3ZV7~H7JP+x? zf$ydQOUQ_Z?*n#Ph;}S-L_`W5 zm;UA6*jK{CNA3+|S9!^g+5xad-M>tL-&~#L*3p&7wIr=7>~+!z=b&BBk1MPak_bA; z!tW)I&-;a=8}kTcN6KB9{YKzV0^M+CpeJzN2%I<E?b zgk+hGw*JjWbe)`%k_r)5BLG_IH>N6XFL?*pGGT-Fks52*umehED)}hh+^Hb*pWdyN zF+}OJoXE<`iQ}Mombb!LU1%&dlpX)|Z{a1xciqX)GTpO{-gPmTwzHJ^ zxYhsi!|Rf+=$8+I!BSYmPxu-;wDr@|Tc>ialoPN)T&FuRegb6lx9UXZ z{it-KwU&a})C^_Brp^kfS}L4`0f}LU-EDj$XKJ#iFP-dEIpJzD9U-KJ4lBEkH~Gz6q@ray zK38L|>08)O?$z!+afJ)B4phtiMMdOgKwmfL6m&^ z{y|W|YG;Vf+3iByIKBz^{UuuP#Q}RKL~CTGb@=Va+)c1_i0oagyQFNfpxT68{n*0p zk~G6OwZ=$}^5YQ5NKw2&Tn12aBS;s&y@67xi%Pcy% z(YE$0t@F$PB}p4w5qp^a|C?#msn(Na)4yj<*Z54D<2S|#lz?W77%?`SIAE4bY*`)#oJhMSQdPn@>ZhpN)adW6;>(J}@~>-K=0wCy94Tl)lSc zc|bf@eb&y5PCk=cuDS7 z^HC-aJ*{9M0QdT#`Hwai%W$04BY}_p$YKF?sc<3_Hf|2QX&fTXiLfTR{D|pBeORvF zK$kux`ZBws0f49CE`=QQ0HDFYj}!UOmmFWNkA;X3Ivnq6nYq{^n0{oc|YFo+NqlqUWTUMR7zcB z!sjCaTr4Hq)~BFAM%S~&S^JurumZpPUiB_v9wNE4lxqkKWv~c1TlL@1UkY6Io~Z5- zECW#+ybK|186lP&dJ7E-2#RdsGr6c&jZ@{;M?uG_zWx+>TC5Xqq>jp{uhBQVnrqCc#xo{D{PYXuWlEg-8^ zP6sLAEn#n>rdQ;^0077qp}-wIY007rLaiwi{{gio_R)z|?1gqslHrbxc$E@Q^zG|b z`$8O@4OedCk#ND*hxG@ds&CBkYD4^O!mltpea~vHJmKEz_tWXwCjOUsNx$)XtHx!* zTTf1_n%{L0O<%iGF`oy74a!R45TZW@kDa8ASPA&%m}!}>C{1^ClWZB_hxP0zF#VpB zCo6o9AlgAd@P2Qc#KWul36cr)s}+(2du=_Om6Lz$Vm{<~qq>2K<|{4Xn>$>@K~)h4 zw9+^zd*V2LCAhHHEAL)|jEDb?3(HWd>#0B~%Osg{3WB*Mtthz;Nt(}K3BgAc+bVSD zQbstut($!=4m-#~EMVMhO>t!+%E%1Y_~L8jq-IK4N#r16PeeHJ5dqEShU!|qthrj5 zw>X7e6@A?mot1b(f&$vrFd#cK0Mv_o7kc{A4qr#k*p%UQauEDO0;Hyxl%GXhjO;hJ zES@LJ+2Oti%{$MGl}mn^eJ69N_}Yut?Kjf5mh_a((t1yI44PQm_auM}VCN6#^~#>t zusZY2)K0?mT0}I1PV@PMvmzkn)zrHZ+W(4mtrgA{&} z1L{30l?##KE6&4@&hkZAeTrlPZBD^no%XVz&aKU|`QEcCFvN0HJeno5>M*2Cz-CHw z5fHEGS1wqOZe68%sPe{L_4|c)oOa&V@56)DFf>mm#vtH{ZfjzzM9&a2HmCRPjr5lm zZioo;>O8OhByl%B1J4^=t341k4z#x<4t+Ra`fZ?Otmgy$JYuz~Q`xf)Bt`l0jh9F= z`b5NCODja$plE|e9#4iROaQ$pT^Ss^Suo2zzMtp z*l5PE^_KT}PwShQxvr&+tu;IAyF{0=-b<_&^6}+YLmJIu*j%EQ$r7+#;`=MU^!pPaA#NOkaq@5~P=3K4(b~*dE+vm?72py8!TJ&)s4~>t0 zp3aJ_h1jUzt8&$zq}~5aufS#S*;@t1lT@E#8}61;~mkjWmr7( z&e9ia2w!A~J%|7ykt5pDSaXj{zY_fT<`R^*cXwM!Qz+x z5p}6LI(NCD%DS)p2{D&|VmL_y@jqC!N)5-#^)EO;*p?J}l&pIz4aPp(0q+x?Ua-=N zYSv50YvNCk4MY5DRuzKN_)?G#^&l9~*SueZkn6@x6imVUsmHZAKlA7_u8k%vX2FpbCp5K8H1& zg@O*U`cvcEK%p^{e?gXfXey>sJE&^EZ1q0IvW|sxs_=Kg*999mUJ$G29Bh&Y(;#P` zz)B<#3c<+${3Fu*=6eUbSgs89K-tIXS18`+_dv+FALhCBiwL;~B#^d!TTLkwB)t*$ zWc$=OC>`eFEZhwx@MxxbLB9x&ob8GH3eo4IkLxErn$1ZAd?goi4JrvylG@@r9ZqNw zyxXj~)QWS-!v@}9WqL?)DF0%X?+cMR-dpS`Q%)6&O<~=HwHS(ypf2Q)RcKd0kj|o# zzdudVc>8Ll*)O2U@`Q2@*|vZZO&)}><8R#1hSFo(-=xo-N;0`WTTA|)3Gm5jEwVKu z6T1}L{jTPITR%h1UDTWY0wj5xU!f!@>=X&3vZU>8bZ44CXu_A0Tp&^-n=bUeSy_5f z*IVT}>a39u?(QnL6tSp)m>N)47BtkeT?}t>LI!QE59m2zkzTOwlel3IDfFM!Sd-0kO33*#cVjHinyr8%^ISu$FX zF&DkF6B|7*FI(Zr1l!M~tpJEOB07Yi|1CPfWvUZm!_c{@i)Zv5kEB8}-w;(#T)i&i z-0pu++uih(@+Gnhwizy@$dMo$5(9L9d--^_(T8tpTBKOQijH8if!X( ziR&5PWb9?u2AkwSN+~P} zfnaCBASeA9`7jOYm6dIL*UyMC$Sg)%cXB~D;Gast9=6Y)rHXoJ* zm1HMpeUcOSlrw4gwkOi#;}*r*tqX0*FHi8v=Xc;TL_J4G;F1lVA^939+RYS7KK{g~ z>K-J1@k$OrxSJB-6D(E6skJP#2t9J&JT6A7_&Yb?yQ)&8b`?o-%^#Ib#sI6ofHkm) z&Xw)dxOnsXwaEkBG~h00lVyd1&&MvpcpxwvRLn?&alTK7Zmu(AS4A-1?Rb=;+5Wjy z*G67fXCZ2`51+EM*VM--DGUs~SgYhIN+tI#LK zuw~E;o;(BbLY`bq{?-TF;W3$i5rgg)?PqRAq}598gX>#b8orxGQkr>m_dii4@;1A$ zAF$i{#9FU=7OO%uXw^$l;LdGXL&w^!32SV<0zVaO8~K;!vf(ynt|z0R2-?)r1w8-02xyo*`y z^Ph)y02fo`&%EFiylN(jo_!w5pH{I*S}}_TPGTxZ-zsz&@9YMtv%DV$5LdRS-8Go60Mcck= zrz)^t@W!bQw3o6f7cz$}Kfi)0%-qZ4d(gATeDXVAKoGu|EwIzm;sV6%ItBscYl@$a zdY#|Ypm_B5j;`NK)WNz-qAxYeEnJ-N7=dND8hZd}tok;89@Qp3a^paDCk(KwjyZ4Yj?}!LjCZi>86&u&%9pDr+m(1_kSL4Y)%Zw9R4Sa{)k$tCSO5=l)nQ^rXU;Ng3 z7r#h@BT>;VPBeBGknF}4u-l-muTos|vm589XdWBPY3b86ER-`kG4LoF6f%j6bQ%Xo z$}?p6OnrR!6(+?g+4*X3<-$Ha7NvZX*=7&(^Kuh7gA-y4Pyxy>o{9ZdD}#3ahk{ja zvXTU@&@$dCA-y;};;@z%!bzSx(YAN!Y=Yh6ciKLUBL|~oALnFxx)Rv>L^>yDqY@L* zKO^ZNt){9sepCd_leWwfP(x_>1>y(8a0KGyhBs#j$IFTA} z%eh+Z!QXf{kk&M*=)G?pj~{d5@Lt9?Pij&An>P%S9y+GNre~#f66Dfl?#ST;(Zo-H zaf~82rDznePnsR92t;fvs|4Vzs%}n6y>7(bNW7IND>7UG@AO-10y{?|Mw^2f(w$hU zW55$7?uH^!7p0-q{iIxqc8YnFUk`RFQ!N;**Qk8~nfytsAlbQ=Sec^(k`HEsX!s+) zb)$oApSl9PxtE_a@Fq=&*)aNwFtxmszWKa2v3hO-z`NC}s=pH!rD6TmCP%N#?2J>k zs(bQgc#(SHAu39$W0va>fqL*qF~`zQ0CLgFqNGD;5rU*R|l_l7)mOx zI{L{UNeHo$joefRPLO6x?G^xdU#kW!7|6cm7q8|dt^b)%NU_1ELQ+F~WPe}tBavuw zyy^JQmbh2rSSOfX#;%ue+N}!i!F)NR6y-~pbIH~omI*qDx>A+6kdo^(KeK89i^y9@ zC$fvaZL99I?3()Av!|wV(^qQeo5p^?sNqH!jE5pQF$X!}VFu`x`~bH<`;Sl%3JDz` z|F0)jV+{Bgu#mmwygqctarNQY8fIpSJV<~?tLGR{ivIV`bZ$_eFOVibHm`w77T z8ijoQpMUZH_kjhZoV2qRWoZ46Gb2xz|^JmN2gduT4&rbI=GtWQXo9KKtk|Avo>D^7HWQWI%6JwIY)? z=zYV6lrL_yPO}XCh4k!GRd0gA&J@?^d**wNZ`D+s;M%Y6>U^*E<=v37tV&PPU?e5Y zUU2u5{ZbmcXUN0?>#6Z0K(<>;ei^<ojc;zh%cY2MPJZ~Z^XH|WU~=iehmF;`VeQ$n61OhDH?EJT z0y)?biQjLsreDy?Q`XE)P1z=Uwih1`@9iC)@Jxeu^j%53e~PI7Prao7x8MIR$OwcB z_mw~Tdh-G`QEDW|2YTt!IX}N=f+V<(z(F}tkaq0|KcXsyQ;_xS`2*eqX`xP2)+eL2 z7i`9T#ir`ZB)4A8U%#W^;r`ly%CuD0T9%QL6YMea`N0rBmaofs_gxnaUclX7oN{p@bO7aSiW z#9lP0y6WEfu0|Gw+HX^Eyt-QU>VCAYZu{y(0O2Vwi9;kH+pk+0U5E@@x;)4{wh3RQ z%X?oIH;T3(Gom;^}1@0E%Q<|j-B=6JiVP9RrBn5~q%F0y)>SfBLQ(`K z+^j-VMZ=3;9pp(#IGQ>SEZ+}rEN2Mq${IQk900u)F~HW3N>6^Ka$#Otd?F=lKGm7G zg{w#c|0n7C;oQC3oxN_c?ZzLCn)9D=U|9+{jYw8PX=HZUxjVhiF4;`|6spr8O63K4 zzWQWP_HbOr(%JQ;;G5d$XFb_WPp6CXnnBWX9MhDn1VWO48AaR;wOTrzdq(oP{rfvn z|H`J@B4Exz^6LS$0=c4F;{%i-eQ_vxjgg(vwyRlw>g2=M(epxT0Fk`#NlIhfV=60^ zk0Eqp&Sev&T#xKx;on$T#1phv-a>LR-)tXBd@|UR%auXA70BNjpdaV7fbplaengiE z*NEomcU2H&4dw|Hl<;Rr^NClwCF0YOci_owo;>Nt++@DVeAZc7*qbp?Q}07_gZwVh z6_SqmltB_~$gP}j@5Xxw8j~Xr1nqpK)jIL1iKsNhx4p6Ge>zkn-WEPj4>Ta^V2 z_R8}7GV&QFHE*jyN&ADEleq;9Bsdiox@8Knhc}uP-#CWA^d{uS$6PFJZy73+Q47)4 z!qp_O*O}?@-)?=8-)9BkG0S}}?oXD3U~W*Ye*trI)FzCz{&deCOy4=aq8Olaro*6Y zXNgqt*?f=REwrO4)T zx8okJBr6G+k>@@gUkOBDhTuDnojk6+s^lF1-m`n*68wV?^-eT*W+)C^hi=zn_PS&& z^&|h&Bhdf;Ao@T3JH5gEaoi}*DLQU?3@*V{1h_+F?-{>BNrwI~Y79L)25-h5p?mZp zR1At9!yGmhO$RBZXQ&S77{rI3}oNrc46`YXD**5!ztBFT^Y-z}&$Up6}IeyY<>Wb(Ws zu`zgRh}TtU)}}0l8HN_>7_rh##??8o%mF3X70Psd9@QahG_Fn~yXHl3p_yZyuAy;# zB>xCmx3v+hYM+kC*@edwV?&R42?yq@CUtiomC~^sUzjf|v>h|U44HIDA)Pr!B8tur6?F5VTN?w?l*cX#(+ z7@zzey_$N{tPVNbRTsO39-KL8nWPrVa}^#`16jj1Hp&9qq;Ol`DxVk2h*aC+Bvq!N zgA&Zl$Jiqn6i*QTCB7idN`<;)SFgZ!u_!DBCNE&Rm*fs`%>zzf8hafoYUWYT?=_G@ z?ex67tuqp^A2um4M!)K;%`;t+K3=Pd!Czujs>OzWi zj3~dp#kgc-8a^Tj6aSXu#*_?`frnImw>&=Xo`oF|x-rC(pRi9m=Fdw=xyBJc!Q* z-J9ej$5%$TSL+||B#K*NS<7<2DY8%iZaSu}r6mKNezO6Z{60K%{FfUtLroc5Pc-Qu zNtyvT{L-4wl|l3VnaVrqb4|=R8Jw)>AU7Vr`h#a0w{PsyKz$^J2(Xm-SY}94ASqE1 z<8y&$VV8I+?4*^Mn6w7a_J~p&zbci;kQT~!b*m~r2SJ*JCmc$?l{FC9g^S5Tx zZFDg#I zzKyj@^{&HbE_*0iQj!JLvw%o+yxAX7B1buw<{auz?}U+bLiy&`v)+<)K{3`c_F^6% z&jm;9qazULaQPtuFZO*ZXa@Gs?5=lxQ#R9mnHGn{%eOYEiPIh^m=wWIDj=t?qr1EA z<^6a?vXim*B&kxAL@$a|&I6a*!`Vb$DSOjKn{eQEhyKr?#JRgzHDL%N0m!%P1qHGp z5-hPNh>ZN`$pYM=<7oe7G z#U>%AA_=g*60O}w^bs=A#g0gr(7g=xbqVGmoTExTr6H{*75-XV_to6J2VnHk;F|^a zCCT_cp~3|TU9;wKogs~gR#^8?|6P=~v1TP@S$1#}R3kAlF%H&#c)mv8q!M)e1`{dzoHQ4|UwGqS)|;C0FSu4E|{X3@cC zX%lHF2*;ck5QPf?6ONUeFyJdsRB6eZ7pq?hPR2OYtML!y+%;8kaRE7w>ujB)JysOk z4iuj{o?RAvuxMH|XrxMTy-S7`!eKM%_S9L>g`tDb86I-KtsA#D;9)`Lyk_FC_Q;cr zFYMv|xQm?CN!^hw6?AGAB^66%bkC8#2~8c}1VKSTzPgu)!lUA&)r-qcr@@l0FOzP> z5GGEDGYHU6*L#F~y=ywd)R6fS+?jd`lg9f3n=R=AY|~u9kR(@XD~ug9 zHR~X??Xy0g)KCXTo&M4Te`N+`1(P?!#OwjdIT}F=ABuyIiEZjTg9;b+F!qkg=mYdJ zieJavTCTEC#CV>pzV-ccfsQ!Qsz9G^&TxB*B+^>CWXvRPD6nYJboRDH47W@YNwiti z;ovYO5lIh6k|J0n1M*CrYRXG*`=5V(vF6ft+ElwP(Pcg}R3ok3%pm-}-KNB$A2~%z zA~7hrT;WYcEgSo#vm*^r`6vd}F#nEPl?y7ZER4~o*cl@Nt;W+ zRxu#RA&BINROs5%JuIbEYj=>Mnh7OSMUk&W)Nr(*(wDVG5W3_w{_|# z?k=3amDGu{d8|y`RnH74@+Y+8`;s?EauGF=0^H^NEqi*0$E77INM;Ay*@{SIcCXGg zU3HMF8g|+u1foIemBDw;YMiEbTG4oeiMxqipPeNENE;-uatM}7`6>o?7=P)WzZFuN zUetsnxj&u|o~IEFbP9P$TOPGSAwMUZ#A=@lCRPeZ5iQhc3EW4v!PdFzMp06;yh(fd zO&p9gGkhN>SVb;8bKUzXWm+;xh2$Qp4J|O+rw1t(n>zT!j0%as3EV_p^2Bt62`hev z^&T#|iwF@zRlL1wpN>g>yqanq?oMZep$yP*@~U&Fy3#8Zbw6ALX2Z-HU?55H>C@}i zpW5oxQCECp9w_O;_1+0J+=Ae<9MrP{MK;YD%boC!9x@r^jim0k3iGHW$j8;Rut6e{ zE{R;qxES0Se|aBg-{$^3mfjQdhkdLgakrlHq?@j+cw)Q<-K)1>kJr4Y-?vxAMfs0- zUaq3ece%fh5t0W7PYFD$6HU07cFyKj6l^!H$ZtDWo2~`Rc=DDEbqm`UyCA}dkAwpFb(29_ zF0XJqv;aq^D;{0~eZU!@AkO$|DcmxSFwB%3f{yb?D&*iPU?B>MlyfJu_`##cu-4VaZ*x!HUI4onNXJH!429Lh_9+bcSVfD$Q<%++vimu}M6z+|#dNQO32` z;`&3Y=kE!{@xAJ}DRH6*;DB&X3WS$Vop(%05!jSpSz3}B{)OzW8PXLaTU^JTba zh&dS$uG55Xzq{_xijK{VUtaNPli;kAVJYq_?D&F=7hklGP7e^)2%2u~^gMSLMM2){ zn3-|DO1H6mDxCU|jvPa&#p3vWt%fjq=0;^64MzGccXi;gVjnbiy-yRlS1mk?67Dj!k5AhH z4w*`Ic@1O7>S+imnj~Se#9gMxot}y4wIYWPyfu@3oXuhB%73F}*AyK$xZ-4WN#KQ5 zy}Ij#XPvkG9sUhUd{K&gN(oEV(iV6J|5{bE0zr#o9RKvXO<06ry=)U2V|@)J)ff|) zU)Om|_CCC9naJ=^Cp-U`#nE_K?&{0{V)mVSB}G3^@oKS4LTX2Y42Dwt@CIaV#Pm&N zk=dhY${Z#VHv#p?loTDnB0a6JySE6&ybfPEdvje-P)7a+8Irp`YFP&^r`y@xPucHc zmC#kD*lI2*gYu!jbFlY(N6*=#T-oYhe>}ws*kp{*xQcAlygpH3i7C_|j zWLOW!O7fAc5J>LCqFh>XJD)4Zz3mda&B{tP3X-HX?A5bDq4erU%x4qw<3Z*tZP;+p zu_yq0EYa3>C^mGa2qsbjomQv!6|c;Zop0Vuu}JVxzupFeLf3Y}hseyX6$Q)UAat)d z6=}%d?JQ*N6X~Q%n9_6bBv3t65chVwJhLgdqQz|h(Bf5D%ZgSrv;L65fzC-4-K&2o zefwW5qhh^h(lzRt^3_sNNt>@9so}44&U;8%vow16t&D#F&c{9H;*Z?ThM28K6bV3< z!Q`Hv@4s#Ox{MZIW#dj$+@x%?+XFkFp@EBvut+9koQGzh9zUXE%-qma^OMHpN1Fpg zo3g{$Rgh4NIc{3k9nuPHbC*j8o9K+~Bpaq0F3Q~Lq(<2?a}S<3P^$IduR;?O_a~3v zzcsz*kzrO$JoD-iM?!A!TS`U;J_u(Nr6M+5iWvaiP3MBykhX|5e>qoo@tuV#_@HNw zv-NxMzH=*lnL_*ZTuB_?oKx;x%E1TSc7W(hD-O1TNp8T&K016#P}F%sfBD|)4#x!> z9w}VKh8jx%HN_Th_GsB^Wt2(Lx=C6JS#f7f=|0h7{r&2&un5e$yDXvYOqSOD_){fY z!}i#{xu+v-rnYq5cM~ichTube-xZ)vO2~IV-l;b^@zxKvBR%OnDDntsd$IOD5Z<;y zWSpmQMrQ%%`_L|djASCCmA0dZ+cYp zu&%LwTu^uNPPEp{_a=ewuz21YtzOS==_ckl2mI#3{6^K8hjx(9(hm~IT;LKcnov`( z5;v&h{+6)Ry!Aj``m&ul`aYYukT3@HA;__oKgzZ0!P3b6br9}y(PB5H`F&;Vxz(GOU(J< zVzCiioT~br!+DaOYL-&?D9W<`;)pJ}JbZI)e1Q`^A zEFFDEu|gXMX`x{ax3>d>AM72reKmKrSM23+dbxlq?wt>eb?CjgeG+=KC610CEWM3v zin#w&UsJ{N$H9&{TlMPvQHrbCNGu1Q1_Q7+Z(oNqO4_{VpfQZ0$rh3VBN4xVyPFo8 z95w;0SyF7qk);|o@#S^puf23Xc^oxv(P_ZPOsk{i-(U8Sl8Vj z<7z0TKm6e+*ZcgTpV(Gol?T|jUn}xIt9idf*3+=@oqOu>q6a-e9VQXGa#nAtr9c^c zUWo7UvZ=uW1AiacMg#dzp zAwUq2jtJ5erB~^_3rOz?AiXy!?^*BnojdN{`<}h;z2ok4#~I`7zhI3)$ee4sH!wx^NH{9 zQ)@bP$rr^-UZb|bn75^F(A*CT9j5f)ebFJMt1yG*8+3KlR-g6I_+7~yEC4D zeFgDgC#A6RJuue1wP86m6UQZ3#z}~9v(bowFL}cgGlAsgL9B5zfx#qI3DFdN zI>7@;P5R{yGJr|_3UZ-Z228`^(oRcg5Ua{@;JtC2>{CqD}d>|79vj3dLd(DPqB z`+wCADEx2P?6sN-*z11JrjM5{@m6@WvDso}jU-~1v7?u43Vz#0Aj&^fYFBP?r?_^+ zDJ-AI{h^8b9k3m1E4MfQ7Z9r*5OU*RUI12Sw+EJo%o7*&a42IKAv%@dIHw9TzS_`7 z;!xGVYWJg1?cXa6O?d>d{$I7Mf78y^tpDr7|KjFl{MQZp9}GtS)kyx$SpQ$W>i;@p z{cq7orUte?|G0ldcOnSG)V=JC3EX>ymc)x}Y{|3S{WrcA)4u>q)$>n>J^pL!Y0uZA zek^UaiKV6PMETr{6jgiIt@ef)cSFv*12%&ZA|n$2Sj~XBAXGQjJLO9K$D^iS$97N0 z9Mw*bwYd(}iEJ56sDo#(p$`mODJn5yu&_AJS5I0t92zW+=1dv9IRTG-txE#zOJ3TA zL0?*41zA}y2X;yaVt18XgCiR2%Blw)vuexUXe96?H^!L1vcAw#FpJFA)X;G4fI$mD z5fk!E$k$Kk%_1j$#q7$?)x}gykVxtreTY478Nl)8ZLc5EIxLPWJ4S0>6=6`?z4mkz z-3TYyvxtAGgPj}wTk8I~%+B4$r#hte)+_M~?H3~E@RQ`dJsO3LC_e)B*XUhl^J?Fp zjur2CdGkAOeT%EerG)c7;80)-u5?aG12wcuewRP>W-E(oFDL0p4C{vw6Q5c7Y60+A06mfaVy%FT-+jt_vY9ehPzd9c$ zF1jfdP8r{ZMgk=3l1@xE_!sBNUCg_nceo02rKZ>$jLB8#FLMIRtyh)N%|0~q&b`)9 zTUSr@n%~zS@`fZ&V7nAV_GT=x_4DsNn`f_g!D1~fHbk+Ce`sKp|6R)l34&^y{8Dtc zt*{=b?2?Q#!;8X9u{h9aLGtn*`~6OPCY~lWQrq-Gf`@tnh zP)@H7CtnbSS#-lPRplJkHEDRe?foD1QjcQsqe!$Sauo~^oL6XAX#l5yK#A8WHKvapXu$;Xomo2~&7Y<$Sv*3hqu;6nYHdERUC6@(I*! z=*u0vU6(EFirG2GMb3<8PaA zy89{s6AFCy209Orz-s`E$~exLwH0E?&gpb=DdzLuIa?5QZfrDZSgw=dd-|;UM`g)* zkCdZDSKOXH56yfnlJ{~0tPzIbKr8(I4XPEJ6z>Fk*pPl3hK`(B%I5`sIdoJ!(2qaccY`{kh<5=LP9fuvxvv$NYoYS$OT;4Xu> zitnsP3_ZeC9R&6$Bxh`!59=y9a|~HGB;K02oR4Uxq1pXjdJapcawu~TEV-B6!!*_* zufv_mmXSr$7OnZ(27iajZnmq@A{Ews3SR>*uiy<{=k&t%9G7Cep}do5FK*`c2mkCT z0y!atSJi{4GfbX!FJ+2RXU8jilK;TClA z+~o?Z`>#dSe7kGj!f;NUW*w-pHxdBR^bcVo(QJ;A6>3NbgFcAkO8x#C-J_)J2wE)d zK4#EZX>Fg*KCi`61gSB-`OcTxdlLb;xRx#>TP;4^6EBrC4H7A4is}(1N`~-|<`P9< z@FGZXv{)c$$6>rnsaIMadL8B#de1Bxtt-z7(gYIRKWiQ?)rL{mzZ5Azo%r>Op~)aM z99cA}dnW9RBrWW`1cR!GB{ehK9ToO$hJun@m`F6{YNhEb9BGi$+`+S7o#jD>3cOFa z9U90vuV~!IlW-11)B4mrj=w3)({RmHfy{!=3m!bo0_;(<^o)P;Nr}Hyo)MQLadYgf zCh3Jh6u-BrWbhP+-LpM)-@N)VhB1?NSE^S``Z^-i8F3S*?>9S8>@@SU0-y@%%4Tyw zGBI+p!rXPE&-F;cp}kxLClc}dHzaDiJ=8LEWVH`nRMt{r-rXo)4A;_uG~v)RG*IN1 zR5gv^!u9&%y1w)pofpE7D%~SPr}I_7R3@%47!;!d0WASkH|V?3wD03PT`6=1I@gI@>*`k{fp%f$G;Njv@XjOpKT5^o3cP4l=^M$Qa^@>I`AKO~^}?%D z&6sA~OIqNn*Menf5GUw&=L0fhDOQOGn$+s|ex#W*B_Cmf;KAk!a=%D5)QtKmQBpt~iQ3pRd`fo2^N! z@B7<|6tW{5D4O-mJ-f>HuGF+1Is~^Q``kFTg4=m5O;`szau^)odS}lfd8hn?JKvoQ#o}~G?Iz%=v)fZ9&miw&Jm2*8E|9MBG-I(w^Qh%caiEu zAKft(7-BLm4erQiEKj5^Y)~I~>6)2>hHh16r)p-}fVj#=nQDTxWd$fg=X+9Cw}WJI zZ4&s}*%P^hC~Q=@sSgQGb5VA3`1``(Jtk1`@O=is}0%-iX z-zl&qxXJbsRU7#hzWkDI3KA2%7G*2V{aMxQF#WE1Z%vXSk*&a?aW2J*omTc2$ZB{} z`_r^eYAHg(R3t&s99P*1#n~2q^^{Ga7Z7ME2%=y>D3H$a062xim55PLb0q{QxaT}9 zm!Pv(`PC8ItJEn}kKM6%C#r9O*U*o@g>y{JJVBj2%adifKr;v9S!XwUj6DxJGXq@ zX||1(1)CZ@$@=8EG2UB~G8!Z^5jQC)GA?O>v5}zshh*T&YrrL`Jl#F_-D?FpWmo&n z$LhDDb&HujLpWUlVUSWKjU9erR=Y#?Q)c+(45gJJ>03i~;uDXv=1km~=T^!$GerQ@ zp);&r_hdRsH*X)WolV%FPn~%gvNn0+LAvc0_#oAumezzW2gDu89)H6zxq&sJI2K8%o+GXTkF?dG>axcNdTajCnsFgUI-0$BLEv2}*z7#z8l zL{)O%uT@jXncJKkWqSFb^G0jmb>C)|JA-E9H>vq?gO8dqeanczF&gkt6gy`L`etbO zj0axfR<;zYXZUmT3lI@?dNUdPm^>Fu6@}g#p_6P)ViTKk&bWww*P?sb*RkO_u?a8SkzSY zbZ3Ow-R+Hia?; ze|Ny`v_!7A6MjFV#5ZlON4tEjfCf3IxJjSt23#|kVg?y&pBR!|dG6HSlzn*#D$qub z+8V-TxebGHLHRaEYIh||DX4;|@eLN*(JH3-iz;13h!kuH;EuXGExx8xZE}C-A)g~m zk)gP%yO2GxT?;fVdNc}vVM70pQiDx4+b$71q1AYp*LiZ=BG17xL~l zsf(097D>a3YF)_IwWrJ5HMPxgL3`P?SG3yl_|(u0F{9<)(uYSm-tBo?tIlic8a@H( zdqacSIyaVAa5D#sHJmvU4_kKxJ{j}4G3#`K+^BN9Sc`Ak#aI-4FWLola8&5jQpci3 zCRV^O%PnxWbK$FBXr1&T_H-2HG|v%S^(TGcwYr4z_NoCmL9;Wu zaV!s?9&W69*yfrUf6njse^+rv|EQv-tIiBuEjow&FPIMbkHC(9uUtB!2YLC-J_8V* z%o0CEIBt4;Q8*Xk_U0K@TI6xpmO0o)@ls=7zdB}BM!2IFUiWlq ztMTy(KmQ>NHBULK^v^5opI@1M6#4GnPo)ZPlPn$!(-4Dlf9)XsE%V66Vl>I`_xeKl zlXa<#!tdrGywUx_`Zl!8PBZ07G+tx`xEpEaKu*k()&$lyD*5P9bg0w&BRy_htq=Gn zYNY7B`PO6fYOtsC-RpIhj|J~f7H>^lV~qU5?638JX*!;{P4lA`iK4gVkNkU$wRpQK zfyD}!?@b|}E-6n*xh4p$%5Kfb-3Eq--EB$>?4&rC?2QyIsAbU2HfzJ)DqIKgFC>S^z?k-pZnO=!km+#K@n z!$k*uHR<@BI2-Yn=4J%tvKl9v**zxze4N5#xc*#3x#(zW1jF4@wm8fY$(`B$OY0s5n zQln-pMTMs{pP-@KX?#qBzpTCwo0^?g77CX0Ab8hFh5<=nYR-A1GlTYiX0G*hbx#MX zK9?;j`*y&hI7kD^ZhQX!N-=*e^4sypyL!0WI8_dZQ@v|6vv9JVXdjO8EhF&$_AP*~ zPS-=_#1#%xZqFrl@yLnHnYtdo#N4|Z#jKdyeW;{*Gr@6Db;w+Jnadm1CYL4_9J#ts zYP7e&`je|E>{SsBnN$Tz6!^0Eo#e4Ot7~T`k}u6`t$3}=F?pk-zY<=mImJU3LZmZZ zj+YbE>=FhtXde$BAonXL7Az-O%(=-32$BY}gL}5MldY=a*;!wwf5zO#nnhdQv+v5M z{K%F9G-r?zshpo(@Rq!WXe4(hS-$Rg(0Nmos`?H|CiB*Z6PfyP4-u22 z?|cr3R~qYi-~@z=dtg|R@MJh7sUM;JI$DY%nQY++QaS|HW=?V3khZ8Ntm>$`*PGXph(f%{ae_}lFEwHYs8_GSbi5} z=N}1n(GsLx8Q0{V_J3CRwWA+~*!J7txvf(8>1FY}vY# z@h^a7M*8Wk$9oT6E#hBQblg%OBN-#ViAIy7%x7=#Kwl|p4PfYU4gC&SF|jwpNy3=< z8sTV7m&?*g%Z2d{{)cvQ;wq+PDtp9AWvgf=sK=nk27*4t0VQf<0wS zP=Lo+M<%}a&0IA*!SVX{3>1hLDtMW z-LY%jPptnSp(MRNKO#N<2!upl{ay9cwrj$P_PNm{Gci#RFTe28h?-$@Do2h7)rKPE zagzZarTWRX&-Rl_2MZ`0q96UtEqal#h_v+FY{v=$+PJJ(jda}__1m5wI`FNx@}&wC z@2Kz0N1-~&f)r4js-19-C`ELIhrTQuer9f}QzUKiWeg}&(0iDbl5a)i!-=H%n7L%_ zu>Z6xkJvT*`gJ>q8SW5MA~8!dC(#?zh9=FEwn9L@SJv-Z;Mj3~)3c(5+8)@mc4?~& zus2kxb$2qXX<#3jSg0NqryxFrtGvwjh}PuHWnRc{B%9$)va-nvqO^H_&B&8?y-R7? zvK_t?h?DuQ_IJJL9r84tm_EMZjQ3UP#Hr89j)oPJ-p`xLu&8*_^2cIP)5$&C@OIf@ z9*6w*y7s>S9o?qFrYhoIw-t9G#BZ2n<-PWEtA$8CR^`Nz3o|!ttGP)Voz9~9#C4~~ zce-D%$Fu8U{?4?1ifgt?8r!ol7!7jiO`!qZufscAdIf!FhPLk3>q0E5^f~e4kH829 zwa}NVG-v{nIyTT`B+=}UVuXF`_SD&6`7)RZj26Sr`M$)^R$QE}Pu@6xetsI@c~rhJ zo&IAMw$l5o&~-!eJde03`(muZp>wjPuWj9}57}?5N1pJ>*skBLZPR*CD*26~5+{@| zNW(>kM%)?KVnKuq6bL;Z`3oraOHc4jcV;tjjyyT3W+Sj8|BMRy>AO1T81=lNOwNmk zACoA|G&_?C6Soe&IfeV8BWb{tp1d8VPcUAJ?w$IJuLcC@3gNE@)6#|;5E!WGdR zw@0&Ts`1^|Z%LukcZgLURwmX4t zaJ5RILBGYG=+Nj5l>%75`<`V9H?lj{yN$#T zJ$_3Q-O+`nxsnH;+Zn;!8uXJ-icm$%8f3-{OVO9b0n>09@ntw$Okf%ca*H;cY492s zmw`#wmwt{hRU++&w72Z-H(If5uU3D)W2c}ft_os6Yo3)_2=)1h6Jmy-?8w68R`FbZ zt9RC8Q6XGBF0tZY3!97qdvaPQan~Lv9DO-QQ&PU+U9b#wlX5Ymc5d^jseahTN z4<${ORFiuv)LV#gNz$q*%Ungnd%qPub^gN@+rM1N=@hx;<{MONk-h&nM>dT5@2&mm zLthK8J|6U5VT@#^QI3DQ&?EN0id~ zd-j(;@W#DzXjFh82&lgMQ7w?K|BmU&M99#$rl3Fx@~S?z6yxI8!tdHAx!-WD``EMb zupq!CQ&u2pJo99BkxSz0Q5DfDyZ z*o>*U4^g3yfDDw=40y9$-IOgO4=E@tBJ;Fqh;hYvafTX4iv>~iq1u$MMQ)!b-bxz( zP&{ee&A`-n^Qz;|XmaQDW^g8gG`!%QYC)=OS?Oy3)S>eT9H5GAAS3~+JejpyE!}3h zQ;(vqwf5u#mKd?H$_9ndD-`f@3QlL#CIHRUe(vzv|LD)U&11^M>CnRi`w<$a|uBiS3()0!K<3bg(VX)7SP(PtiM5 z%9L{Ha<~Oa!*Apqzym4EtO^LP-=$5y7zb%eEnjBoSDKrJ11(s4Ytne8d*1f?g`#N2 zbv;lgMS*zdh6eC)dw))y?|vs0W?5b;K50R!be)gKx|6k054FS>{ zhx+(>s~+1$?Y$eUm_{j;4x;G*)LRkFv=b>Sps5}u`GUz1>dovR;UOvM09d9lk&b@2uN za?h?PijcY2omCR1F!c~4VqRp}rWF|Sq+!GO#si(ZTQtUoQxEQyeJr1ZGYD51K2TDb zxl+`xp(J+;Ef3B9_4@v{LE8~EzUULEE9OBEkjoJZ*PH3qsw3wrr=Ey8dXV#CA3r1= zTjngMXw!VDsNj?%u$1oUAR;R8ew6a^OP9JQekp}w*fd)9A`Ad*m7X@fW-%7L-x1OL z-??bE)JBHtLftc$_dcs6SVNcm=2BwX*$!lXCCr&zVV9ghWtx1G77F|&NSqz zOo3%(6ti{Fgo4d08uO@)B9bE9;&d$@2FBCF5AWW_)p6998+rJd@HaWE8+k`cKv5UB zG*n@Sz}0A)nTS2s+@&3=q1y7#i#Jmj9vf3=lXA#Ezic^I!r!94;8z`MQUP000`b75SunUOSKj- z8NcFPVU<|3*thQR@&{T*hVMyLKoJo_@i#h~G$x0-@1S&M& z-~%P}+scT*j#UB2_zfltl(JSATIm5*aB%;lB|np|tU+$RS{w^*H}{S>m0%xfV46@hI>o{6XMy2(JS(JwNFcnbbsVM>!V_OtFkbPhnI zC7r@GeYI_@M1lm1TO{YR326s5#lD`NHz}Y-|3*ze+p<(L9Gttnr#}~oN9LHE*c(h3 zON)RlJ02SK7-YBmT!kQ2IRH_x=X+OQnSi!$vvb zu7hPc{2U~A(Ea@{>0V6KZL9DKK-Qv7rBT|o{lSK=-@Pw&dCOaXw}fa*jlvCHb24I@ z_j1Nzp=$#Nb47&eCaM1}WfcLt>BtBGZQxm0Z0wfqz8pn!VREySivC6d0C%C2fJO6M zh~PzCL>kF4G7J%O0xWArgBcdL^@UD<2^D2Un!Nvf(Si|mxy;;&m|OL_v%VmzV2cRf z&Ynv~zgpYdaPc-(QbCwoqJ1##Zu)l!qDRG(E4GWAHKHfjPs@BPp}e%F?cNs6vFtCWO&#Ud5~I5>q|UNFFZdrxWB1a#s$Z~JTN#z%r{#qrJELiP zYB85NFI5>YV>BIkATAMe_XIRA7)p!FjOo!2OG5ZF_>Co_Q4=q2sv@U8ksUA!eoAf; z)7YIzejn-?E`q-Kkiwh9iz_*(N3|a?rP6}tXdAQR*||0F0*|Ye5EJi~_*BeK9B8)V)fq*^c_R`1uf@Mk&lyU;#OBL`MpNLJjbr`yM4vYW+Q zxoxS68v1}uO|v!Q$In^c8Vw66Ht>fZ`texmBHE8|gO}l?P-)WFcC{HavV?ZAv5mB) zp9^J{kY2$rU96iW4>RI6qBY3~u^5k9wS`LqnR|(b;~x;#n0Qb74Q-5biu+k05(;S< zo!yRAaZ_`yg50c%X5+X0!fJ|ycRV6|gnUN6jIUJ$t@Z43e>3g1GA@_aGj$@?%)K2) zb|3vsl+`^1iLx1hJac=F@heZ3oOc#DkD`(ayYO3D7AGx_lE3RXnkpbbQ1WN=q}k5V z->|r``?H{Av*cntqDuLWj-8`{yL6sm@Fc{7C+m!vF+7+OervJ+gl zWT&(nq3Ufrz}0vqs#bNc983Vx(n3jS9L1o_V@%jZtI_t#7*WE7YgS9u_$dyPL;JRd%`8gNNJ>RdUdlTpZL@X~WT z&1PLS)ExSxZ=&d`)2N+S`$!j2ol=;Ztq!qNId0!BPV+jrm1`$UTQ!n(DMFdy^-p~7 z0Vk}V(CT?tN4p!npYNKTJ8gK+{QaOm$Ag!iBK#n!@7#~D-N;ckq+nl8paA{^q}e{> z%e#MPW+EE&{cHWJooG>;_-lg1OIoTR>luXr!|qaPmlm)xez9 zZyE6Xa^!+j&CLCFI(5P0pO+Ay*yi%fJ;Ejd$MzS?+7EUNjD(HWY#f@S8KVtuY+bF= zns<@?ZQieuXw~#>zx~JX^>dTf#tGUP82=eA6~TUaSuRSEkSZ%Rd8Z|U)k0$}ttaBq zcbTwrC55>dc~*1}NIi!a018lea0eWhF-m#8^_4{Z_}9yjei0|yG*3pTK{=UVLN;-??wsKuEhLrSbai zVaHR}3O8L;-}Td(xDeN!r~NVbrU|w8@>OnAwJAFl-R3yS6pP@%z*x_wKb+;!<=!TH zMxCX^jq}4Lg{z(?*)%eze|3L6->V=U_fk;_y#v<$rlRt zGoHC+NZB+{DpVSZV%`+Jf7W~)itIQbe9FvS^T}M%Qgs_^QRxlxAO)Mb>v|{l2I_GNJ(_u)Fa4;D#f|mh2jadX??4WeVAR%otI%Lj;OUDd6F0s?i({~ z7KeFt%*SRP0rnb{##7hri#H~iqu@UE#yh*wA85+743R*X5*UhJQql(p zmazrNPoNqQLkE$bdfQ`arxoFu-hgl}Gi$K;bfc&^MqVm8TCCCv&hb&v^th%~ZT|PK zAZD((rYu`@kLL51Ik!2EN4S&1N1N&%gW|&oub}n>YxJ9tr+CrppHY7ShBfR*TF~sD z#!Hb42bDu@1xN}~5!0M%5o78WmlnT_v@EK$GLT^xU$PK*SYsJ614#`mFP~!$Bo?G# zO^H0xbdm$m>=FNpZ;hGoq{Z@^rWqTS#2{x7AwyoJN#cduGX!Nt9=T;$ z?M||7(Z=#og#}iGq{!65yVGda5YG?gsH$!gJpn3}-U{M5^kMf3jrC5+7dlKp9aYSqP1 zrm1c5aq99>|QrQ5O*|pfVeYKmvc~e}a<98MEj4xvQc}#)2 zqo9Kzr@^wP>ylrek(6P$NIkdHw|e6NXyO0t47z_DE}`g>fQX`6UCcrTcR{>5)JKLA?H~iFnm!w1C;|miL1z)%Ajo@C^TQtzV4^xy>cug%d0ATUf zPGsU4x06=>0tRoJn!7c7--MOgVs$l7TO6j>UE06x_Hr0zPZ_{iwW*vUU??_kFRcBm1V6Pd2cvfN>1G@ zdaE*hQCb*E)N_2x255*PWgv|%jt>KepPd-+C>hsj!skrQ**jLn_bP3@Eu;7cpwV6) z+aE^U#Yrk^$ZPDUf`5bw&QVo-Y#=}*)*S7#b{tAs-WZlw-S6jcnPS7-aMMSq%AO|2@6<>vg-NMjeQ!K!9-ZzHvQ?YNNdi8d{mqT)!h&Tm4-I zVdl)?{St9vfno#LKo9>PoE=z=yOX33<{SZx7l?Dl{$Zm!hk_8;jrr3J{!aEcF%$@{ zI7{jeiNywRUA_u#IDO#xOm=di0XVP88f6Yq6-s-l`1UOT5SNt=>t`h)cv zEvHd{Gvsh0L2nc1z+B8eLhI6N*$#uY_%(b{CWz4H0jyxl5k(sRr~vuT|4Bbb#PdGM zO#k{i5mP+dH+5Mm>O-Is$Z)8-Ren~Y9B&OtAKt%%s14S73+dKZRq%MyG3y49KyA3b zJICUD=o4Pecb}7$>OHwXvfdiUy(h+@Dy5T$z?$Q|QAjepuO|P`#Ux;@`42ABp|>Y`qauy_mT*H|-xt;AFc0986wW!&D1EFS1T<|>MG39X=!tqd?nx}e z+C;We4!_p_qW~=zZ2=X30oE4Y0hYT(u{EBF^~g4nD8J=0#s9BuXL5%r;$Dqs$x9s- zC}#@Y0|<@)w{VV`a{v0zx-W2VFP@)NT)kJV>>#bdKsQI1woY>e$4CW<#S8PEkG|3P zdUxnKT}Q{yreG@0C*&5F62dPt_tDHGnql2J{xK|c+H$Z~)eX&R#Qa+7pya%|$J@cI z=2t~sYI?q@q{fysIAUH$!_xbaM~AfJ?Oc$*>C@O~w8BcMdEWm~{q1ic4Y=r*1#%V< z$@vC`6*FH{80G;;(tLLYo(z{775K*g_%1?=VtiDx)o3wqe66!@2#c25)no^oz-}+# z`W&{s|HoqV`gMlOk1zCKf^AZa!Eq2sE`)5E8F}x)1zl%-aec8Tck){N_(e_6T7`^E z^@aPyKgK0;?r=A&U(%6pXm2mwF>>bQO#~(KX#NHRFHmYH;#iB zhUN91?wHA18rhAeIwgHOq0Z(zZQfw;5sAr-f0jT`mQvDpoMKGWF#L#VK0M9`Ljs%9 zB-L$+TdBOhL)r%fvjts(mq$CvxhEBQ4^h?}X76Wt^^O6)susBg}K12i%|kqib|e96wwUdvGuDO2j+1 z4s@m>uy9}3JNjzMoa0IybKl`d3!zUS(8iGdJ)sar=bW9j$Nn+7JEaiR!b~Zpecy-#_t03ETL_ z%W%MeNPuty7JpIzSJ2^{iW z&ED!WkCWJF|I^ei<>KRbu*{y9P)BQ&3$K{bQ$Yl0M>-6#Gp1n2wX{tWvtUJ30s5Z%+ z{jZOBAZfA9qU~;@0~*?|L=w$K3O09-8_a_;zOjKsk$uw5^vu`zg@rv2|Di>{%C=d7 zM+g0=KUBUW*^DG_%}u3I?7ht*?lzVw^JsZaE+tKb`8VdnFR;?&52f=|zVW-eTAQnn z9IPDHd%So^1xJ9_TklCVWqvUN9nl$AR9}L5l$}RNz~U5;x#Svq{7A=Be3Y8%X_Ys< zw&6Po8odW#l$i6V4bg`NOe6q-^YfSg0>T3hPz^*+~R2H2j+ ziO=5hT3kt4@9!Q4d9nS2WuW-dS8uzgME$Vau!rV1(_^J#z74rMaKaM1sEad3SS;b# zwW)p#uP&6ddvftY^sG;u6cw)G`JZXjrMi>t+Mq@2h1gSHSb$$eYQ60weU(xPdKC;2SL76k!zvx z^jwaKu9hDC6G@ot8<4h~&3vmwO;0AuK*CuhgCZa~>p{Wfnh^Bsm#dRo0$gJOqDs1* zR!=TB5f;htAOL2s*Vg8bX?Y<3BuyT}$Buc7Rt|hQc%|0_lsb+{Q#zZ5PK@jjFw0kd z7JQ$QwU^bwxhM??YxodT)y~Q1%U>t05GGkZIVmQ4OwHHXo8dGFXU0By2aF_r5`pt+ z<6pA5u*Kd{@GGzm75+K8`^%q!d9PJf5ks%%8!U2?2Q$b-jbGTC4xcc6Fg)!JBz5|P z2&RRQKmT`H$S>a;lwq7z6;}KeEyi{e^GBZi#t zGj8wee3caeZ!EtQ(ZMPZ-If z16HvjXUb&b^zMa{Sj~~z?RCNpuN|C!)nPuz)$NuE3c9lP#481tH19mUlbb2soFgQPq}O#R;Kz%a_gVv8v#by=9IDgO(yOQA%{;s7~ zBhSS2Kv{qNy5@fW2K(%8bJt|l;nC)FdNb_IdT3v>*x2~FWB-KTw*=VaV&3zrWjTc? zpJDK(IMgEEUF$84{2{m$|6muR-_r*4&Bt-V357JsFC*KC3K9p)Dyvd#;Vt@nhP)%j zjw}W!Ga&_>3vf+fGDgkzagwiH+)cd!71B#{Z{;ym^k6C(Z4Rhk`5zU z=PBu*eSYDuyjeI|Qc7?E-e5q8GCMhnm|V>iejc~%H(7f^O!zEPe?#bLiut!2kHE5` zx`nQEn%S_w7kiIqLa5Nuc`_jw5kbP!V#DMc5$THCYZEG?o(zdOcfQNEV#)e8YV?ED zTvV4cV9QePwaAsj{3NS89#m#U*Bwva$A6JTH!QjaDKj@L?A95ZJH==FET^24%d9<#;DLl~(?l1@ z^sc(n$9%%<0_uyPl&Y||#euW%auYG4-g|CTb!NBE6#^n;ylsCwW9f1LHX`0dl{+Rj z4IILk<>u*aOm{6)i67LL`Lk%_6^_t}oYogx8X6*Pw@SCMO$&T$?_&9yYXNf|W66!V zI}PAAXy1Hb8((fFMs)xD>UzTU>&YdD>3oZA;wQHHh2H%G<}=?++6F%%9E!T4zhWj; z*~Dp~&=k)+P?*f8zOBBQ^cnf>JEa)gq*9L|PL0WuEBpYFHhsy#?m5fFScQ>|g_F1p zwm4&==^>2a5|rJw&39X&k=0ELdN2Fk_ z)X~VpU63agF6u^dWIclqj}p`+jiNh}$pRz^c4FjQVMog{8kCTcpYqJ#vTKar74cED z7*Rdgyo&c^i|v=eNYf@WLm&Nbm|*@*Vkdj`cXe6eNAZWUPX*`u<&e_u4SS4fl5U*~ zKW^o&vG7Z__$xL+9|s462uC^vvKt>)Vg{0cqQlbh<;@pDjvM2w9t5chw>DJ&V?Du7 z3%Q?5D{IPQH1Wke0rL#JXBmz#d%OrXv;%T4gtpNaVcME)N`bg;%;tfVN52k}4Xx(u zhfem}PS}1+xVq6FhZ%p8#TM_70D^Vjc5D(x>5_dfAHlS z$8nmByS`HKt9YYuIuR|yYYMcf-R;HD{{xv?$5YG9NZo! zTmQP;XB2PG=3EtyoO4dGO0mREKeiG{92%+n1a`}ZK zQy25mvjhmfb<8`1x{{m5i~SfXbL6Kz?^UZxSMlMyF1q0(KqQq4B`kf70CozfU%t3z z^z65A1(#;pqUbeFr)iuFz>z3Lz8+urZs85z=dsqDXP8V?Z8BTYo=*Y|i{Z1Scu*VV z@8}~(>BTYIY=pg;I9t%6U?1RS3XprRbgrdP8H}6>F%|J&XJDeXJ&nEtT#b_^a>!~A zvHvFN%%50s;z;}fCPWp%V&eK*Ns@zHgvr%7D!;r4KRk?mCNUB5CE|A(i#b`!m2T zO+mYCaKQccwtD?pc9tsrNk%07@ODFfV2Tf$1t{y)lK&O^A_z6o(oyHTOo4K|?%XF< zfm2$yDz{4-zMwalMZI^5lF_?O;sS1q@R@&8zyL7PGC$Oukve24Tns#$jmP`-&wgy6 zY;5l$R|a~l%TJ8Q>5q8Qbk6@NL?Zl? zLqGiNCN%uo6ZH7w4GViwB9@Sgnt;MjO-E#-wln+H;v7k0#wmE& z+aPzyBsvQ4BD0*sTI2z(2Kp*P_>n2Hu&yv2+If=nyw1Kwvb3xN>68P{q}GbJU-euX zA!N zc4X_i{`DRp-Zx$VOUN(<5Obs(Tm6V3{`w*J6~8|Jen;uLNtdhO8{$FasLbn7DQd_= zbq2DMup*Ts)2d5#mi(?5=+hO0=eLeu*%kIU5=HsGlaz~MJg|^Zy=8z#7`c*yCm9*> z&-vDvU92qqjyb_&`s~gG3Cb}zcU8%U#`afs{=}_jSd-F69gCDpFbH>AT>8QdDuo3y zdSgM4Wjjdd6D3jFeH2+>w6i?DSJTYk!ZiLkzr{xcY1+VWK zWvQaaWVKQ=p|FXJH0R*R`RcvnmtUTpu@;2{7sWO7cWsiUNv-QjyU#^+RYzJi?||r` z#^M-Z?Xc}i3I#AVo{eNE8*qI=aks3j_$rnubv(R{;>x2-{b+H#j0A^N5(qeIX@CCu z>@|LtI5~?p-t2R|D62NlIO=!KF%)>C>X^vKz#HT~f~& z!{BU11i*QZqiRE*Qp?dF6-ofB0XN_U{8kYrdB8{yc{v6wvetcP4 zFicun<#!Zp*x=q2F)krx^sD*s2Nz5;BFkvFiZ5#vAsa0b@h88&YxtV_Tp8PL ze*@p1D3)gxitO2lx4(+rhp>jt(fTC;b7emy)qM@|QyQk$nJ)z1`^`EVn-Cu!RY@q6Ep~r6U%5M#^LnEZ24qzUydZkJR&@m>Zq%lR; zjV<@Fn!Wa-Ii1?!F0d+6sN+aBvEYmnfY z5{)$er!w2U*H5{|SM73kcp{s(mj#!Br6QEfbr2(7cu!>`3pYN=pjmI)h#C`}3JeTf zRW7^E@-_y6w)fccJnO1boDka+_v%+XxYz1cBY&##$>ww=p?~j!_+h-5>omo$rv6=_ zo&HnL;@Y7NJ!KxfIq@Y#T}LS8K9y^q${L9Fbkk3@dB)Wq#<9{n^)pLfpW+=WeQ;bO zH;Na^ifn%=>iT>{>c{hrH7EC5DltqCv6rHbE>$=h&v$Qh&H)<2I+p;BWJQ-}p*dXB zKg!xC2&FbJsT%R(RE9b`OTrDthyB_~mVwTkeSu{>h0xy9EF4|$ZdwQ|O>$>tMgDKf zuzp3Pz;J=L>pjq@&UAd!A(8Qw0r8sabhB{Z{hcG_%mL8-G8*mw$`ao?D3yuW1Bk>CESnK^p*#oaGGRe1M@?ew8-5`q-=sTuJA(G>E_ zHoGp5y$5f^X{jRa1mk3F)5i~kPUJp3% zJ=!>*otdog@IUf1&$+k!=k^cR!j2?9+4eHa(}xlL)rui;^7g*mhYc!QYYN&dXlNU6_H2!UhA^$2w0|pr=gM71!7w3%Dpl+qMKxt@m zvvjY3wX>p~wOY`nzSfIC~9cmd43D6$(Z+CTiRUv1y=kG8!xya-A0oCU`Y(7&~(9e25R%Q50Tn^rPYU=$} z_P)wD`@Y}`0fKZvN~D`8N|PdxKb7w!#+-B(xRKv^#D|D<$CXnJMmxxZ^(Xti)W5*TsXD$dOFX5G@h8YvO4dJ9jh zcn3TSBy!$)@ZgH}8Ry`6Zw3kdi#K`~?RVPO3KzZ4LZ3Zq-99+8Br&CVr71W)PFSMr z_8jc}+c;@So=Pt=&?VmdJ+8E`;AiusiObk)qql`BtwL`L-@h5~B0v+ZrJ?}73cIxr zf^uA(-)}MeEa{f!W_n>toy}j68wi7j>(K;`Hdnm)7Ur(M4)LB-*!K#1w1O{X7d}T| z%wGAz>aF&z;?%UInE!CTMW!G@h5Gp6B}s2pMm;U-%mG?}LCMRhF|G57Ni2d9yy`{? zNbkO?H{1az+1X4AOR{<2uzCX*=ZlF8@=D$%k1p|k>+ngAe4h=xmj+0 z|E0Zs8r*Nguu)$;!-v$GO%WJ`w|A*oD#w+`$9}n(PA{0&hGN~AUhJiMmexiimC*7R z(FylycrQYCD&#qQm+o~|=)5ZOykMlzpjfD7-hCU0D*wY$*W{1a>iXB~FOc<)k+q@W z$JVr58>}4`I`eJ}b8fBn@V+HTGmTS=>mGePOmLCWezb&jK%5sEy_szN9gDH!3rbpQxL2kA~mRk08Mo$mDPFS?Wa zU8c6D`84{Y*+1<0ZgK|1>(dSl_{ zeEm+6&f+-Q?^!_f_d7yjN$sx5PCYo{pr9D@dg1z{w&)+m)67WSY`x{Q8TJq3$V#y+SM^ z(g7Q1tE5MF_GJT?jk(Hr*;<{&xR&;r;W-C26o&8;!>!KJ!nol}w{4@D1a0#`-(0MD*Ea zWUOjUQuMLd*iJUpDTL##?HC--ayJD9F-##Wg)53CXmpcMa*Ba1M-G;c*5UgPFiwwt zWHnf(t}n*Ky0zpTM=qZS{?r#i@S{lkYaPJPANVKtiCD*Dqc_x0F z_Zt=mmQ^C<=a*jocvN}Zk7H1HxhHsWr_HVz1gey}{D_&7KP2W_67pKDTIwmw)_R63 zksm6?S&G-BpFe)Q^uG4S2kO&ALlLTndI8XS1;2deh4`(5dv4Fqyq0}g*Sl5v>d4|3 zP%1Ldb<1)q)IEJb-;!3btYDLR#MQs%s0kBsio-Ph*&FHQ`;O6!@{!fcKM z08q~U59h*_^yZ?OitLlqEosioXX5UWiBXf1S3{s%+`NzhoT?E|C_{6)>1=8DN?%55 zv{cgZ;~5U=r?1rT=4y8_Mb-khpIxnf;x8zI*AWIFJ;>Z}W4674v*qL`DCf7&>MXug zPpjK_k>+Um!qEe7o55}W?Xl+IjTq|ED%Ajg!&`$T$S?`l$91mN)-Lt&Dz|e(SxF{R z7ctKUyiIB_ARBV%ZL1q+(fJAZ>1eB#R0;MzN8ZIMVN};P8FbkMQP?kM>h70y+*>u2 zoUd=R=>v@%(0nXGYpYa`i%VY@J;Hcw@pB zt71_?HoxjhBW#qu#mhNeG5EFd`}TAkj8Q>yP+gI~?o9yn=q3oy^#aLaLogGwA0L|d z33xOA;C>FH6VGH=FXuy>y5MbtK||od1!x*j<9hvPGRf3os_FVXrvBEzYTee`Oj-Knmw_Rp@4jOGU)P&skX|xx(%3(JFE^tqPNDa-U3fsVISDqpy)!xP9 z)d|p^k3&DtWf?!tD%9~k-m9HY%!IEoAA`g2GVRnx%}dJsp=*lwK)Xm2&p?b<;zo&J zL~d~!D2)rQ=WhQ!ZR%go|7mRi;(q`2vwv6zR|DmSpr6>uL5NR&B(qLK%mYcwq?e*) zymRbBLB2tCvex9YV%S#G`;^cxbV z!3IL&5SKtm9G*7F=%qrULO43aQ)^WA`00mke)adOXHKbPm3ASP1cdAddjkfB^qAc) z_g&5Yg!?`v}pmm*7hYh7!|PVoHw4NURic5$=kH-3piflW#5@L{7h zGi+mTU&}*NPsR$;@PI5?H0@y1RGX#7TVh5DDTQ)iLf5AV^Lx}jB+)0&hp}I#f``bT zX(6|bQJ)A&0m~H~^&E8ZR3!kY=8prQ`QUZ+W3?xk-d%mFR}Y_7i;@-zz!f6!DJdit zy>R}sVvFL$dGSdEQ%_7ko972=I~Rrqy!ImdEWs<~?fz)sD5QTil)+$R`li;2r-L$* z!qQP!nMxSrr5cjkc(qzlJ;QU0*IIa476+|E|3Y<&UaZ=3Vw96311r_Ocv=N?RY^qhBjo%`@r8-IB;_>^vkvS_+FQ2)4W>ka8c>4 z;5viG_U`Mm=b@+d7V7NuzfxS}b!D53>N7(F0*p)ysG4aky=l3FUlcX~f7L<%9`q-T ztCbrUw|}Nd4_e=ROtonP?>NYTU6%Z*kL02y zPIw4X-T5C9izBUTz_M=w+qOkb+Q8f^;pB7|LSv%qQ+dS*kYL6A@r(J%%Gh0hzlL}d zhlZR+Hh%#rDuNgBxwjU@{KN0Y1S#mYDpS9JTIm-zCxXlEH)fVS2c!sgv*`6}=6lXR zA8na|1o3-pQPdl+$k!s~?9de0R>hwogX$B984aI0;AZh%Ehi@*0fBph=tXz*en`#cqK z$PG}Bh?~L}w3tY)`}6yq?=HYkKW`YlHHoRaeV@xgEMZp_kW|zWk0fOK3=zr%m~O7p z%-4`O8yv-+;E?@+$o1=mBq^fK;^G{e&S%W;G*@=?ne|IQuHV9xjx!gWZ=g3t;Uob{ zcoW%c+YWQ1^0s1v->`+^GKekgu-FixN_9Z0AUAl4(h97B6<>ab2UO3Y;uBY050An~ zZ0)A@#arzmIi{pm$@lfL-?m$r56#8k{S!}&{nUr%In zb_oM_5@y+)-72Sg9Q#3RVL!V4IybLB9EuHH|}xnw`fgG;tB3sC#&H}oYqLBlOW%7=??DI!{7C{v?IVc zbMxci$O42CMuo9D*(W4*`gnOL{qUMy2S zVm#FhPnMGZuuN>d|muuxhu~lUH&*sl#$C$KwKMbAgK^8sppjv310Ml zjne&@@-w*!GizBtxbwlus_EnU_;zK-U(*r$YGUcnygm`ky^#^6N@9MWcmm497EdrZJaey<(@Y|@jCH^zlvEq;!4}SdeS_VE%u=$$_Qd;?`1H<`d>w=Q5AENU_a^YfHJq>)#tBGhi%b&$y+9PV;-4tyqaYk3 zG1saPHTvYtC-00)Q?=y^Eh64a@Ui2R;{D0z&>p6a#PP>aI_AZe+2@y8Ad zv4ZP=CR%Xgs@MKqMYMlfX64IN0}M4W;FIX?*z^lHwwnIKFmZ*)=ft*-*aOC>4%BKB zU?=F?Lk_I0`coEN<{x*a%F=}8N_vwWB>e?D8!>E9D)4^q=dfIo!)A1z*At7nx`I=+ zd7^NcguAS5HuAy|BM(7WrHa3%+7NdA(b{>wMvF@k^mxQ}19tEYVaKkgXDv`^Z6hW` zY5iRv`vXG(9&N=xgVk_+KG&H~9Dd!W!A(U(`BwH}#T4RU z`JPzSSODLW2GuL-USN6{>t4OD;N-IQTp{SMA}16-$U#?noVPa)XL}pP`$%HJ=Pq?l zqjRU{CSW zX@erS^w7vGzg&{i^5g2HrzaZd^i|26llrjmki_9|Mf!(M413wE#iqQdl_ZkWB_ajqhDG!&RAlHC*_-I6 zT`4?J-M%=?;eVBB6XtL|AAjs)yN4d`w^+vguU95I?eU{J?DJRJ<>vavS0)#?+6YP7 zyx7D~$#ak0l~obTr~d4#lS!rj?t;bioH+~NCt(5mra z(8kWM(>2)W&9#Ku*Mu6CH7;+S_@63BoPf;!2ghj7OgyoWxp=H<{Qf6p0TQ41gSpkO{x2W@?PDPYA96;h?M^7TR3b{a><|{A~DwlF+n5eatcZW^lBlTsgzsb zjry&nR6}Wz?l-$1PCXozP#~<}^`_Zq13s34B2DwB>qaWvCqL+pa}v1AVAOFwD}su0 z-g*!vU@m3+@#gc@A!|PGSr>_m-jHEKhv{P6s^$PUl|H`DH#d9*Cnl9_#xe;Afia1MU3)fh@J+2zp&}T#4tR7a8$E$t`{?#f3vO77TG`W|zB` z)|2sv?G0zi0>sR3nD{ztFPi(iNmgAR@?o6=H>Ko1pBLzBf_@)_FM1^pY81`SsOZ1c zaYyK|qBKs|k}o+-PO#v8QnnV$j)!M<;g}z&kKHhj@}N*7Hri~U!R3bEkiPtNH?_uy zMY6BX@?T}HiQX81NHg-n2Ah zgTG7l1_qwg^iv7U=S1b?+#j|K%;2|4 zQsZN3xcs3~o*e2wB^LVT8EEjNGqt=ivCD;?0ujfvCm>;0H!Vqe^(HuOWU@};3Y#dl z=T?&@1ezV>OV$ihSg3^;j-HQS1H|8yO2r|rp8}1lL@#rbOmn$lK#<2wLuUQ62d|I+ ztap=9>}zqyf3&5Ch;Se5u?{MJnQaslEOzZGz%;aS$$!YhV*VbTF_vo0y$=n{g%9fMOw?WT8t1OZ-G z@wxq@ckaM}y9XamWlVVHK6`TZO9VFx-Gc`BHj2GYx4M7rTJDy*JI#(36v+50i9VDv zE{odqh`)e6V+xU&(De6g-57r2s9bnJ!U5o(!H(SQHr-FsWtcV-bCT-pROo4mnWRsj zTj$MY>LSkZrP_tLzXbRF&%R<_J_~GWpK0lzAgpkA)%$$NnYXwXh#fUY2N+gg*Fk#g z4L)F`!c#>KO#80+yj(v23-Ay)Fb|h6mq0!UdmxZrugS1YJ6*sXs^B!VCGsw?lk>(0 zHGjUwnO^`qI=FMTx;0EFNZe>O5oG2%IC`&0hJ~fPNpT zT$9R)uT25_x4zX(TQxU^l1GEy{a8@ubT;U~@@-X~Nwzn}zUgM;m&y*KTU9ji{O1V< zU*WnOUv#es&;d{4f1k!fjC>X2#3@d{6)*{)0A>$x*cA~mI3HhUWmuo7PWU& zo6w8ZL7Y_H{W&M(S6b~#`LcyCtvQ7ukJS;5w8yur=e>sJ*ktfQi(bZc-FKU3 zN^I!1jx9Q+ZpW$^s3L~8L95k=;1`uq8xBb#S0NhFNW4r=J|~%Okk=mC!@<5c_C|>7 z@wFwH&x{<2Z}2!nrnWh!Bvku`C}}TFY)rm>_rc^@bq=<>Y$7rqOk3=PRD@DDuYILx z>NvK5b9nFsIZST()W9t%iS=hBT7BW{Bmg-6sSQ^3(OS6vUCumS^^1Uk%qIefk&&6U z_eL)|rv3sFKf5EHk@sO5(GaWZ5b07)to$s1(s-SO%{@P z_&6F!tnLhiFWDtU?od-HvB*}Hhjn|8A3dMi*Ht~)wV;^`grRIm%8Qv4zIu@ShP2rx z#+=Mbk6r)vzH?iM`4Aag54fyN1}Cr^*edC260UMnY0(T33KDHo5` z?ab)b)(&qRPc{>uqBU4T$4hmqTD;``LfBO08@RX7f^~mtf%c9RUc}J`dH2%l-^$Jw z&@fX*?jq?T%G!bf4pYzvjH>gG+fWQ~m@=(%V82q@$$m!g*=C zc-fS+P-mWnp3xR}s%{F7UC2&zXM?@r@#Di4MvTragwq9w3cbwGJy{;br(KG-|!&bP5goc zxypj6NIw+PSU(Eu(EPU2E}UH`<7+WV>iDfMsoh|-mokH6ZDyCKu^*$eERiLuq zdaOpp^w^IojA4U+N1*Y~iYY939+#mxb)$Qx@f#Oj9a zS@i|A&RSCOY!G&#APJGyTOY8G-?EUC(o%j9;yt!hG`;#Yuq9(|;{)^OCADt|YW5VX zljby|-}W-t*xsO$aT6Es<4uGa>0odaqUr=>#^v`|y|x^!dR^s(o{1;ChY_@T|A7mf zd&jbOwPFY5B$vV>eb(w}Z->W;`TD1e;X!l!;4Wo3Se!LW*Nj`r*q>TcdXZgHNNugF z;kiS5+0!`p^+I{Mdv2(0eohuvsqTw+zM>ROQrg?-Y0pAmejTWJ@kXN3QS)G`=pZ)K zyWoq6UG=JTNKm?qvh1^WgD3Vc;s!pf>+;Xw<+HU`^t0}<$8bb_@HE{M}410mDd=N3V2G8MK9U!nUQ z)XBTZLGJYiL7#R6Ec-TU_#J5DUUW+LLO3!HN2uSBNjkx%srYTtr@Kn*?IY;L=3plB zZE6Y$dhy?UlE$@4W9{my8`E3_1Lkf@7^<&w7X}&wY*)^rc&VUH2s~t}t6W1&1#3*p z7q!cnm#QXAY~n_9cVp~iy8~pb<;I3x$G1|=mKC8=_5k}U;r@DH>c~_v)R;*SCUk}W z82Vt*7Y!kaeF)B^2@<1|8}3o04)ZFGyj0Qee;a{o-5M=FJ$)%a(f zmsyE-*3a}Lm995J@bZ$VeG_5yfHti3pREb}!hnJp;+S)%_MhpZNz2;ir|%0U+GZz5sY`3{ zuAt{2M4tx~(Q{(!;v;vohX#+k^m5tLac9O?88jY=Pw?q@X0_ySnlrNhdf2&MG$|5XY_dG_jXX#jkmtjh}Z=%)i!n z7SIZR-}RwKa0OAlQvSQ9sdE1_!`@~!mr3sWr3+h`y0zAps^`;6(KNA)ZS})k7#uA) zJD2`xqO7N1W1r&h&`s~lz>Y`L5JGK}I!-rPZqY(Mk#ycDd$L?j>R@`_9ydo2vWZ`7 z6CvEUBP{)PXdwDnaiwUbsPaa2Md-e3{n~TRWrN_Ta~T3|{lYa10e~C)0JyN&$Sn9^ z(Oo4w`+$4kM)$=5HRv)70n6*)cpLb;iTbtXb;LDG2U740TIN=GPKIeU)s zUsFYuV1H5{kH*MIL>*LNo;ODygD0q2y=gh!h1~fJ8B}X4X@wsjA^dQm7Gv8;Oib^6 zAQmpQ6e|=VjM+>fDpdV$J@ifLiyqXIDfp9H*ZUf8wHEE$(gab_>S=n@p=C!5b9MQ3 z0j*0qzgvm=_WzSdv!Lj>?|t{~ym@~h|6q%v*!r4b9AmfYvu?rv``fo%L-`J@`nguy zt!D$!y025oQc1m<5Y!q3-DTiC($4mAW8Kc%hG;BiCxwjXPT5s!yGCGyWJ5?esrP^S z_`pnn$-1A`Rg#Ifp`-DBMm2VBdrIk9POB4UBqqjsYx0Wd#MKYC4%#_S!Dv(&K;v+< zQV{E<+kcYxvTNsJ&oEzDFXS91uQA?In;1vAKjUSTLMA?lY;I7gQ5jLG^$+WNnfgp% z{mV>?O0?A8Sl920=LU5h^FHQHD!yEr?Vb1^9A?+E!RV(JPYz!xkJTimEZM)0lI9W4 z^=77Jsqpxd-QKA^wAXYLeGC(GRRXj0BO3(bGj`U^PXR9g871%*Dr1KYhfLVL*p zD$9KG%fEm_*Kj4;`0X!yW+r*xm>+D19m#4Pij@uifa&hP1kvyLENYKh4~{sEe!qSQ z0)G=g7kLJe?W2g1P|sfgxdb}o1|wT@f`}dxN5kyWdXlo=#%j3~p=!4*`xg+E8u$xP z{rFP;7eFx#d({hOCI9y91JE;}6!>;hbnxZ8gLT-Df+u)Xxc5%r>(eTg)&Fj`D(`gi zvnvqZ&T0rnF9;eczZDcwd^}8oRJx}u_9Ctc3fh3ePDlz=$vP*fVe|AWd$E#o$fsz4K*4N-o(F%Y zNA|zlvnc!P7iaaE+dO#ORCw$pjz3s7@M;$Z7Uxb*RjMr1J-TvBti04(>49munZI`U z+zy=2Yb;z&me0$2W<&gRc&eah@-`jXGTH&d%dga3!BC+os!mNTF_nU3NT@T`z?DvT zhrrG>>BnZ>Ha=C} z$jrMtGn%3_vofXUP&Dt)4qDnL4{|KuoXGP33H4O@GX3(9TYD&y@ zjI!h~K!*rjVy1<9tS}Hrnt-C|--#x>q?@=nKQ=SFMk_s_UeeRngYhk|qFZCNRt@b< zIH`qnrj9}9qLaP}Ig1Sh87XTH`?C=0bAun+Z2i88 zhcnmrSvI`HCiU@D!-e=vDUWf-C|Re+#TQaOuZ!7QMpQS)^w~i@d{UAV%@;24$=1IA zvg15|fC`vyt1RfhcCrTfMBuDr`_u@*&iT5}1rU~J2XBI+l)UM<-qR8m-iYscDT1IReFOoEgw`4e&mM`E+`Z(e4$J;&JN;WZ~ObM?9 zA;yyi05?F_{o79%82tKfqabX_QvbUbbqROu;j9c})6M6p1KNZ2UgqZ36-R^y6KRcE zpUz)E)4^*^c;XOm-t%OwyWoCeVCv{OD1JP|*~qe=t}=M|6O{C}SR0ydQR9srKI1Ra zoCaQO8+c0wD1S3u8(M>JA$8;^$`)mIXfjSuCel*nUMs?_Sp1O&x9+$LJBJvYgl!+K z_h;4OC8>6EQ^z;>KI(Y1CUyjq^DpG@J5FSIqNkYbEU57sIZ7*u? zI`P|;u5b@XYkDOc3uQVQtg0CUcxE+Nk{X{{mGraPrf~_0MWfn`E*u!7i(>qZ)YWN> zx{W>!KpdxakR}#$R#aGe+J=lL{pGy~Cwn6sK&orhA z5vqI3v_m()1N>dt_Q$i%%f^X)c~s}l?O}@xXUWjvG>gLo7tw*N*odABe``Nc&^5cY z^4l{a>}OWELi5>2;q?FAKg+E~71NXYSSROGvp&n)k|70s2D5EGBT9)Lsl&fX%z+Y~ z?g+fTh{pG9<+i;}SN+}qG+cn_Of{BQH8W|YWfz(pRw&B-VY+^r%phIulbf-~qBfv6 zGd1J=p}k&L%(>GZ=6i#f*^VHBB-8`U$w&)V@#X1qhl)i-4o3T=DLVk0G`E2vm1_DC z8dT<=i+t)d;K@nzfoJZvE@(bblDz!0pApN@z<>vYFF;oL#W&Rh{Ghlgv%M)ejxZ}7 zNj!#v2?Os&$HhO$;7$`di)lKZs0Pf{<5&>epiyE$$9l2z3!{PYtm(5R2U8kX8|nKY zP!FyKC?AdM;l+_h)g!{%*RJUhlHyM|^{ZtA=!I~Fse85cQ_Iqo-|1Uo;dXB|gHqo6 zmQ>a`V~?5HUlh_{-6&O0sg>&am@6}a@vRK|oBA(ZJ85X1R$ZnbT57rhA)6?>SSAHv zq(0?Y=NrKEC7L{0`>t^FKo^@6lVc%2ehzB`--P39-2BpAPsgPWtuWq|&gSJk-etZ} z$3(@XVXS>R!5md?lp1taRElAXKn0*C1G-#8BOcRL%8D|0+p3?MXh3PEotf^Hmh_1v zD*%!}8_dG9Ov8Jf+8d#rIbFJDYBRT_*4;jL@UD6LC+CT;+f!2?%pYmP?c$dKdc_l> z(Sk7Q$ixiRH)(AQ$zywI-+4q`9GZG!Zh_a+8iyd5tY<)h;DqLLrm_(C{_wM2L(HSi z{;sbbF|$pW=<0^m6n$);@GeUxhQ2)>ly`?kwtrf6>#x!%uQw66Wr3Nw2rZ1|j#DT& zMS~%>#Bhs}waad@c@zx`vrlktpJ_ES&&oV*@~&PDS-+*u zFGp|g^mDk{25$PK8>OVM82|iE$!nXIW#3D}Kno506M=+YXdHyQ)VMUuw0rolm0Reo zPcVtpfBvQzH^}Qlrm@~Mj=ZpYEI7H#=j26$_H$5D+ZXk=e2+{dODaxUyA5W<*e4yM zPG3#U>J8#{!TTPc?SO?3JkM;ua2v(eB=zRQSZX`fRy(RJ4~!E3%ScaqVv?_QvPmmm zy29QPAFt*k$B?8Y77{cByY{`|KtH+p{P~`l2I0Y(mpt{~wl>K@8;`pzyEsj~IgHiIc zGqkSp-NSlcyv}j^V63q(qc={naB=ag(pu+;n21$3eLhL24FIM2@;R1%2t==MeDiNj zhF%@I>|b*_hGeOQ*Y5=kBpay#=1ZpImCG&nuGTXqe2?vrY!qK=5%Ws@pw&NN_iBal zeK$DpI2CFYqJ!f=jh(@?wf6&F+3bY5cg^z`Zo+0PtS<$9!m^!eZl2taYn9HXD#W7P z`9JKpb@~7EP&NN<+kHv)$~9f^MDLREXvJb<0*PyDn!-}6jHW&;j!f9F(D@%R>?!uGG?U65gw`C$4Jk}cre6kPh_&(*P8$1sb8t!;BVC$6TpxSoU zUC78bpQOo+ZJSAL<5hdu?nV3f`o}RXPHf#Mws(J;lN*q?hH-Zx!J8=TCES?znnK5P zpiH3)DI$koGRSbD@gRW{eu>wAL1r!B5-xEBX*BgC>Eqm2$&tyPdJ)^~14<(|5Js7Hlw(m+eS}^=bew zgdCK)bMUEgskSceEi%V}jjts|Bwhy~9JZ#y;V35ZZ?&4noI9OW1%W}q4G;%=iCre< zfNAy8&L$qBq)r>XOdmhr+#rY2;TOl@dr`-~m|b){C24f|1PH=b6UZDm0j(`5Y}THz zbA;q68YUf^l*TD!GdF&;JX2OR?cA|0?$20G#Pm7PJ=cR9MVwC+CJ^Qvp5Ymf&Q&+2 z8`MuIzd741tiPyVtSM74wo4W(E&VQ60TvLMZVfD!t zsk)kd>jmTHjoE?k*t3n-_;>DW+9GHSA6|uwE*{^{o>x^+a_VGtZd2;G%ZNiEvwi2) zP<(@GT_qJKDZaWF0@AkJ{K zZ8r%Vo|3*E$5dYFBj@mtv3G7EmlflX4L8zbJT@cAo2iQg-o&d1<1&x-p6at-;jZU7 zm7t-g$Kaue@02cN)$X~~W4$)b25Oy+OepPNTV`+wCuhugTGpW8f+3WYA$~1$;L}>> zI|Dtjrfo(?y=)pruBs=(i4O-*113?0Sz)t0_nV^9OA@Z7HVWR-$LYLTno_p zdB&};U^i>AD`Lc*oefZ?OoP-ZbYRGjJ}160X{w&pa8wgi)&+{C>yco;zZ?59kQ) zi#w51NI`*XN@fMy2gM((UHl~{t-7Cy4=d9dM4gnKZnI(P^&w=lk24S?VHTIXnk&nE zLVRS4T6;X|YobrTs`2jS5ytIb3u2QYEUpOBkMT>U_32$Xh-TBlL>WAdGFmK|skSe9 zZ#w6Jo>X#%wv_stms;p>JaYxx(e{3~L(m3!9@%(9B+rf&Vy%NE`6`}PFs?Ars}jER=F zDN2{j>fT*n*1@JL&Yk5x{&Q!#P(bfP6O3S!8x+WHIJzJ?_uxYM01mZJewT<_Ya`(T z1mw`vhClLtNEBgD?KH+aPbpD##XT?4&RMHc|N;FPx{POI&NKtQbW3F?Nkj(7JXuEd$e8O3nFlb$x4|?-7oo5NaV;y@I zneT~t81$=6L`|Ao6-qDY$d@@T2LrlkFI2W=*Tb}DCJaQ>#p z|0qZQm%+|7ly-d9JiO-&gBC)_p&P_W3s6%@vs`7dWR4VgEyu;S#yKTC@p5467jU~` zX`SG?7K;7wQ_%os;$MEc{H=MlVx|1LAR~*oKks&KjwF+H<@wIHgM4rBo!ui**&g>f z)GxX@LpgiF=wP%|cPdwtt28{@)%zmVh2dC?gDZ>LU%o`>>$pA!{1nNGK;;xy%I zkjY7*9-+DKG8fE>-U`;^--dfCaBF2isIh{yZL2tG6WGWJkR@ih^QP`yHnq|)?Y8uY z&dIZeWPl;3Fs-deiF=po$)256@`m**9nw|{zDEoc6Y|Q~C{7ll37_vswQZ{cKBIX+ zaVgXrz+-lgqmeE|%FMEy=6xxR(gQr83)^?)io+k)fMkRAZ2hE2gKu5QCJih>@ zt~-c<*O59NL%hcm%5{+T0uS#VDvab7EA_**9#AQudqpxjLNl&5XOzGnB#4dKMr z{uP9Ha+@HakUfg6n!ah;Rr-3XHqZsZDskf&#i&r zCO8jXvTxLz)+@Il{?(A|K1M?-_k7y0Y!~Xomh=-r{4ofmi`ssRftl9+NHq5YLmWfM z)XH6*XSjG}W$#jD?DJ=%$)q4w=H>XVuX7JvT!gRObw82JVYnj{(|b8dQZi@-r$poa z7qND@)UhgloAb29(k?=kQy2G+$6+g;nj|9e;-M7=w%`8|@Bn z$bhm7cc`ltsC)^G?8W%FczRTX@#t`60d(4m_4O=_*>+050Q#y;{&(05Pi_%zAxw=l zb=u5WAt{5G2lvK*0sLOSfbmzLF(sRE)$8;7Fnw?}`V08xYCxM8ea6%sJJU^H|CSBh zyJ#K*g?~)YzMCX6cpz&66_6IB4_JSGe{&>BMWlE0^@zr!$w%48IA<&(x{q^pHHfhA z=cbBR5sK?#&CjHtjXh_ThqmO;UuMr<$zDODK@Q2#x1Z`tnzD^ik(w02#O-!II!t8y za${c=Ax*O85?dqpell>Q3;Vg4m>sci9M&;&#%2D+Q<8i`y!*b}DfzzTvM22}Mc=~< zsyrqNG@iG76$wdOnCfq^db47|)b)7TaX^L;)#u)JBcaUzcIVNjMY2QeF zUFmWvFEk|uoUHK2diTI90YT8sYd!BM;WFU)>J7&1<7Q5g`Sp#7L9{JL^_>$81e})A zwxxcj3b)1VOj{IpMfS#N#!?Mnl@99Ft;k~O%kl9AJ9u}X==oze2E4vEUkXKl$bn_> z+Ww}%0p=hLcUtrg5@a>qLCE9FQ<_WX~%U%P1*l-s^G|tG!s8 z>-Jjw#Y*4wF&?e77ERQkUX$?GGUZzZ{TCogwr-)ER@XXTnLWfk)WNGi2uGG6sCn7E zc9h?bZZq-U%4du_*2od z*-=Fk&v~4R*Q0Rjzsc7XqWh+4Y`U(2-`OjgdywJFmiN zy@&zjVSDNi54gT-u53N`Zutd_1?Kossv7hM>VrG9GMuUEs~(*xTMCSdNtV9cq7Ann zfOKPg1~tB1+K5f}=?Hk;FctVf72&eY+~lj$sJFqMwnEqNg6!kR_-x+ zPHqG6MW%wsO55fqX(RY!;L*}=o=;2^Vh8$XOmoq5etgn_J@S~}X+l}Zlfk4ezG-@M zHyvZuvW}-jBthN)t}p21Csn(6?a9Y2SNS0a{bbh!A>sQj0%z|<9_rxRo5*+U*_)P6 zVmegW-x>t|?n2bx4Eg_RSPoc*^EMNpe@X3s^%u-`n@?E{GEq2ZvCCK>p}60w7~@oY z_4wYqJju7qCxPOURnd?O@(!8S@0+YzaQ@-kti1t(b_9MsW}K$cc*m-J>V{BSz{wlw ztd|XC>~p$=n)VZ`Kf`2){%YQvho@LW5)Xu#7T3Ez>_2Pq`}|{Lzu69B$9rQPBgKnT z${s{+cI&7(hpcz=LLMd$Gs@L2ReEbzj!?9UPN!TkDM`O^%%lfjCytv))komGtSs}AX* z^dRB6v4d6Ke-6xTncIBEEs|Rr&tlVje}sNtI5jAg|9`Oe-eFCB+q&?AAOV3;1WhCq zO%S9>5lHBuQbcJ=lPVpN8ahf91Pm<*2u6w^f)oX%qkur@O%RbL5Fqp}h$7yl?){zp zyZ3I-x%Zs&efNIPdHf?PteLsS9COSv-toR;um|WL04s(g_?MrFKWx-3&v6PQDt9MP znRm$C9ig{KJJ=!jT0BTKT`yaVJH^(`5OMet8~Yd)p9-9JGAX`bhxGK9u~c&AHx|VA z#3=>BU7pLWYjQF^3cZtJ07qttpQ^$&gPJYA7=z0Xvy!e0JsJgzr~S#?dkv)eU(XsI zH0!(qW#sJYdigs@YU8!LU>XCrhWE+Q=s$9C>sDE7Z`!O&Gg6YwYX!rQ3wHk&VIJ8` z`4ttzQl8*1pv?#})2hu|A(C52k4uB{Cup;8rr*j=$0Vyh8n!YxEM#lNMzt!Q@xI`f zt>6I;VW_e+*9oUNzb2Zk*@pl@&A?tRVku`Jl} z_H&+^Z>PFH@&tB`;~f;_$Q<>v$K`XBk!r~5A;4Dm1IM6qsBJn@kVV%pSO?UWarvD|u~qWa>{=4tD} zcYOYMH)J9`@HS=QfemS@zn3?&M!d}@-o}@2<8{q>1L>AyHm)RFM%FSxY9-mX_8E?nP;~G|0HTj?UuO4c{pZxx? zv)$9ZanldNkAg4DJsPuG{QW4$lhKJUE=)vShN$q;*gI`^gxFLQIwZz56|fBp*JNsL z?jDmiVx-zM1W9oA&dFQ3!&iALJO;sv%M87oj1Cexv9vD1PFC&=7UL5BSb^V^OmDm(u$wEkl7yM1WwnTP_&MKijZirYXfn) zUK78%(YE;Y_Hc@b;YVotNqS*naxz-_{Y@L*q?9%!Bcx4c`?cEU)W@eG7ml~Sjpmqf z=(VQP6>r5*kYvoK--FMo`X!K~Immn8uEf^Yp))beczd(WjJ0<#GwWpE>MQ;XPP*1) z48ECksmSGRwIBsc(pFoI5etA(evLimJOA6>sdgJ@tK$e(eUJW10n7teS6UrGW=NLJ zJHKVuo2zF;A1hC|eeAma0QhzcCIP!j=4BHna;KF%{oTU2kb3&uirWO0bEz4|grlqW ztL-UhN07C)CP;R7PZ7jht5(;Rx#n3aXik=O(YnjsK{;7@WNIf5?x|(TS|bkiKp(K= zt$x#la+6W00irh+XkAx(cq+|-qpr!hWFH^?emG7Am0hB*bJ)zZMdU$woC!~t(v8Hy zmq*)shW3(68z@u<)*9`K$-n1f>|FHOlpV2%z2eylCt9P><5O|C@bCrVPT|)#5BXYV zpS;EADh6#OlD4V*`1$z<6hHr-#N5{v?m0`2X$<8p*{+6;c)>XGeoJrh(yzBxaXlyBftdsL$|aWnFevNaTfhKXMri4Q6Id`wc4Ek)sC$|cZ^4lARR z+T}B^y)PYLYdlI9a#bY+y0hP`Q!KV$3>^r_5C=r_YO0!A-P(Sp`)+874`D@2iSZyjj1=-bay#JuY6(g=aS_H z6PY~IHn;QTZ=}?VyzXc#rnGKFwYNeK`9d>-P&+s8_k-JUF>E7%9L}3}wBcp`lPFc;V}Pjn^V4 zeXX&ad3)46t3;+I`NZEH;vHav`d zYupk}94s`9Nw#ygHn1_aK=2Ok`RjzyiJIwkj%dxjJhX=yZv!?URNBW?IoBxe2(D($;^it642LL-yibt z+#T8Y_Pp%oc;aqd_b>@J@J8J9;8zf9b~5}h!O7%=JUI$SGk{~e%}$2wh}Yj)+lmi<=w=o zO2MNNPoaKF(qndU^lk9bP-3|G^IwMbsELoX2%LRzTC6UiW9_xthfrGs-KPYYky5<; z21jPZoYr)gQa_sszkZ9U7eNru(aQ6vN>I2pNE5G{^UbVhFG|=^SL@vqW z)NHzg8Lzw`yOs8l@0oQ~Tp`S5eXHbw=>ZN^`N#{&aYJ_vP-v4}kv%z@fg+mlC|S!TkL|=Rhz-JV?Ot z$dXSxQ`wq_L@8&o9~~KM4b>Mq*IHwiUVOizPjrFDo>sXBt?!S9h3pnuuBVv%0D7C1 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 z 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

g!_AnU23zv%cwY4wKdDi^879AsgBacg;W?` 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⩔WWE|~2R3-Yl;Rytu=8C=KoM2mFWmk^YY2QZJ+ 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 literal 529184 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%0AqU9A5;b@ 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

o##fM%Qmcy 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 Op~8~-_4YH7(L;r+Pf^Te@235< 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

vn}hn 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 literal 0 HcmV?d00001 diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst new file mode 100644 index 00000000..ff89b2c8 --- /dev/null +++ b/docs/source/mvBaseWriter.rst @@ -0,0 +1,6 @@ +mvBaseWriter +============ + +.. automodule:: Lib.mvBaseWriter + :members: + diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst new file mode 100644 index 00000000..596bd673 --- /dev/null +++ b/docs/source/mvCdmsRegrid.rst @@ -0,0 +1,5 @@ +mvCdmsRegrid +============ + +.. automodule:: Lib.mvCdmsRegrid + :members: diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst new file mode 100644 index 00000000..6f221a28 --- /dev/null +++ b/docs/source/mvESMFRegrid.rst @@ -0,0 +1,7 @@ +regrid2-mvESMFRegrid +==================== + +.. automodule:: Libregrid.mvESMFRegrid + :members: + + diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst new file mode 100644 index 00000000..06166cfa --- /dev/null +++ b/docs/source/mvGenericRegrid.rst @@ -0,0 +1,7 @@ +regrid2-mvGenericRegrid +======================= + +.. automodule:: Libregrid.mvGenericRegrid + :members: + + diff --git a/docs/source/mvLibCFRegrid.rst b/docs/source/mvLibCFRegrid.rst new file mode 100644 index 00000000..c8d8be6d --- /dev/null +++ b/docs/source/mvLibCFRegrid.rst @@ -0,0 +1,7 @@ +regrid2-mvLibCFRegrid +===================== + +.. automodule:: Libregrid.mvLibCFRegrid + :members: + + diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst new file mode 100644 index 00000000..e86bf9e8 --- /dev/null +++ b/docs/source/mvSphereMesh.rst @@ -0,0 +1,6 @@ +mvSphereMesh +============ + +.. automodule:: Lib.mvSphereMesh + :members: + diff --git a/docs/source/mvVTKSGWriter.rst b/docs/source/mvVTKSGWriter.rst new file mode 100644 index 00000000..34e46b7f --- /dev/null +++ b/docs/source/mvVTKSGWriter.rst @@ -0,0 +1,8 @@ +mvVTKSGWriter +============= + +.. automodule:: Lib.mvVTKSGWriter + :members: + + + diff --git a/docs/source/mvVTKUGWriter.rst b/docs/source/mvVTKUGWriter.rst new file mode 100644 index 00000000..62a3cc38 --- /dev/null +++ b/docs/source/mvVTKUGWriter.rst @@ -0,0 +1,9 @@ +mvVTKUGWriter +============= + +.. automodule:: Lib.mvVTKUGWriter + :members: + + + + diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst new file mode 100644 index 00000000..86795de3 --- /dev/null +++ b/docs/source/mvVsWriter.rst @@ -0,0 +1,7 @@ +mvVsWriter +========== + +.. automodule:: Lib.mvVsWriter + :members: + + diff --git a/docs/source/mySphereMesh.rst b/docs/source/mySphereMesh.rst new file mode 100644 index 00000000..ff89b2c8 --- /dev/null +++ b/docs/source/mySphereMesh.rst @@ -0,0 +1,6 @@ +mvBaseWriter +============ + +.. automodule:: Lib.mvBaseWriter + :members: + diff --git a/docs/source/pressure.rst b/docs/source/pressure.rst new file mode 100644 index 00000000..4e6201f6 --- /dev/null +++ b/docs/source/pressure.rst @@ -0,0 +1,7 @@ +regrid2-pressure +================ + +.. automodule:: Libregrid.pressure + :members: + + diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst new file mode 100644 index 00000000..f18eb91e --- /dev/null +++ b/docs/source/restApi.rst @@ -0,0 +1,9 @@ +restApi +======= + +.. automodule:: Lib.restApi + :members: + + + + diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst new file mode 100644 index 00000000..8fbfd3fa --- /dev/null +++ b/docs/source/scrip.rst @@ -0,0 +1,7 @@ +regrid2-scrip +============= + +.. automodule:: Libregrid.scrip + :members: + + diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst new file mode 100644 index 00000000..63da37fb --- /dev/null +++ b/docs/source/selectors.rst @@ -0,0 +1,5 @@ +selectors +========= + +.. automodule:: Lib.selectors + :members: diff --git a/docs/source/slabinterface.rst b/docs/source/slabinterface.rst new file mode 100644 index 00000000..9a674396 --- /dev/null +++ b/docs/source/slabinterface.rst @@ -0,0 +1,9 @@ +slabinterface +============= + +.. automodule:: Lib.slabinterface + :members: + + + + diff --git a/docs/source/tanya_2.rst b/docs/source/tanya_2.rst new file mode 100644 index 00000000..3a43d6ad --- /dev/null +++ b/docs/source/tanya_2.rst @@ -0,0 +1,7 @@ +bindex +====== + +.. automodule:: Lib. bindex + :members: + + diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst new file mode 100644 index 00000000..23ed8de1 --- /dev/null +++ b/docs/source/tvariable.rst @@ -0,0 +1,5 @@ +tvariable +========= + +.. automodule:: Lib.tvariable + :members: diff --git a/docs/source/variable.rst b/docs/source/variable.rst new file mode 100644 index 00000000..61866e46 --- /dev/null +++ b/docs/source/variable.rst @@ -0,0 +1,7 @@ +variable +======== + +.. automodule:: Lib.variable + :members: + + diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index ae380e4e..1bfcee08 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -56,6 +56,7 @@ def guessPeriodicity(srcBounds): class GenericRegrid: """ Generic Regrid class. + Constructor From 6155ef0a2b54d8786c95cb148ecd6d96dd52e336 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 23 May 2018 15:16:36 -0700 Subject: [PATCH 132/239] Changes made to API --- Lib/avariable.py | 23 +++++++------- Lib/coord.py | 69 +++++++++++++++++++++++++++-------------- Lib/cudsinterface.py | 2 +- Lib/database.py | 4 +-- Lib/variable.py | 38 ++++++++++++----------- regrid2/Lib/gsRegrid.py | 8 ++--- 6 files changed, 85 insertions(+), 59 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 9a69d76a..5c2dbb2e 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -132,10 +132,10 @@ class AbstractVariable(CdmsObj, Slab): Parameters ---------- - variableNode - is the variable tree node, if any. - parent - is the containing dataset instance. + variableNode + is the variable tree node, if any. + parent + is the containing dataset instance. """ def info(self, flag=None, device=None): Slab.info(self, flag, device) @@ -1431,8 +1431,8 @@ def crossSectionRegrid(self, newLevel, newLatitude, method : Optional either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation. - missing and order: - are as for regrid.CrossSectionRegridder. + missing-and-order: + are as for regrid.CrossSectionRegridder. """ from regrid2 import CrossSectionRegridder @@ -1683,12 +1683,13 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. - Parameter - --------- - ar - is a masked array, scalar, or numpy.ma.masked. + +Parameters +---------- + ar + is a masked array, scalar, or numpy.ma.masked. - _: None + _: None """ diff --git a/Lib/coord.py b/Lib/coord.py index ef731cec..cb5aa229 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -62,7 +62,20 @@ def createCoordinateAxis(data, bounds=None, id=None, copy=0): class AbstractCoordinateAxis(CdmsObj): + """ + Parameters + ---------- + clone + (self, copyData=1) + + _:None + + Returns + ------- + a copy of self as a transient axis. If copyData is 1, make a separate copy of the data. + + """ axis_count = 0 # Transient axis count def __init__(self, parent=None, variableNode=None, bounds=None): @@ -73,9 +86,9 @@ def isAbstractCoordinate(self): return 1 def clone(self, copyData=1): - """clone (self, copyData=1) - Return a copy of self as a transient axis. - If copyData is 1, make a separate copy of the data.""" + """ + + """ raise CDMSError(MethodNotImplemented) # Designate axis as a latitude axis. @@ -275,21 +288,31 @@ def writeToFile(self, file): class AbstractAxis2D(AbstractCoordinateAxis): + """ + Parameters + ---------- + + clone + (self, copyData=1) + _:None + + + Returns + ------- + a copy of self as a transient axis. + + Note + ---- + If copyData is 1, make a separate copy of the data. + """ def __init__(self, parent=None, variableNode=None, bounds=None): AbstractCoordinateAxis.__init__( self, parent, variableNode, bounds=bounds) def clone(self, copyData=1): - """clone (self, copyData=1) - - Returns - ------- - a copy of self as a transient axis. - - Note - ---- - If copyData is 1, make a separate copy of the data.""" + """ + """ result = TransientAxis2D( self[:], copy=copyData, @@ -369,22 +392,22 @@ def __repr__(self): class TransientAxis2D(AbstractAxis2D, TransientVariable): + """ + Create a transient 2D axis. + All arguments are as for TransientVariable. + + Parameters + ---------- + bounds: + is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and + nvert: + is the max number of vertices per cell. + """ def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): """ - Create a transient 2D axis. - - All arguments are as for TransientVariable. - Parameters - ---------- - - 'bounds' - is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and - - nvert - is the max number of vertices per cell. """ AbstractAxis2D.__init__(self, None, None, bounds=bounds) TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index e91ce10b..99c02bb7 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -125,7 +125,7 @@ def listdimension(self, vname=None): Returns ------- - a list of the dimension names associated with a variable. + a list of the dimension names associated with a variable. If no argument, return the file.axes.keys() diff --git a/Lib/database.py b/Lib/database.py index b69ee49e..0cba0284 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -45,7 +45,7 @@ def connect(uri=None, user="", password=""): Description: Open a CDMS database connection. Arguments - --------- + uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. user: user id password: password @@ -465,7 +465,7 @@ def searchPredicate(self, predicate, tag=None): class LDAPSearchResult(AbstractSearchResult): - + def __init__(self, db, LDAPresult): self.db = db self.result = LDAPresult diff --git a/Lib/variable.py b/Lib/variable.py index 887ef32a..b09a0dec 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -39,9 +39,7 @@ def timeindex(value, units, basetime, delta, delunits, calendar): class DatasetVariable(AbstractVariable): - - def __init__(self, parent, id, variableNode=None): - """Variable (parent, variableNode=None) + """Variable (parent, variableNode=None) Parameters ---------- @@ -50,6 +48,10 @@ def __init__(self, parent, id, variableNode=None): parent is the containing dataset instance. + + """ + def __init__(self, parent, id, variableNode=None): + """ """ AbstractVariable.__init__(self, parent, variableNode) val = self.__cdms_internals__ + ['domain', 'name_in_file'] @@ -322,30 +324,30 @@ def expertPaths(self, slist): a 3-tuple (npart, dimensionlist, partitionSlices) - Where: + Where: - npart - is the number of partitioned dimensions: 0, 1, or 2; + npart + is the number of partitioned dimensions: 0, 1, or 2; - dimensionlist - is a tuple of length npart, having the dimension numbers of the partitioned dimensions; + dimensionlist + is a tuple of length npart, having the dimension numbers of the partitioned dimensions; - partitionSlices - is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. + partitionSlices + is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. - The exact form of partitionSlices depends on the value of npart: + The exact form of partitionSlices depends on the value of npart: - npart partitionSlices + npart partitionSlices - 0 (filename,slicelist) + 0 (filename,slicelist) - 1 [(filename,slicelist),...,(filename,slicelist)] + 1 [(filename,slicelist),...,(filename,slicelist)] - 2 [[(filename,slicelist),...,(filename,slicelist)] - [(filename,slicelist),...,(filename,slicelist)] - ... - [(filename,slicelist),...,(filename,slicelist)]] + 2 [[(filename,slicelist),...,(filename,slicelist)] + [(filename,slicelist),...,(filename,slicelist)] + ... + [(filename,slicelist),...,(filename,slicelist)]] Note: - A filename of None indicates that no file was found with data corresponding to the slicelist. diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 2d915b1e..3c949192 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer and Dave Kindig, Tech-X (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Regridding of curvilinear structured grids -Alex Pletzer and Dave Kindig, Tech-X (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ # standard python includes # from re import search, sub From 521fb97c99ed64487548b06df2ccea049075c1d1 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 24 May 2018 15:28:00 -0700 Subject: [PATCH 133/239] Made some changes to API --- Lib/MV2.py | 1 + Lib/grid.py | 2 +- Lib/mvCdmsRegrid.py | 7 +++---- Lib/selectors.py | 13 +++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index f95d72dd..16dee76e 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -770,6 +770,7 @@ def transpose(a, axes=None): class _minimum_operation: + "Object to calculate minima" def __init__(self): diff --git a/Lib/grid.py b/Lib/grid.py index 9ab1c9e8..a777ed0c 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -941,7 +941,7 @@ def isGrid(grid): Parameters ---------- - grid cdms2: + grid-cdms2: contruct to be examined _: None diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index 12d03901..ac8a1baf 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -379,11 +379,10 @@ class CdmsRegrid: regridder. If a multidimensional variable is passed in, the apply step loops over the axes above the Lat (Y) -- Lon (X) coordinates - Establish which regridding method to use, handle CDMS variables before - handing off to regridder. See specific tool for more information. + Establish which regridding method to use, handle CDMS variables before handing off to regridder. See specific tool for more information. - Parameters - ---------- +Parameters +---------- srcGrid CDMS source grid diff --git a/Lib/selectors.py b/Lib/selectors.py index d4403135..947a4e37 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -16,14 +16,14 @@ def __init__(self, args): class Selector: - """Selector class""" + """Selector class + + Positional args are SelectorComponents or Selectors Keyword args and their value are passed to kwselect to create selectors. All the selector components are put into the components list of this Selector, along with all the componentsof any Selector arguments. + + """ def __init__(self, *args, **kwargs): - """Positional args are SelectorComponents or Selectors - Keyword args and their value are passed to kwselect to create - selectors. All the selector components are put into the - components list of this Selector, along with all the components - of any Selector arguments. + """ """ self.__components = [] self.refine(*args, **kwargs) @@ -96,6 +96,7 @@ def select(self, variable, *args, **kwargs): Options modify the result of the selection. The options and their default values are: -- raw = 0: if 1, return an numpy.ma only + -- squeeze = 0: If 1, eliminate any dimensions of length 1 from the result. -- order = None: If given, is a string such as From 7302fd94f794a6b462187477a489dca70d2bf62e Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 29 May 2018 09:46:45 -0700 Subject: [PATCH 134/239] update documentations --- docs/createRST.sh | 15 --------------- docs/source/API.rst | 18 ++++++++++-------- docs/source/CDML.rst | 2 +- docs/source/CDMLParser.rst | 2 +- docs/source/MV2.rst | 2 +- docs/source/avariable.rst | 31 +++++++++++++++++++++++++++++-- docs/source/bindex.rst | 2 +- docs/source/cache.rst | 2 +- docs/source/cdmsNode.rst | 2 +- docs/source/cdmsobj.rst | 2 +- docs/source/cdscan.rst | 2 +- docs/source/cdurllib.rst | 2 +- docs/source/cdurlparse.rst | 2 +- docs/source/cdxmllib.rst | 2 +- docs/source/convention.rst | 2 +- docs/source/coord.rst | 2 +- docs/source/crossSection.rst | 2 +- docs/source/cudsinterface.rst | 2 +- docs/source/database.rst | 2 +- docs/source/dataset .rst | 2 +- docs/source/esmf.rst | 3 ++- docs/source/forecast.rst | 2 +- docs/source/fvariable.rst | 7 +++++++ docs/source/gengrid.rst | 2 +- docs/source/grid.rst | 2 +- docs/source/gsRegrid.rst | 2 +- docs/source/gs_horizontal.rst | 2 +- docs/source/hgrid.rst | 4 ++-- docs/source/mvBaseWriter.rst | 2 +- docs/source/mvCdmsRegrid.rst | 2 +- docs/source/mvESMFRegrid.rst | 2 +- docs/source/mvGenericRegrid.rst | 2 +- docs/source/mvLibCFRegrid.rst | 4 ++-- docs/source/mvSphereMesh.rst | 2 +- docs/source/mvVTKSGWriter.rst | 2 +- docs/source/mvVTKUGWriter.rst | 2 +- docs/source/mvVsWriter.rst | 2 +- docs/source/mySphereMesh.rst | 2 +- docs/source/pressure.rst | 2 +- docs/source/restApi.rst | 2 +- docs/source/scrip.rst | 2 +- docs/source/selectors.rst | 2 +- docs/source/slabinterface.rst | 2 +- docs/source/tanya_2.rst | 2 +- docs/source/tvariable.rst | 2 +- docs/source/variable.rst | 2 +- 46 files changed, 91 insertions(+), 69 deletions(-) delete mode 100644 docs/createRST.sh diff --git a/docs/createRST.sh b/docs/createRST.sh deleted file mode 100644 index 15bc19f2..00000000 --- a/docs/createRST.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -a=('cdmsobj' 'axis' 'coord' 'grid' 'hgrid' 'avariable' 'sliceut' 'error' 'variable' 'fvariable' 'tvariable' 'dataset' 'database' 'cache' 'selectors' 'MV2' 'convention' 'bindex' 'auxcoord' 'gengrid' 'gsHost' 'gsStaticVariable' 'gsTimeVariable' 'mvBaseWriter' 'mvSphereMesh' 'mvVsWriter' 'mvCdmsRegrid') - -for i in "${a[@]}"; do -echo "creating "$i".rst" -echo "$i -======== - -.. automodule:: Lib.$i - :members: -" >$i.rst - - -done - diff --git a/docs/source/API.rst b/docs/source/API.rst index b67a04bf..a1a9e70c 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -6,6 +6,8 @@ API Classes ------- .. autosummary:: + :toctree: generated/ + avariable axis fvariable @@ -42,14 +44,14 @@ Regridder --------- .. autosummary:: regrid2.horizontal - esmf - crossSection - gsRegrid - mvESMFRegrid - mvGenericRegrid - pressure - scrip - mvLibCFRegrid + regrid2.esmf + regrid2.crossSection + regrid2.gsRegrid + regrid2.mvESMFRegrid + regrid2.mvGenericRegrid + regrid2.pressure + regrid2.scrip + regrid2.mvcdms2.FRegrid diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst index 109a93b0..68263fb5 100644 --- a/docs/source/CDML.rst +++ b/docs/source/CDML.rst @@ -1,7 +1,7 @@ CDML ==== -.. automodule:: Lib.CDML +.. automodule:: cdms2.CDML :members: diff --git a/docs/source/CDMLParser.rst b/docs/source/CDMLParser.rst index 259442d2..d417412e 100644 --- a/docs/source/CDMLParser.rst +++ b/docs/source/CDMLParser.rst @@ -1,7 +1,7 @@ CDMLParser ========== -.. automodule:: Lib.CDMLParser +.. automodule:: cdms2.CDMLParser :members: diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst index e0ade528..d729f973 100644 --- a/docs/source/MV2.rst +++ b/docs/source/MV2.rst @@ -1,7 +1,7 @@ MV2 === -.. automodule:: Lib.MV2 +.. automodule:: cdms2.MV2 :members: diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index 0d8a099b..ef4f86ea 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -1,7 +1,34 @@ avariable ========= -.. automodule:: cdms2.avariable - :members: +#.. automodule:: cdms2.avariable +# :members: + +.. currentmodule:: cdms2 + +.. autosummary:: + :toctree: generated/ + + avariable.splitSlice + avariable.splitSliceExt + avariable.setNumericCompatibility + avariable.orderparse + avariable.order2index + avariable.guessPeriodicity + avariable.getNumericCompatibility + avariable.getMinHorizontalMask + avariable._getCoordList + avariable.getBoundList + avariable.axisMatchIndex + avariable.axisMatches + avariable.axisMatchAxis + avariable.TransientVariable + avariable.Slab + avariable.CdmsRegrid + avariable.CdmsObj + avariable.CDMSError + avariable.AbstractVariable + avariable.AbstractRectGrid + avariable.AbstractAxis diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst index bac32540..af8b0dd1 100644 --- a/docs/source/bindex.rst +++ b/docs/source/bindex.rst @@ -1,7 +1,7 @@ bindex ====== -.. automodule:: Lib.bindex +.. automodule:: cdms2.bindex :members: diff --git a/docs/source/cache.rst b/docs/source/cache.rst index ec91bd2b..41f2ad72 100644 --- a/docs/source/cache.rst +++ b/docs/source/cache.rst @@ -1,7 +1,7 @@ cache ===== -.. automodule:: Lib.cache +.. automodule:: cdms2.cache :members: diff --git a/docs/source/cdmsNode.rst b/docs/source/cdmsNode.rst index f67a4dd0..ba0d72ae 100644 --- a/docs/source/cdmsNode.rst +++ b/docs/source/cdmsNode.rst @@ -1,7 +1,7 @@ cdmsobj ======= -.. automodule:: Lib.cdmsobj +.. automodule:: cdms2.cdmsobj :members: diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst index f67a4dd0..ba0d72ae 100644 --- a/docs/source/cdmsobj.rst +++ b/docs/source/cdmsobj.rst @@ -1,7 +1,7 @@ cdmsobj ======= -.. automodule:: Lib.cdmsobj +.. automodule:: cdms2.cdmsobj :members: diff --git a/docs/source/cdscan.rst b/docs/source/cdscan.rst index d1b0275e..8646afff 100644 --- a/docs/source/cdscan.rst +++ b/docs/source/cdscan.rst @@ -1,7 +1,7 @@ cdscan ====== -.. automodule:: Lib.cdscan +.. automodule:: cdms2.cdscan :members: diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst index 3c886ec9..3ed5b1be 100644 --- a/docs/source/cdurllib.rst +++ b/docs/source/cdurllib.rst @@ -1,7 +1,7 @@ cdurllib ======== -.. automodule:: Lib.cdurllib +.. automodule:: cdms2.cdurllib :members: diff --git a/docs/source/cdurlparse.rst b/docs/source/cdurlparse.rst index 99603cb9..fe4fd974 100644 --- a/docs/source/cdurlparse.rst +++ b/docs/source/cdurlparse.rst @@ -1,7 +1,7 @@ cdurlparse ========== -.. automodule:: Lib.cdurlparse +.. automodule:: cdms2.cdurlparse :members: diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index 35efb257..1603fab5 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -1,7 +1,7 @@ cdxmllib ======== -.. automodule:: Lib.cdxmllib +.. automodule:: cdms2.cdxmllib :members: diff --git a/docs/source/convention.rst b/docs/source/convention.rst index 66e90a58..92a8984f 100644 --- a/docs/source/convention.rst +++ b/docs/source/convention.rst @@ -1,7 +1,7 @@ convention ========== -.. automodule:: Lib.convention +.. automodule:: cdms2.convention :members: diff --git a/docs/source/coord.rst b/docs/source/coord.rst index 95c33f93..40375359 100644 --- a/docs/source/coord.rst +++ b/docs/source/coord.rst @@ -1,7 +1,7 @@ coord ===== -.. automodule:: Lib.coord +.. automodule:: cdms2.coord :members: diff --git a/docs/source/crossSection.rst b/docs/source/crossSection.rst index 9a02a523..97c5f7bb 100644 --- a/docs/source/crossSection.rst +++ b/docs/source/crossSection.rst @@ -1,7 +1,7 @@ regrid2- crossSection ===================== -.. automodule:: Libregrid.crossSection +.. automodule:: regrid2.crossSection :members: diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst index 8d5707a4..20837af2 100644 --- a/docs/source/cudsinterface.rst +++ b/docs/source/cudsinterface.rst @@ -1,7 +1,7 @@ cudsinterface ============= -.. automodule:: Lib.cudsinterface +.. automodule:: cdms2.cudsinterface :members: diff --git a/docs/source/database.rst b/docs/source/database.rst index 0eae3466..33736863 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -1,7 +1,7 @@ database ======== -.. automodule:: Lib.database +.. automodule:: cdms2.database :members: diff --git a/docs/source/dataset .rst b/docs/source/dataset .rst index 02698c18..66ed5f06 100644 --- a/docs/source/dataset .rst +++ b/docs/source/dataset .rst @@ -1,7 +1,7 @@ dataset ======= -.. automodule:: Lib.dataset +.. automodule:: cdms2.dataset :members: diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst index 8e6dd740..1f58c9ab 100644 --- a/docs/source/esmf.rst +++ b/docs/source/esmf.rst @@ -1,7 +1,8 @@ regrid2- esmf ============= -.. automodule:: Libregrid.esmf + +.. automodule:: regrid2.esmf :members: diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index 80cd9352..fc0ad421 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -1,7 +1,7 @@ forecast ======== -.. automodule:: Lib.forecast +.. automodule:: cdms2.forecast :members: diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst index a433f3d4..4ba233f3 100644 --- a/docs/source/fvariable.rst +++ b/docs/source/fvariable.rst @@ -4,4 +4,11 @@ fvariable .. automodule:: cdms2.fvariable :members: +.. currentmodule:: numpy + + +.. autosummary:: + :toctree: generated/ + + diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst index 389e5ca4..90e1adca 100644 --- a/docs/source/gengrid.rst +++ b/docs/source/gengrid.rst @@ -1,7 +1,7 @@ gengrid ======= -.. automodule:: Lib.gengrid +.. automodule:: cdms2.gengrid :members: diff --git a/docs/source/grid.rst b/docs/source/grid.rst index 8ae39c33..0130759b 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -1,7 +1,7 @@ grid ==== -.. automodule:: Lib.grid +.. automodule:: cdms2.grid :members: diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst index 495dcc07..c64632c7 100644 --- a/docs/source/gsRegrid.rst +++ b/docs/source/gsRegrid.rst @@ -1,7 +1,7 @@ regrid2-gsRegrid ================ -.. automodule:: Libregrid.gsRegrid +.. automodule:: regrid2.gsRegrid :members: diff --git a/docs/source/gs_horizontal.rst b/docs/source/gs_horizontal.rst index a7b54048..250f5357 100644 --- a/docs/source/gs_horizontal.rst +++ b/docs/source/gs_horizontal.rst @@ -1,7 +1,7 @@ regrid2-gs_horizontal ===================== -.. automodule:: Libregrid.gs_horizontal +.. automodule:: regrid2.gs_horizontal :members: diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst index b8d069ea..2f84a891 100644 --- a/docs/source/hgrid.rst +++ b/docs/source/hgrid.rst @@ -1,9 +1,9 @@ hgrid ===== -.. automodule:: Lib.hgrid +.. automodule:: cdms2.hgrid :members: -.. automodule:: Lib.hgrid.AbstractHorizontalGrid +.. automodule:: cdms2.hgrid.AbstractHorizontalGrid :members: \ No newline at end of file diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst index ff89b2c8..70b0f35e 100644 --- a/docs/source/mvBaseWriter.rst +++ b/docs/source/mvBaseWriter.rst @@ -1,6 +1,6 @@ mvBaseWriter ============ -.. automodule:: Lib.mvBaseWriter +.. automodule:: cdms2.mvBaseWriter :members: diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst index 596bd673..5375a055 100644 --- a/docs/source/mvCdmsRegrid.rst +++ b/docs/source/mvCdmsRegrid.rst @@ -1,5 +1,5 @@ mvCdmsRegrid ============ -.. automodule:: Lib.mvCdmsRegrid +.. automodule:: cdms2.mvCdmsRegrid :members: diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst index 6f221a28..33d86c32 100644 --- a/docs/source/mvESMFRegrid.rst +++ b/docs/source/mvESMFRegrid.rst @@ -1,7 +1,7 @@ regrid2-mvESMFRegrid ==================== -.. automodule:: Libregrid.mvESMFRegrid +.. automodule:: regrid2.mvESMFRegrid :members: diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst index 06166cfa..24fa7077 100644 --- a/docs/source/mvGenericRegrid.rst +++ b/docs/source/mvGenericRegrid.rst @@ -1,7 +1,7 @@ regrid2-mvGenericRegrid ======================= -.. automodule:: Libregrid.mvGenericRegrid +.. automodule:: regrid2.mvGenericRegrid :members: diff --git a/docs/source/mvLibCFRegrid.rst b/docs/source/mvLibCFRegrid.rst index c8d8be6d..a886c78b 100644 --- a/docs/source/mvLibCFRegrid.rst +++ b/docs/source/mvLibCFRegrid.rst @@ -1,7 +1,7 @@ -regrid2-mvLibCFRegrid +regrid2-mvcdms2.FRegrid ===================== -.. automodule:: Libregrid.mvLibCFRegrid +.. automodule:: regrid2.mvLibCFRegrid :members: diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst index e86bf9e8..7c2374e6 100644 --- a/docs/source/mvSphereMesh.rst +++ b/docs/source/mvSphereMesh.rst @@ -1,6 +1,6 @@ mvSphereMesh ============ -.. automodule:: Lib.mvSphereMesh +.. automodule:: cdms2.mvSphereMesh :members: diff --git a/docs/source/mvVTKSGWriter.rst b/docs/source/mvVTKSGWriter.rst index 34e46b7f..1e13b950 100644 --- a/docs/source/mvVTKSGWriter.rst +++ b/docs/source/mvVTKSGWriter.rst @@ -1,7 +1,7 @@ mvVTKSGWriter ============= -.. automodule:: Lib.mvVTKSGWriter +.. automodule:: cdms2.mvVTKSGWriter :members: diff --git a/docs/source/mvVTKUGWriter.rst b/docs/source/mvVTKUGWriter.rst index 62a3cc38..708ba9b9 100644 --- a/docs/source/mvVTKUGWriter.rst +++ b/docs/source/mvVTKUGWriter.rst @@ -1,7 +1,7 @@ mvVTKUGWriter ============= -.. automodule:: Lib.mvVTKUGWriter +.. automodule:: cdms2.mvVTKUGWriter :members: diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst index 86795de3..e36bc344 100644 --- a/docs/source/mvVsWriter.rst +++ b/docs/source/mvVsWriter.rst @@ -1,7 +1,7 @@ mvVsWriter ========== -.. automodule:: Lib.mvVsWriter +.. automodule:: cdms2.mvVsWriter :members: diff --git a/docs/source/mySphereMesh.rst b/docs/source/mySphereMesh.rst index ff89b2c8..70b0f35e 100644 --- a/docs/source/mySphereMesh.rst +++ b/docs/source/mySphereMesh.rst @@ -1,6 +1,6 @@ mvBaseWriter ============ -.. automodule:: Lib.mvBaseWriter +.. automodule:: cdms2.mvBaseWriter :members: diff --git a/docs/source/pressure.rst b/docs/source/pressure.rst index 4e6201f6..cc9d1641 100644 --- a/docs/source/pressure.rst +++ b/docs/source/pressure.rst @@ -1,7 +1,7 @@ regrid2-pressure ================ -.. automodule:: Libregrid.pressure +.. automodule:: regrid2.pressure :members: diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst index f18eb91e..3840f053 100644 --- a/docs/source/restApi.rst +++ b/docs/source/restApi.rst @@ -1,7 +1,7 @@ restApi ======= -.. automodule:: Lib.restApi +.. automodule:: cdms2.restApi :members: diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst index 8fbfd3fa..941a36c0 100644 --- a/docs/source/scrip.rst +++ b/docs/source/scrip.rst @@ -1,7 +1,7 @@ regrid2-scrip ============= -.. automodule:: Libregrid.scrip +.. automodule:: regrid2.scrip :members: diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst index 63da37fb..994f7ed3 100644 --- a/docs/source/selectors.rst +++ b/docs/source/selectors.rst @@ -1,5 +1,5 @@ selectors ========= -.. automodule:: Lib.selectors +.. automodule:: cdms2.selectors :members: diff --git a/docs/source/slabinterface.rst b/docs/source/slabinterface.rst index 9a674396..dd0c8550 100644 --- a/docs/source/slabinterface.rst +++ b/docs/source/slabinterface.rst @@ -1,7 +1,7 @@ slabinterface ============= -.. automodule:: Lib.slabinterface +.. automodule:: cdms2.slabinterface :members: diff --git a/docs/source/tanya_2.rst b/docs/source/tanya_2.rst index 3a43d6ad..13ad6282 100644 --- a/docs/source/tanya_2.rst +++ b/docs/source/tanya_2.rst @@ -1,7 +1,7 @@ bindex ====== -.. automodule:: Lib. bindex +.. automodule:: cdms2. bindex :members: diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst index 23ed8de1..9d2aed0b 100644 --- a/docs/source/tvariable.rst +++ b/docs/source/tvariable.rst @@ -1,5 +1,5 @@ tvariable ========= -.. automodule:: Lib.tvariable +.. automodule:: cdms2.tvariable :members: diff --git a/docs/source/variable.rst b/docs/source/variable.rst index 61866e46..db52728d 100644 --- a/docs/source/variable.rst +++ b/docs/source/variable.rst @@ -1,7 +1,7 @@ variable ======== -.. automodule:: Lib.variable +.. automodule:: cdms2.variable :members: From ca61e5de028bb5288e5fd8b0cd3745204bfe90ae Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 29 May 2018 15:40:37 -0700 Subject: [PATCH 135/239] Changes made to API --- Lib/cache.py | 47 ++++++---- Lib/mvVTKSGWriter.py | 18 ++-- Lib/mvVTKUGWriter.py | 15 ++-- Lib/mvVsWriter.py | 20 +++-- regrid2/Lib/gsRegrid.py | 193 ++++++++++++++++++++-------------------- 5 files changed, 159 insertions(+), 134 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index 899b909c..324bf30f 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -181,8 +181,14 @@ def copyFile(fromURL, toURL, callback=None, For request manager transfers, is the logical collection distinguished name, - - is the string user ID, is true if the request manager should search the replica catalog for the actual file to transfer. + Parameters + ---------- + + + is the string user ID, + + + is true if the request manager should search the replica catalog for the actual file to transfer. """ if callback is None: if _useWindow: @@ -349,15 +355,17 @@ def copyFile(self, fromURL, filekey, lcpath=None, """ Copy the file into the cache. Return the result path. - For request manager transfers, lcpath is the logical collection path, + For request manager transfers, lcpath is the logical collection path, +Parameters +---------- - - is the string user ID, + + is the string user ID, - - is true iff the request manager should search the replica catalog for the actual file to transfer. + + is true iff the request manager should search the replica catalog for the actual file to transfer. """ # Put a notification into the cache, that this file is being read. @@ -397,32 +405,35 @@ def getFile(self, fromURL, filekey, naptime=5, maxtries=60, """ Get the file with . - If the file is in the cache, read it. + If the file is in the cache, read it. - If another process is transferring it into the cache, wait for the + If another process is transferring it into the cache, wait for the transfer to complete. + + Parameters + --------- - is the number of seconds between retries, + is the number of seconds between retries, - is the maximum number of retries. Otherwise, copy it from the remote file. + is the maximum number of retries. Otherwise, copy it from the remote file. - is the cache index key. A good choice is (datasetDN, filename) + is the cache index key. A good choice is (datasetDN, filename) where datasetDN is the distinguished name of the dataset, and filename is the name of the file within the dataset. For request manager transfers, - - is the logical collection path, + + is the logical collection path, - - is the user string ID, + + is the user string ID, - - is true iff the request manager should search the replica catalog for the actual file to transfer. + + is true iff the request manager should search the replica catalog for the actual file to transfer. Returns the path of a file in the cache. diff --git a/Lib/mvVTKSGWriter.py b/Lib/mvVTKSGWriter.py index b857e541..ce12f582 100644 --- a/Lib/mvVTKSGWriter.py +++ b/Lib/mvVTKSGWriter.py @@ -14,16 +14,20 @@ class VTKSGWriter(mvBaseWriter.BaseWriter): + """ + Write file - def write(self, filename): - """ - Write file + Parameters + ---------- - Parameters - ---------- + filename + file name - filename - file name + _: None + """ + def write(self, filename): + """ + """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVTKUGWriter.py b/Lib/mvVTKUGWriter.py index 120f1549..9fd0dbfe 100644 --- a/Lib/mvVTKUGWriter.py +++ b/Lib/mvVTKUGWriter.py @@ -14,18 +14,21 @@ class VTKUGWriter(mvBaseWriter.BaseWriter): + """ + Write file - def write(self, filename): - """ - Write file - - Parameters - ---------- + Parameters + ---------- filename file name _:None + + """ + def write(self, filename): + """ + """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVsWriter.py b/Lib/mvVsWriter.py index 1aff8dec..d9681495 100644 --- a/Lib/mvVsWriter.py +++ b/Lib/mvVsWriter.py @@ -13,16 +13,20 @@ class VsWriter(mvBaseWriter.BaseWriter): - - def write(self, filename): - """ - Write file + """ + Write file + + Parameters + ---------- - Parameters - ---------- + filename + file name - filename - file name + _: None + """ + def write(self, filename): + """ + """ try: import tables diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 3c949192..738a264d 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -48,19 +48,19 @@ def getTensorProduct(axis, dim, dims): Parameters ---------- - axis - 1D array of coordinates + axis + 1D array of coordinates - dim - dimensional index of the above coordinate + dim + dimensional index of the above coordinate - dims - sizes of all coordinates + dims + sizes of all coordinates Returns ------- - coordinate values obtained by tensor product + coordinate values obtained by tensor product """ return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) @@ -74,14 +74,14 @@ def makeCurvilinear(coords): Parameters ---------- - coords - list of coordinates - _: None + coords + list of coordinates + _: None Returns ------- - new list of coordinates and associated dimensions + new list of coordinates and associated dimensions """ rank = len(coords) @@ -126,16 +126,16 @@ def makeCoordsCyclic(coords, dims): Parameters ---------- - coords - input coordinates + coords + input coordinates - dims - input dimensions + dims + input dimensions Returns ------- - new, extended coordinates such that the longitudes cover the sphere and new dimensions + new, extended coordinates such that the longitudes cover the sphere and new dimensions """ # assume lon is the last coordinate!! @@ -192,17 +192,17 @@ def checkForCoordCut(coords, dims): Parameters ---------- - coords - input coordinates + coords + input coordinates - dims - input dimensions + dims + input dimensions Returns ------- - True for cut found - False for no cut + True for cut found + False for no cut """ # Assume latitude is next to last coordinate and longitude is last @@ -300,19 +300,19 @@ def handleCoordsCut(coords, dims, bounds): Parameters ---------- - coords - input coordinates list of rank + coords + input coordinates list of rank - dims - input dimensions + dims + input dimensions - bounds - boundaries for each coordinate + bounds + boundaries for each coordinate Returns ------- - extended coordinates such that there is an extra row containing connectivity information across the cut + extended coordinates such that there is an extra row containing connectivity information across the cut """ # Assume latitude is next to last coordinate and longitude is @@ -329,19 +329,19 @@ def getIndices(array, nlon, newI): Parameters ---------- - array - Array of booleans + array + Array of booleans - nlon - number of longitudes + nlon + number of longitudes - newI - index row with connectivity to be updated + newI + index row with connectivity to be updated Returns ------- - new coordinates, new dimensions, index row + new coordinates, new dimensions, index row """ for i in range(len(array)): # An edge @@ -371,32 +371,35 @@ def getIndices(array, nlon, newI): class Regrid: - def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, - handleCut=False, verbose=False): - """ - Constructor + """ + Constructor - Parameters - ---------- + Parameters + ---------- + src_grid + source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient - src_grid - source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient + dst_grid + destination grid, a list of [x, y, ...] coordinates - dst_grid - destination grid, a list of [x, y, ...] coordinates + src_bounds + list of cell bounding coordinates (to be used when handling a cut in coordinates) - src_bounds - list of cell bounding coordinates (to be used when handling a cut in coordinates) + mkCyclic + Add a column to the right side of the grid to complete a cyclic grid - mkCyclic - Add a column to the right side of the grid to complete a cyclic grid + handleCut + Add a row to the top of grid to handle a cut for grids such as the tri-polar grid verbose print diagnostic messages - handleCut - Add a row to the top of grid to handle a cut for grids such as the tri-polar grid - verbose print diagnostic messages + Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. + """ + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, + handleCut=False, verbose=False): + """ + Constructor - Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. + """ self.regridid = c_int(-1) self.src_gridid = c_int(-1) @@ -568,7 +571,7 @@ def getPeriodicities(self): Returns ------- - numpy array, values inf indicate no periodicity + numpy array, values inf indicate no periodicity """ coord_periodicity = numpy.zeros((self.rank,), numpy.float64) status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, @@ -612,11 +615,11 @@ def setValidMask(self, inMask): Parameters ---------- - inMask - flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. - 0 - invalid, 1 - valid data + inMask + flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. + 0 - invalid, 1 - valid data - _: None + _: None Note: This must be invoked before computing the weights, the mask is a property of the grid (not the data). """ @@ -641,11 +644,12 @@ def setMask(self, inDataOrMask): Parameters ---------- - inDataOrMask cdms2 array or flat mask array, - 0 - valid data - 1 - invalid data + inDataOrMask + cdms2 array or flat mask array, + 0 - valid data + 1 - invalid data - _: None + _: None Note: this definition is compatible with the numpy masked arrays @@ -672,12 +676,11 @@ def computeWeights(self, nitermax=100, tolpos=1.e-2): Parameters ---------- - nitermax - max number of iterations + nitermax + max number of iterations - tolpos - max tolerance when locating destination positions in - index space + tolpos + max tolerance when locating destination positions in index space """ status = self.lib.nccf_compute_regrid_weights(self.regridid, nitermax, @@ -692,14 +695,14 @@ def apply(self, src_data_in, dst_data, missingValue=None): Parameters ---------- - src_data - data on source grid + src_data + data on source grid - dst_data - data on destination grid + dst_data + data on destination grid - missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ if not self.weightsComputed: raise RegridError('Weights must be set before applying the regrid') @@ -813,14 +816,14 @@ def __call__(self, src_data, dst_data, missingValue=None): Parameters ---------- - src_data - data on source grid + src_data + data on source grid - dst_data - data on destination grid + dst_data + data on destination grid - missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ self.apply(src_data, dst_data, missingValue) @@ -886,15 +889,15 @@ def getIndicesAndWeights(self, dst_indices): Parameters ---------- - dst_indices - index set on the target grid + dst_indices + index set on the target grid - _: None + _: None Returns ------- - [index sets on original grid, weights] + [index sets on original grid, weights] """ dinds = numpy.array(dst_indices) sinds = (c_int * 2**self.rank)() @@ -924,10 +927,10 @@ def _extend(self, src_data): Parameters ---------- - src_data - input source data + src_data + input source data - _: None + _: None Returns ------- @@ -969,17 +972,17 @@ def _findIndices(self, targetPos, nitermax, tolpos, Parameters ---------- - targetPos - numpy array of target positions + targetPos + numpy array of target positions - nitermax - max number of iterations + nitermax + max number of iterations - tolpos - max toelrance in positions + tolpos + max toelrance in positions - dindicesGuess - guess for the floating point indices + dindicesGuess + guess for the floating point indices Returns ------- From e737c891dd8377c688e7542932743635cd79d955 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 30 May 2018 15:07:48 -0700 Subject: [PATCH 136/239] Changes made to API --- Lib/MV2.py | 3 ++- Lib/gengrid.py | 2 +- Lib/mvBaseWriter.py | 15 +++++++++++- Lib/mvCdmsRegrid.py | 57 ++++++++++++++++++++++++--------------------- Lib/tvariable.py | 1 + regrid2/Lib/esmf.py | 18 +++++++------- 6 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 16dee76e..11b0648b 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -949,7 +949,8 @@ def ones(myshape, typecode=float, savespace=0, axes=None, def outerproduct(a, b): - """outerproduct(a,b) = {a[i]*b[j]}, has shape (len(a),len(b))""" + """outerproduct(a,b) = {a[i]*b[j]}, has shape (len(a),len(b)) + """ ta = asVariable(a, writeable=1) tb = asVariable(b, writeable=1) maresult = numpy.ma.outerproduct(ta, tb) diff --git a/Lib/gengrid.py b/Lib/gengrid.py index 23c4c70c..aea1197f 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -396,7 +396,7 @@ def __repr__(self): class TransientGenericGrid(AbstractGenericGrid): - + grid_count = 0 def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None): diff --git a/Lib/mvBaseWriter.py b/Lib/mvBaseWriter.py index 38f76d46..0421f46a 100644 --- a/Lib/mvBaseWriter.py +++ b/Lib/mvBaseWriter.py @@ -12,9 +12,22 @@ class BaseWriter: + """ + Constructor + Parameters + ---------- - def __init__(self, var, sphereRadius=1.0, maxElev=0.1): + var + a cdms2 variable + + sphereRadius + radius of the sphere upon which the grid will be projected + + maxElev + max elevation/depth normalized to the sphere radius + """ + def __init__(self, var, sphereRadius=1.0, maxElev=0.1): """ Constructor diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index ac8a1baf..13c258c1 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -22,9 +22,11 @@ def _areCellsOk(cornerCoords, mask=None): Parameters ---------- - cornerCoords + cornerCoords - mask checks will not be performed where mask is 1 (True) + mask checks will not be performed where mask is 1 (True) + + _: None Returns ------- @@ -56,7 +58,8 @@ def projectToSphere(the, lam): Returns ------- - x, y, z coordinates in Cartesian space""" + x, y, z coordinates in Cartesian space + """ ct = numpy.cos(the) return ct * numpy.cos(lam), ct * numpy.sin(lam), numpy.sin(the) @@ -181,13 +184,15 @@ def _buildBounds(bounds): Parameters ---------- - bounds - CdmsVar.getBounds() + bounds + CdmsVar.getBounds() + + _:None Returns ------- - ndarrray of corners + ndarrray of corners """ bndShape = [s + 1 for s in bounds.shape[:-1]] @@ -212,22 +217,22 @@ def getBoundList(coordList, mask=None, Parameters ---------- - coordList - coordinate list, should have getBounds() + coordList + coordinate list, should have getBounds() - mask - avoid checking areas where mask is one + mask + avoid checking areas where mask is one - removeBadCells - set to True if you want to the code to remove bad cells, ie zero cells, butterfly cells, ... + removeBadCells + set to True if you want to the code to remove bad cells, ie zero cells, butterfly cells, ... - maskCellIndices - list of bad cell indices to mask out (output) + maskCellIndices + list of bad cell indices to mask out (output) Returns ------- - [latBounds, lonBounds] + [latBounds, lonBounds] """ cornerCoords = [] for c in coordList: @@ -262,7 +267,7 @@ def _getCoordList(grid): Returns ------- - lats, lons + lats, lons """ lats = grid.getLatitude() @@ -288,16 +293,16 @@ def _getDstDataShape(srcVar, dstGrid): Parameters ---------- - srcVar - the variable from which all axes other than lat/lon will be taken from + srcVar + the variable from which all axes other than lat/lon will be taken from - dstGrid - target, horizontal grid + dstGrid + target, horizontal grid Returns ------- - list + list """ shp = srcVar.shape @@ -334,16 +339,16 @@ def _getAxisList(srcVar, dstGrid): Parameters ---------- - srcVar - the variable from which all axes other than lat/lon will be taken from + srcVar + the variable from which all axes other than lat/lon will be taken from - dstGrid - target, horizontal grid + dstGrid + target, horizontal grid Returns ------- - variable with non-horizontal axes from srcVar and horizontal axes from dstGrid + variable with non-horizontal axes from srcVar and horizontal axes from dstGrid """ shp = srcVar.shape diff --git a/Lib/tvariable.py b/Lib/tvariable.py index e4ab46c7..fe580558 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -1,3 +1,4 @@ + # Automatically adapted for numpy.oldnumeric Aug 01, 2007 by # Further modified to be pure new numpy June 24th 2008 diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index f3e37936..a6a0435f 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -37,7 +37,7 @@ class EsmfUnstructGrid: """ - + Constructor Parameters ---------- @@ -50,7 +50,7 @@ class EsmfUnstructGrid: """ def __init__(self, numTopoDims, numSpaceDims): - """Constructor + """ """ @@ -92,7 +92,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- .. figure:: /images/ESMF.jpg - :scale: 95% + :scale: 55% :alt: 3 4-------------3 /\ | | @@ -819,14 +819,14 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): Parameters ---------- - srcField - source field (or None if src field passed to constructor is to be used) + srcField + source field (or None if src field passed to constructor is to be used) - dstField - destination field (or None if dst field passed to constructor is to be used) + dstField + destination field (or None if dst field passed to constructor is to be used) - zero_region - specify which region of the field indices will be zeroed (or None default to TOTAL Region) + zero_region + specify which region of the field indices will be zeroed (or None default to TOTAL Region) """ if srcField is None: srcField = self.srcField From a7063e29d344594197449b0f66bcef77ba3bb766 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 31 May 2018 15:52:04 -0700 Subject: [PATCH 137/239] Changes made to API --- Lib/avariable.py | 5 ++- Lib/grid.py | 94 +++++++++++++++++++++++++++++++++++++++++++++ Lib/mvBaseWriter.py | 2 +- docs/source/conf.py | 1 + 4 files changed, 99 insertions(+), 3 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 5c2dbb2e..ace517d2 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -861,8 +861,9 @@ def getSlice(self, *specs, **keys): #. an instance of the slice class #. a tuple, which will be used as arguments to create a slice #. `None` or `:`, which means a slice covering that entire dimension - #. Ellipsis (...), which means to fill the slice list with `:` - leaving only enough room at the end for the remaining positional arguments + #. Ellipsis (...), which means to fill the slice list with `:` + + leaving only enough room at the end for the remaining positional arguments There can be keyword arguments of the form key = value, where key can be one of the names `time`, `level`, `latitude`, or diff --git a/Lib/grid.py b/Lib/grid.py index a777ed0c..ebb50bc2 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -24,6 +24,9 @@ def setClassifyGrids(mode): + """ + Not documented + """ global _classifyGrids if mode == 'on': _classifyGrids = 1 @@ -34,6 +37,10 @@ def setClassifyGrids(mode): def createRectGrid(lat, lon, order="yx", type="generic", mask=None): + """ + Not documented + """ + return TransientRectGrid(lat, lon, order, type, mask) # Generate a uniform rectilinear grid @@ -41,6 +48,10 @@ def createRectGrid(lat, lon, order="yx", type="generic", mask=None): def createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None): + """ + Not documented + """ + lat = createUniformLatitudeAxis(startLat, nlat, deltaLat) lon = createUniformLongitudeAxis(startLon, nlon, deltaLon) return createRectGrid(lat, lon, order, "uniform", mask) @@ -50,6 +61,9 @@ def createUniformGrid(startLat, nlat, deltaLat, startLon, def createGlobalMeanGrid(grid): + """ + Not documented + """ inlat = grid.getLatitude() inlatBounds, inlonBounds = grid.getBounds() outlatArray = numpy.array([(inlat[0] + inlat[-1]) / 2.0]) @@ -70,6 +84,9 @@ def createGlobalMeanGrid(grid): def createZonalGrid(grid): + """ + Not documented + """ inlat = grid.getLatitude() outlatBounds, inlonBounds = grid.getBounds() outlat = createAxis(inlat[:], outlatBounds) @@ -88,6 +105,9 @@ def createZonalGrid(grid): def createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None): + """ + Not documented + """ lat = createAxis(latArray, latBounds) lat.units = "degrees_north" lon = createAxis(lonArray, lonBounds) @@ -205,6 +225,7 @@ def setRegionSpecs(grid, coordSpec, coordType, resultSpec): class AbstractGrid (CdmsObj): def __init__(self, node): + CdmsObj.__init__(self, node) self.id = '' # String identifier if node is not None and hasattr(node, 'id'): @@ -329,6 +350,7 @@ def listall(self, all=None): return result def _getshape(self): + if self._order_ == "yx": return (len(self._lataxis_), len(self._lonaxis_)) else: @@ -336,6 +358,9 @@ def _getshape(self): # Get the n-th axis. naxis is 0 or 1. def getAxis(self, naxis): + """ + Not documented + """ ind = self._order_[naxis] if ind == 'x': axis = self.getLongitude() @@ -344,6 +369,9 @@ def getAxis(self, naxis): return axis def getBounds(self): + """ + Not documented + """ latbnds, lonbnds = (self._lataxis_.getExplicitBounds(), self._lonaxis_.getExplicitBounds()) if (latbnds is None or lonbnds is None) and getAutoBounds() in [1, 2]: @@ -356,24 +384,45 @@ def getBounds(self): return (latbnds, lonbnds) def getLatitude(self): + """ + Not documented + """ return self._lataxis_ def getLongitude(self): + """ + Not documented + """ return self._lonaxis_ def getMask(self): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def setMask(self, mask, permanent=0): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def getOrder(self): + """ + Not documented + """ return self._order_ def getType(self): + """ + Not documented + """ return self._gridtype_ def setType(self, gridtype): + """ + Not documented + """ if gridtype == 'linear': gridtype = 'uniform' if gridtype == 'unknown': @@ -387,6 +436,9 @@ def setType(self, gridtype): # lonWeights[i] = abs(lonBnds[i+1] - lonBnds[i])/360.0 # Assumes that both axes are represented in degrees. def getWeights(self): + """ + Not documented + """ latBounds, lonBounds = self.getBounds() latBounds = (numpy.pi / 180.0) * latBounds @@ -401,6 +453,9 @@ def getWeights(self): # Create a transient grid for the index (tuple) intervals. def subGrid(self, latinterval, loninterval): + """ + Not documented + """ if latinterval is None: latinterval = (0, len(self._lataxis_)) if loninterval is None: @@ -424,12 +479,18 @@ def subGrid(self, latinterval, loninterval): # Same as subGrid, for coordinates def subGridRegion(self, latRegion, lonRegion): + """ + Not documented + """ latInterval = self._lataxis_.mapInterval(latRegion) lonInterval = self._lonaxis_.mapInterval(lonRegion) return self.subGrid(latInterval, lonInterval) # Return a transient grid which is the transpose of this grid def transpose(self): + """ + Not documented + """ if self._order_ == "yx": neworder = "xy" else: @@ -453,6 +514,9 @@ def transpose(self): # isoffset is true iff this is a BOUNDARY grid, hence the bounds # are the points wrt nlat, plus the poles. def classify(self): + """ + Not documented + """ import regrid2._regrid CLOSE_ENOUGH = 1.e-3 @@ -539,6 +603,9 @@ def classify(self): # basegrid is the full grid, if this is regional, or None # latindex is index into basegrid latitude, or None def classifyInFamily(self, gridlist): + """ + Not documented + """ gridtype, nlats, isoffset = self.classify() coverage = 'global' basegrid = None @@ -567,6 +634,9 @@ def classifyInFamily(self, gridlist): # Generate default bounds def genBounds(self): + """ + Not documented + """ import regrid2._regrid if hasattr(self, "parent") and self.parent is not None: @@ -784,6 +854,9 @@ def toCurveGrid(self, gridid=None): return grid def toGenericGrid(self, gridid=None): + """ + Not documented + """ curvegrid = self.toCurveGrid() gengrid = curvegrid.toGenericGrid(gridid=gridid) return gengrid @@ -808,6 +881,9 @@ def __init__(self, parent, rectgridNode=None): # Set pointers to related structural elements: lon, lat axes, order, mask def initDomain(self, axisdict, vardict): + """ + Not documented + """ if self.latitude not in axisdict: raise CDMSError('No such latitude: %s' % repr(self.latitude)) if self.longitude not in axisdict: @@ -824,6 +900,9 @@ def initDomain(self, axisdict, vardict): self._maskVar_ = None def getMask(self): + """ + Not documented + """ if self._maskVar_ is None: # return numpy.ones(self.shape) return None @@ -831,6 +910,9 @@ def getMask(self): return self._maskVar_[:] def getMaskVar(self): + """ + Not documented + """ return self._maskVar_ # internattr.add_internal_attribute(RectGrid) @@ -856,11 +938,17 @@ def __init__(self, parent, gridname, latobj, lonobj, # Set bounds. If persistent==1, write to file, else just shadow any file # boundaries. def setBounds(self, latBounds, lonBounds, persistent=0): + """ + Not documented + """ self._lataxis_.setBounds(latBounds, persistent) self._lonaxis_.setBounds(lonBounds, persistent) # Return the mask array (NOT the mask variable). def getMask(self): + """ + Not documented + """ if self._tempMask_ is not None: return self._tempMask_ elif self._maskVar_ is None: @@ -872,6 +960,9 @@ def getMask(self): # Set the mask to array 'mask'. If persistent == 1, modify permanently # in the file, else set as a temporary mask. def setMask(self, mask, persistent=0): + """ + Not documented + """ if persistent != 0: raise CDMSError(MethodNotImplemented) if mask is None: @@ -884,6 +975,9 @@ def setMask(self, mask, persistent=0): self._tempMask_ = copy.copy(mask) def getMaskVar(self): + """ + Not documented + """ return self._maskVar_ # internattr.add_internal_attribute(FileRectGrid) diff --git a/Lib/mvBaseWriter.py b/Lib/mvBaseWriter.py index 0421f46a..0159791d 100644 --- a/Lib/mvBaseWriter.py +++ b/Lib/mvBaseWriter.py @@ -27,7 +27,7 @@ class BaseWriter: maxElev max elevation/depth normalized to the sphere radius """ - def __init__(self, var, sphereRadius=1.0, maxElev=0.1): + def __init__(self, var, sphereRadius=1.0, maxElev=0.1): """ Constructor diff --git a/docs/source/conf.py b/docs/source/conf.py index fb72cd1e..a178ee54 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,6 +17,7 @@ import sys,os sys.path.append(os.path.abspath('../../regrid2')) sys.path.append(os.path.abspath('../..')) +sys.path.append(os.path.abspath('..')) import mock os.environ['READTHEDOCS']="True" #MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] From 3cb0aad1ff06563bfe3d20b25592246d6a62593b Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 1 Jun 2018 14:51:15 -0700 Subject: [PATCH 138/239] Changes made to Section 2 and API --- Lib/grid.py | 15 +++ Lib/hgrid.py | 15 +++ docs/source/manual/cdms_2.rst | 230 +++++++++++++++++++++------------- 3 files changed, 172 insertions(+), 88 deletions(-) diff --git a/Lib/grid.py b/Lib/grid.py index ebb50bc2..e08bcc39 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -268,6 +268,9 @@ def hasCoordType(self, coordType): return 0 def getAxisList(self): + """ + Not documented + """ axes = [] for i in range(len(self._order_)): axes.append(self.getAxis(i)) @@ -690,6 +693,9 @@ def genBounds(self): return (latbnds, lonbnds) def writeToFile(self, file): + """ + Not documented + """ return None def getMesh(self): @@ -1005,6 +1011,9 @@ def __init__(self, latobj, lonobj, order, gridtype, maskarray=None): self.setMask(maskarray) # numpy mask array def getMask(self): + """ + Not documented + """ if self._maskArray_ is None: # return numpy.ones(self.shape) return None @@ -1014,6 +1023,9 @@ def getMask(self): # Set the mask. The persistent argument is provided for compatibility # with persistent versions, is ignored. def setMask(self, mask, persistent=0): + """ + Not documented + """ if mask is not None: if not isinstance(mask, numpy.ndarray): raise CDMSError('Mask must be a numpy array') @@ -1022,6 +1034,9 @@ def setMask(self, mask, persistent=0): self._maskArray_ = copy.copy(mask) def setBounds(self, latBounds, lonBounds): + """ + Not documented + """ self._lataxis_.setBounds(latBounds) self._lonaxis_.setBounds(lonBounds) diff --git a/Lib/hgrid.py b/Lib/hgrid.py index e012e929..d9a31ddd 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -49,10 +49,16 @@ def __init__(self, latAxis, lonAxis, id=None, # Generate default bounds def genBounds(self): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) # Get the n-th axis. naxis is 0 or 1. def getAxis(self, naxis): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def getBounds(self): @@ -100,14 +106,23 @@ def getWeightsArray(self): raise CDMSError(MethodNotImplemented) def listall(self, all=None): + """ + Not documented + """ result = [] result.append('Grid has Python id %s.' % hex(id(self))) return result def setMask(self, mask, permanent=0): + """ + Not documented + """ self._maskVar_ = mask def subGridRegion(self, latRegion, lonRegion): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def hasCoordType(self, coordType): diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 544fd9dd..62cd95e5 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -46,8 +46,8 @@ the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: -Table PythonTypes used in CDMS -------------------------------- +PythonTypes used in CDMS +------------------------ .. csv-table:: :header: "Type", "Description" :widths: 10, 80 @@ -134,8 +134,8 @@ Rather, they are called as module functions, e.g., -Table Cdms Module Functions ---------------------------- +Cdms Module Functions +--------------------- .. csv-table:: :header: "Type", "Definition" @@ -224,8 +224,8 @@ Table Cdms Module Functions -Table Class Tags --------------------- +Class Tags +---------- .. csv-table:: :header: "Tag", "Class" :widths: 20, 20 @@ -259,8 +259,8 @@ external attributes are written, but not the internal attributes. >>> extatts = obj.attributes.keys() -Table Attributes Common to All CDMS Objects -------------------------------------------- +Attributes Common to All CDMS Objects +------------------------------------- .. csv-table:: Attributes common to all CDMS objects :header: "Type", "Name", "Definition" @@ -269,8 +269,8 @@ Table Attributes Common to All CDMS Objects "Dictionary", "attributes", "External attribute dictionary for this object." -Table Getting and Setting Attributes ------------------------------------- +Getting and Setting Attributes +------------------------------ .. csv-table:: :header: "Type", "Definition" :widths: 20, 80 @@ -297,8 +297,8 @@ documents methods that are common to all CoordinateAxis types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D Axis objects. -Table CoordinateAxis Types --------------------------- +CoordinateAxis Types +-------------------- .. csv-table:: :header: "Type", "Definition" @@ -309,8 +309,8 @@ Table CoordinateAxis Types "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." -Table CoordinateAxis Internal Attributes ----------------------------------------- +CoordinateAxis Internal Attributes +---------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -321,8 +321,8 @@ Table CoordinateAxis Internal Attributes "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." -Table Axis Constructors ------------------------ +CoordinateAxis Constructors +--------------------------- .. csv-table:: :header: "Constructor", "Description" @@ -343,8 +343,8 @@ Table Axis Constructors , "* See `A First Example`_ ." -Table CoordinateAxis Methods ----------------------------- +CoordinateAxis Methods +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -382,8 +382,8 @@ Table CoordinateAxis Methods "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." -Table Axis Methods, Additional to CoordinateAxis ------------------------------------------------- +CoordinateAxis Methods, Additional to CoordinateAxis +---------------------------------------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -420,8 +420,8 @@ Table Axis Methods, Additional to CoordinateAxis ,,"* see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." -Table Axis Slice Operators --------------------------- +CoordinateAxis Slice Operators +------------------------------ .. csv-table:: :header: "Slice", "Definition" @@ -464,9 +464,8 @@ formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. As of CDMS V3, the legacy cuDataset interface is also supported by Cdms-Files. See “cu Module”. - -Table CdmsFile Internal Attributes ----------------------------------- +CdmsFile Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -478,8 +477,8 @@ Table CdmsFile Internal Attributes "``String``", "``id``", "File pathname." "``Dictionary``", "``variables``", "Variables contained in the file." -Table CdmsFile Constructors ---------------------------- +CdmsFile Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -490,8 +489,8 @@ Table CdmsFile Constructors "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." -Table CdmsFile Methods ----------------------- +CdmsFile Methods Object Name Transient Variable +------------------------------------------------ .. csv-table:: :header: "Type", "Method", "Definition" @@ -504,6 +503,15 @@ Table CdmsFile Methods ,, " **Example:** The following reads data for variable 'prc', year 1980:" ,, " * >>> f = cdms.open('test.nc')" ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" + +CdmsFile Methods Object Identifier Variable, Axis or Grid +--------------------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." ,, " **Example:** The following gets the persistent variable" ,, " * ``v``, equivalent to" @@ -514,16 +522,55 @@ Table CdmsFile Methods ,, " * ``t = f.axes['time']``." ,, " * ``t = f['time']``" "``None``", "``close()``", "Close the file." + +CdmsFile Methods Copy Axis, Grid +-------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + +CdmsFile Methods Create Axis, RectGrid and Variable +---------------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + + +CdmsFile Methods Read CurveGrid, Generic-Grid +--------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." + + +CdmsFile Methods Write Variable +------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + + + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." ,,"* ``var`` is a Variable, masked array, or Numpy array." ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." @@ -536,8 +583,8 @@ Table CdmsFile Methods ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." -Table CDMS Datatypes --------------------- +CDMS Datatypes +-------------- .. csv-table:: :header: "CDMS Datatype", "Definition" @@ -628,8 +675,8 @@ To access a database: ``db.close()`` -Table Database Internal Attributes ----------------------------------- +Database Internal Attributes +---------------------------- .. csv-table:: @@ -643,8 +690,8 @@ Table Database Internal Attributes "``String``", "``uri``", "Uniform Resource Identifier" -Table Database Constructors ---------------------------- +Database Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -656,8 +703,8 @@ Table Database Constructors ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" -Table Database Methods ----------------------- +Database Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -808,8 +855,8 @@ variables defined on a 94x192 grid: -Table SearchResult Methods --------------------------- +SearchResult Methods +-------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -829,8 +876,8 @@ information defined for the associated CDMS object, which is retrieved with the ``getObject`` method. -Table ResultEntry Attributes ----------------------------- +ResultEntry Attributes +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -840,8 +887,8 @@ Table ResultEntry Attributes "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" -Table ResultEntry Methods -------------------------- +ResultEntry Methods +------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -852,7 +899,7 @@ Table ResultEntry Methods Accessing data --------------------- +-------------- To access data via CDMS: @@ -871,7 +918,7 @@ In the next example, a portion of variable ‘ua’ is read from dataset Examples of Database Searches ------------------------------------ +----------------------------- In the following examples, db is the database opened with: @@ -957,8 +1004,8 @@ As of CDMS V3, the legacy cuDataset interface is supported by Datasets. See “cu Module". -Table Dataset Internal Attributes ---------------------------------- +Dataset Internal Attributes +--------------------------- .. csv-table:: :header: "Type", "Name", "Description" @@ -974,8 +1021,8 @@ Table Dataset Internal Attributes "Dictionary", "``variables``", "Variables contained in the dataset." "Dictionary", "``xlinks``", "External links contained in the dataset." -Table Dataset Constructors --------------------------- +Dataset Constructors +-------------------- .. csv-table:: :header: "Constructor", "Description" @@ -985,12 +1032,12 @@ Table Dataset Constructors "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" -Table Open Modes ----------------- +Open Modes +---------- .. csv-table:: :header: "Mode", "Definition" - :widths: 50, 70 + :widths: 10, 70 :align: left "‘r’", "read-only" @@ -999,8 +1046,8 @@ Table Open Modes "‘w’", "Create a new file, read-write" -Table Dataset Methods ---------------------- +Dataset Methods +--------------- .. csv-table:: :header: "Type", "Definition", "Description" @@ -1010,13 +1057,20 @@ Table Dataset Methods ,, "**Example:** The following reads data for variable 'prc', year 1980:" ,, " * f = cdms.open('test. xml')" ,, " * x = f('prc', time=('1980-1','1981-1'))" - "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found." - ,, "**Example:**" - ,, " * f = cdms.open('sampl e.xml')" - ,, " * v = f['prc']" - ,, " * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``." - ,, "**Example:**" - ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. + + **Example:** + + * f = cdms.open('sampl e.xml') + * v = f['prc'] + + * gets the persistent variable v equivalent to ``v=f.variables['prc']``. + + **Example:** + + * t = f['time'] + + * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." ,,"``lat`` is a latitude axis in the dataset." @@ -1096,8 +1150,8 @@ https://numpy.sourceforge.net for a description of these functions. -Table Variable Constructors in Module MV ------------------------------------------ +Variable Constructors in Module MV +----------------------------------- .. tabularcolumns:: |l|r| @@ -1122,8 +1176,8 @@ The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. -Table MV Functions ------------------- +MV Functions +------------ .. csv-table:: :header: "Function", "Description" :widths: 50, 80 @@ -1173,8 +1227,8 @@ cells. Specifically, a HorizontalGrid: CDMS supports several types of HorizontalGrids: -Table Grids ------------ +Grids +----- .. csv-table:: :header: "Grid Type", "Definition" @@ -1185,8 +1239,8 @@ Table Grids "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" -Table HorizontalGrid Internal Attribute ---------------------------------------- +HorizontalGrid Internal Attribute +--------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1202,8 +1256,8 @@ Table HorizontalGrid Internal Attribute -Table RectGrid Constructors ---------------------------- +RectGrid Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1223,8 +1277,8 @@ Table RectGrid Constructors -Table HorizontalGrid Methods ----------------------------- +HorizontalGrid Methods +---------------------- .. csv-table:: @@ -1263,8 +1317,8 @@ Table HorizontalGrid Methods ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." -Table RectGrid Methods, Additional to HorizontalGrid Methods ------------------------------------------------------------- +RectGrid Methods, Additional to HorizontalGrid Methods +------------------------------------------------------ .. csv-table:: :header: "Type", "Method", "Description" @@ -1322,8 +1376,8 @@ advantage of the attribute, domain, and mask information in a transient variable. -Table Variable Internal Attributes ----------------------------------- +Variable Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1336,8 +1390,8 @@ Table Variable Internal Attributes "Tuple", "``shape``", "The length of each axis of the variable" -Table Variable Constructors ---------------------------- +Variable Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1352,8 +1406,8 @@ Table Variable Constructors -Table Variable Methods ----------------------- +Variable Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1474,8 +1528,8 @@ Read all data for March, 1980: -Table Variable Slice Operators ------------------------------- +Variable Slice Operators +------------------------ .. csv-table:: :header: "Operator", "Description" @@ -1493,8 +1547,8 @@ Table Variable Slice Operators -Table Index and Coordinate Intervals ------------------------------------- +Index and Coordinate Intervals +------------------------------ .. csv-table:: :header: "Interval Definition", "Example Interval Definition", "Example" @@ -1578,8 +1632,8 @@ components is the positional form, where the component order corresponds to the axis order of a variable. For example: -Table Selector Keywords ------------------------ +Selector Keywords +----------------- .. csv-table:: :header: "Keyword", "Description", "Value" From 7878e5340cf6301fdc9dec123aa6d69e2c5bed9c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 4 Jun 2018 15:49:48 -0700 Subject: [PATCH 139/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 585 ++++++++++++++++++---------------- 1 file changed, 310 insertions(+), 275 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 62cd95e5..3a21f535 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -145,10 +145,10 @@ Cdms Module Functions "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" - , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." - , " * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." - , " * See ``setAutoBounds``." - , " * Also see: ``CdmsFile.createAxis``" + , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. + * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * See ``setAutoBounds``. + * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" @@ -156,63 +156,61 @@ Cdms Module Functions "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values." - , " * ``lonArray`` is a NumPy array of longitude values. " - , " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. " - , " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. " - , " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." - , " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values. + * ``lonArray`` is a NumPy array of longitude values. + * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. + * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. + * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. + * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" - , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation." - , " * ``lat`` is a latitude axis, created by ``cdms.createAxis``." - , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." - , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - + , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + * ``lat`` is a latitude axis, created by ``cdms.createAxis``. + * ``lon`` is a longitude axis, created by ``cdms.createAxis``. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" - , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``." - , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." - , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. + * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``. + * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" - , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes." - , " * ``deltaLat`` is the increment between latitudes." + , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. + * ``deltaLat`` is the increment between latitudes." "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" - , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis." - , " * ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes." - , " * ``deltaLon`` is the increment between longitudes." + , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + * ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes + * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." , " * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: " , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" - , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" - , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:" - - , " * Letters t, x, y, z meaning time, longitude, latitude, level" - , " * Numbers 0-9 representing position in axes" - , " * Dash (-) meaning insert the next available axis here." - , " * The ellipsis ... meaning fill these positions with any remaining axes." - , " * (name) meaning an axis whose id is name" + , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * Dash (-) meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``:" , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" @@ -327,20 +325,18 @@ CoordinateAxis Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 20, 80 + :align: left "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" - , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" - , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited``" - , "``cdms.createEqualAreaAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createGaussianAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" - , "* See `A First Example`_ ." + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: + * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or + * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` + + * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. + * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. + * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. + * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." CoordinateAxis Methods @@ -360,19 +356,22 @@ CoordinateAxis Methods "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." - "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis:" - ,,"* ``Axis``: ``(n,2)``" - ,,"* ``Axis2D``: ``(i,j,4)``" - ,,"* ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell." - ,,"If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." - "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are:" - ,,"* ``cdtime.GregorianCalendar``: the standard Gregorian calendar" - ,,"* ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar" - ,,"* ``cdtime.JulianCalendar``: years divisible by 4 are leap years" - ,,"* ``cdtime.NoLeapCalendar``: a year is 365 days" - ,,"* ``cdtime.Calendar360``: a year is 360 days" - ,,"* ``None``: no calendar can be identified" - ,," **Note** If the axis is not a time axis, the global, file-related calendar is returned." + "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: + + * ``Axis``: ``(n,2)`` + * ``Axis2D``: ``(i,j,4)`` + * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. + * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: + + * ``cdtime.GregorianCalendar``: the standard Gregorian calendar + * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar + * ``cdtime.JulianCalendar``: years divisible by 4 are leap years + * ``cdtime.NoLeapCalendar``: a year is 365 days + * ``cdtime.Calendar360``: a year is 360 days + * ``None``: no calendar can be identified + + * **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." @@ -394,30 +393,32 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if:" - ,," * ``axis.topology == 'circular'``, or" - ,," * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: + + * ``axis.topology == 'circular'``, or + * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." - "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None or ':'``" - ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:" - ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" - ,,"* ``'n'`` - select node values which are contained in the interval" - ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" - ,,"* ``'e'`` - same as n, but include an extra node on either side" - ,,"* ``'s'`` - select axis elements for which the cell boundary is a subset of the interval" - ,,"* The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected." - ,,"* If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``." - ,,"* An interval of ``None`` or ``':'`` returns the full index interval of the axis." - ,,"* The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty." - ,,"* for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``" - ,,"* if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint." - ,,"* otherwise the interval wraps around the axis endpoint." - ,,"* see also: ``mapinterval``, ``variable.subregion()``" + "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: + + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None or ':'`` + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: + * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi + * ``'n'`` - select node values which are contained in the interva + * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval + * ``'e'`` - same as n, but include an extra node on either sid + * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval + * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * An interval of ``None`` or ``':'`` returns the full index interval of the axis. + * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. + * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` + * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. + * otherwise the interval wraps around the axis endpoint." + * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." CoordinateAxis Slice Operators @@ -433,16 +434,17 @@ CoordinateAxis Slice Operators "``[:j]``", "the beginning element through, but not including, element ``j``" "``[:]``", "the entire array" "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" - "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." - , " **Example:** a longitude axis has value" - , " * ``[0.0, 2.0, ..., 358.0]``" - , " * of length ``180``" - , " * map the coordinate interval:" - , " * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval" - , " * ``-2 <= n < 3`` wraps around, since" - , " * ``-2 < 0``, and has a stride of ``1``" - , " * this is equivalent to the two contiguous index intervals" - , " * ``2 <= n < 0`` and ``0 <= n < 3``" + "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element. + + * **Example:** a longitude axis has value + * ``[0.0, 2.0, ..., 358.0]`` + * of length ``180`` + * map the coordinate interval: + * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval + * ``-2 <= n < 3`` wraps around, since + * ``-2 < 0``, and has a stride of ``1`` + * this is equivalent to the two contiguous index intervals + * ``2 <= n < 0`` and ``0 <= n < 3``" Example 1 ''''''''''' @@ -499,10 +501,12 @@ CdmsFile Methods Object Name Transient Variable "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, " **Example:** The following reads data for variable 'prc', year 1980:" - ,, " * >>> f = cdms.open('test.nc')" - ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" + ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + + **Example:** The following reads data for variable 'prc', year 1980: + + * >>> f = cdms.open('test.nc') + * >>> x = f('prc', time=('1980-1','1981-1'))" CdmsFile Methods Object Identifier Variable, Axis or Grid --------------------------------------------------------- @@ -512,15 +516,19 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid :widths: 10, 30, 80 :align: left - "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." - ,, " **Example:** The following gets the persistent variable" - ,, " * ``v``, equivalent to" - ,, " * ``v = f.variables['prc']``." - ,, " * f = cdms.open('sample.nc')" - ,, " * v = f['prc']" - ,, " **Example:** The following gets the axis named time, equivalent to" - ,, " * ``t = f.axes['time']``." - ,, " * ``t = f['time']``" + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. + + **Example:** The following gets the persistent variable + + * ``v``, equivalent to + * ``v = f.variables['prc']``. + * f = cdms.open('sample.nc') + * v = f['prc'] + + **Example:** The following gets the axis named time, equivalent to + + * ``t = f.axes['time']``. + * ``t = f['time']``" "``None``", "``close()``", "Close the file." CdmsFile Methods Copy Axis, Grid @@ -545,8 +553,9 @@ CdmsFile Methods Create Axis, RectGrid and Variable "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." - ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + + **Note:** Unlike copyAxis, the actual data is not copied to the new variable." CdmsFile Methods Read CurveGrid, Generic-Grid @@ -571,17 +580,18 @@ CdmsFile Methods Write Variable "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." - ,,"* ``var`` is a Variable, masked array, or Numpy array." - ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." - ,,"* ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``." - ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." - ,,"* ``id`` is the variable name in the file. Default is ``var.id``." - ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." - ,,"* The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." - ,,"* ``fill_value`` is the missing value flag." - ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." - ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." + ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. + + * ``var`` is a Variable, masked array, or Numpy array. + * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``. + * ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``. + * ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``. + * ``id`` is the variable name in the file. Default is ``var.id``. + * ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable. + * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour. + * ``fill_value`` is the missing value flag. + * ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. + **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." CDMS Datatypes -------------- @@ -712,33 +722,37 @@ Database Methods "None", "``close()``", "Close a database" "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." - "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." - , "* ``dsetid``","is the string dataset identifier" - , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." - , "* ``openDataset``", "is a synonym for ``open``." + "Dataset", "``open(dsetid, mode='r')``", "Open a dataset. + + * ``dsetid``, is the string dataset identifier + + * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + + * ``openDataset``, is a synonym for ``open``." "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." - ,, - ,," **Example:**" - ,," * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'." - ,," - A formal definition of search filters is provided in the following section." - ,," - ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." - ,," - ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." - ,, - ,," **Example:**" - ,," * To search only dataset 'ncep_reanalysis_mo', specify:" - ,," - ``relbase='dataset=ncep_reanalysis_mo'``" - ,," * To search only variable 'ua' in 'ncep_reanalysis_mo', use:" - ,," - ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``" - ,, - ,,"If no base is specified, the entire database is searched. See the ``scope`` argument also." - ,,"``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**)." - ,," * **Subtree** searches the base object and its descendants." - ,," * **Onelevel** searches the base object and its immediate descendants." - ,," * **Base**\ searches the base object alone." - ,," * The default is **Subtree**." - ,,"``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." - ,,"``timeout``: integer number of seconds before timeout. The default is no timeout." + ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + **Example:** + + * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. + * A formal definition of search filters is provided in the following section. + * ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid'). + * ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy. + + **Example:** + + * To search only dataset 'ncep_reanalysis_mo', specify: + * ``relbase='dataset=ncep_reanalysis_mo'`` + * To search only variable 'ua' in 'ncep_reanalysis_mo', use: + * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'`` + If no base is specified, the entire database is searched. See the ``scope`` argument also. + + * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**). + * **Subtree** searches the base object and its descendants. + * **Onelevel** searches the base object and its immediate descendants. + * **Base**\ searches the base object alone. + * The default is **Subtree**. + * ``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list. + * ``timeout``: integer number of seconds before timeout. The default is no timeout." ------------ @@ -1053,10 +1067,14 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, "**Example:** The following reads data for variable 'prc', year 1980:" - ,, " * f = cdms.open('test. xml')" - ,, " * x = f('prc', time=('1980-1','1981-1'))" + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + + **Example:** The following reads data for variable 'prc', year 1980: + + * f = cdms.open('test. xml') + + * x = f('prc', time=('1980-1','1981-1'))" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. **Example:** @@ -1072,22 +1090,24 @@ Dataset Methods * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." - ,,"``lat`` is a latitude axis in the dataset." - ,,"``lon`` is a longitude axis in the dataset." - ,,"``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" - ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." - ,,"``id`` is the string axis identifier." - "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset." - ,,"``id`` is the string grid identifier." + "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the dataset. + * ``lon`` is a longitude axis in the dataset. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic' + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset. + * ``id`` is the string axis identifier." + "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset. + * ``id`` is the string grid identifier." "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." - "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." - ,,"``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." - ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``." - ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset. + * ``id`` is the string variable identifier." + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile. + + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1288,33 +1308,37 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" - ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." - ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." - ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." - ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``)." - ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + + * for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." - "Axis", "``getLongitude()``", " Get the latitude axis of this grid." + "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." - "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.``" - ,,"``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively." - ,,"Each interval is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None``" - ,,"where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" - ,,"``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." - ,,"If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0." - ,,"An interval of ``None`` returns the full index interval of the axis." - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." - ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` + + * ``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively. + * Each interval is a tuple having one of the forms: + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None`` + + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: + + * ``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co'). + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. + * An interval of ``None`` returns the full index interval of the axis. + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. + **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." RectGrid Methods, Additional to HorizontalGrid Methods @@ -1324,28 +1348,36 @@ RectGrid Methods, Additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." - ,,"The latitude weights are defined as:" - ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" - ,," The longitude weights are defined as:" - ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" - ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" - ,,"**Example:**" - ,,"Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``." - ,,"* from cdms import MV" - ,,"* latwts, lonwts = gri d.getWeights()" - ,,"* weights = MV.outerproduct(latwts, lonwts)" - ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees. + + * The latitude weights are defined as: + * ``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`` + + * The longitude weights are defined as: + * ``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0`` + + * For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0 + + **Example:** + + * Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``. + * from cdms import MV + * latwts, lonwts = gri d.getWeights() + * weights = MV.outerproduct(latwts, lonwts) + * Also see the function ``area_weights`` in module ``pcmdi.weighting``." ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." - ,,"**Example:**" - ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." - ,,"``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))``" - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges." - ,,"**Note:** The result grid is not associated with any file or dataset." - "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed." - ,,"**Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + + **Example:** + + * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. + * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + + **Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1400,8 +1432,9 @@ Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." - "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." - ,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. + + * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1420,54 +1453,56 @@ Variable Methods "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." - "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." - ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." - "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time." - ,,"* ``newLevel`` is an axis of the result pressure levels." - ,,"* ``newLatitude`` is an axis of the result latitudes." - ,,"* ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,,"* ``missing`` is a missing data value. The default is ``var.getMissing()``" - ,,"* ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``." - ,,"*See also:* ``regrid``, ``pressureRegrid``." - "Axis", "``getAxis(n)``", "Get the n-th axis." - ,,"``n`` is an integer." + "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. + * If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." + "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``newLatitude`` is an axis of the result latitudes. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``. + * See also:* ``regrid``, ``pressureRegrid``." + "Axis", "``getAxis(n)``", "Get the n-th axis. + * ``n`` is an integer." "List", "``getAxisIds()``", "Get a list of axis identifiers." - "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." - ,,"``axis_spec`` is a specification as defined for getAxisList" - "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable." - ,,"If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." - ,,"If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." - ,,"``order`` is an optional string determining the output order." - ,,"Specifications for the axes or omit keywords are a list, each element having one of the following forms:" - ,,"* an integer dimension index, starting at 0." - ,,"* a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'." - ,,"* a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches." - ,,"* an axis object; will match if it is the same object as axis." - ,,"``order`` can be a string containing the characters t,x,y,z, or * ." - ,,"If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." + "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match. + * ``axis_spec`` is a specification as defined for getAxisList" + "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable. + * If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given. + * If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below. + * ``order`` is an optional string determining the output order. + * Specifications for the axes or omit keywords are a list, each element having one of the following forms: + * an integer dimension index, starting at 0. + * a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'. + * a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches. + * an axis object; will match if it is the same object as axis. + * ``order`` can be a string containing the characters t,x,y,z, or * . + * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." - "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found." - ,, "String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" - ,, "* 't': time" - ,, "* 'z': vertical level" - ,, "* 'y': latitude" - ,, "* 'x': longitude" - ,, "* '-': the axis is not spatio-temporal." - ,, "**Example:**" - ,, "A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." - ,, "**Note:** The order string is of the form required for the order argument of a regridder function." - ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." - ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." - ,, "**Note:** This function is not defined for transient variables." + "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found. + String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of: + * 't': time + * 'z': vertical level + * 'y': latitude + * 'x': longitude + * '-': the axis is not spatio-temporal. + **Example:** + A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude). + + **Note:** The order string is of the form required for the order argument of a regridder function. + * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned. + + * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. + **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." - "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." - ,,"**Note:** ``size()`` returns the total number of elements." + "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. + **Note:** ``size()`` returns the total number of elements." "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." ,, "``newLevel`` is an axis of the result pressure levels." ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." @@ -1475,32 +1510,32 @@ Variable Methods ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" ,, "See also: ``regrid``, ``crossSectionRegrid``." "Integer", "``rank()``", "The number of dimensions of the variable." - "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid." - ,, "``missing`` is a Float specifying the missing data value. The default is 1.0e20." - ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." - ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." - ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." + "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." - "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." - ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." - ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." - ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." - ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" - ,,"* a single integer n, meaning ``slice(n, n+1)``" - ,,"* an instance of the slice class" - ,,"* a tuple, which will be used as arguments to create a slice" - ,,"* ':', which means a slice covering that entire dimension" - ,,"* Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments" - ,,"* a Python slice object, of the form ``slice(i,j,k)``" - ,,"If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read." - ,,"The keyword arguments are defined as in subRegion." - ,,"There must be no conflict between the positional arguments and the keywords." - ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." - ,,"String ``typecode()`` The Numpy datatype identifier." + "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``. + * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. + * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. + * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." + "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off. + * ``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form: + * a single integer n, meaning ``slice(n, n+1)`` + * an instance of the slice class + * a tuple, which will be used as arguments to create a slice + * ':', which means a slice covering that entire dimension + * Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments + * a Python slice object, of the form ``slice(i,j,k)`` + * If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read. + * The keyword arguments are defined as in subRegion. + * There must be no conflict between the positional arguments and the keywords. + * In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing. + * String ``typecode()`` The Numpy datatype identifier." Example Get a Region of Data. ----------------------------- From e8077bb4c9ffeea52564b4f4dcef6f43e36826a5 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 5 Jun 2018 14:52:22 -0700 Subject: [PATCH 140/239] Changes made to Chapter 2 --- docs/source/manual/cdms_2.rst | 86 +++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 3a21f535..3c6bde95 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -161,11 +161,9 @@ Cdms Module Functions * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. - * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." - + * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. @@ -186,7 +184,8 @@ Cdms Module Functions * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." - "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." + "``RectGrid``","``createZonalGrid(grid)``:" + ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. @@ -200,7 +199,9 @@ Cdms Module Functions "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." @@ -212,11 +213,19 @@ Cdms Module Functions * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: + * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. + * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." + , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. + * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. + * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." + , "Write a grid to a SCRIP grid file. + * ``path`` is a string, the path of the SCRIP file to be created. + * ``grid`` is a CDMS grid object. It may be rectangular. + * ``gridTitle`` is a string ID for the grid." : @@ -488,7 +497,9 @@ CdmsFile Constructors :align: left - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. + * ``path`` is the file pathname, a string. + * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." CdmsFile Methods Object Name Transient Variable @@ -539,8 +550,14 @@ CdmsFile Methods Copy Axis, Grid :widths: 10, 30, 80 :align: left - "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." - "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. + * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. + * ``axis`` is the axis object to be copied. + * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. + * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. + * ``grid`` is the grid object to be copied. + * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." CdmsFile Methods Create Axis, RectGrid and Variable ---------------------------------------------------- @@ -550,10 +567,23 @@ CdmsFile Methods Create Axis, RectGrid and Variable :widths: 10, 30, 80 :align: left - "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. + * ``id`` is an alphanumeric string identifier, containing no blanks. + * ``ar`` is the one-dimensional axis array. + * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. + * ``lon`` is a longitude axis in the file. + * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). + * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. + * ``id`` is a String name which is unique with respect to all other objects in the file. + * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. + * ``axes`` is a list of Axis and/or Grid objects. + * ``fill_value`` is the missing value (optional)." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." @@ -566,7 +596,10 @@ CdmsFile Methods Read CurveGrid, Generic-Grid :widths: 10, 30, 80 :align: left - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." @@ -579,8 +612,9 @@ CdmsFile Methods Write Variable :align: left - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable. + * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. + * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. * ``var`` is a Variable, masked array, or Numpy array. * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``. @@ -709,9 +743,11 @@ Database Constructors :align: left - "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." - ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." - ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. + * For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. + * For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. + * If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. + * If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" Database Methods ---------------- @@ -729,8 +765,8 @@ Database Methods * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. * ``openDataset``, is a synonym for ``open``." - "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database. + * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. **Example:** * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. @@ -878,8 +914,10 @@ SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." - "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." - ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. + * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. + * ``tag`` restricts the search to objects of the class denoted by the tag. + **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute From a27487c87e35bbb123c7ad1ffdccb4ebf20b2cac Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 6 Jun 2018 15:43:33 -0700 Subject: [PATCH 141/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 105 +++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 3c6bde95..a4c914e2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -143,27 +143,39 @@ Cdms Module Functions :align: left - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." + "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. + * ``s`` is a masked array, Numpy array, or Variable. + * If ``s`` is already a transient variable, ``s`` is returned. + * See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. - * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * ``data`` is a one-dimensional, monotonic Numpy array. + * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, + * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. + * If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + * ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" + , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + * ``nlats`` is the number of latitudes. + * ``xorigin`` is the origin of the longitude axis. + * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values. + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." + , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. @@ -185,7 +197,8 @@ Cdms Module Functions * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``:" - ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." + ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. @@ -196,15 +209,20 @@ Cdms Module Functions , " * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: " , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. - * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + "``Dataset``", "``open(url,mode='r')``:" + , "Open or create a ``Dataset`` or ``CdmsFile``. + * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. + * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. + * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." + , "Find the index permutation of axes to match order. Return a list of indices. + * ``axes`` is a list of axis objects. + * ``orderstring`` is defined as in ``orderparse``." "``List``", "``orderparse(orderstring)``:" , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: * Letters t, x, y, z meaning time, longitude, latitude, level @@ -216,7 +234,9 @@ Cdms Module Functions , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. - * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. + + **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. @@ -338,9 +358,13 @@ CoordinateAxis Constructors "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: - * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or - * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. + * ``name`` is the string ``name`` of the ``Axis``. + * ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. + To define an axis as unlimited, either: + + * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or + * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. @@ -426,7 +450,7 @@ CoordinateAxis Methods, Additional to CoordinateAxis * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. - * otherwise the interval wraps around the axis endpoint." + * otherwise the interval wraps around the axis endpoint. * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." @@ -571,7 +595,8 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``id`` is an alphanumeric string identifier, containing no blanks. * ``ar`` is the one-dimensional axis array. * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the file. * ``lon`` is a longitude axis in the file. * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. @@ -1348,17 +1373,19 @@ HorizontalGrid Methods "Tuple", "``getBounds()``", "Get the grid boundary arrays." ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: - * for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). - * for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). - * for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." - "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." - ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. + * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. + * ``lonBounds`` is defined similarly for the longitude array. + **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` @@ -1375,7 +1402,9 @@ HorizontalGrid Methods * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. * An interval of ``None`` returns the full index interval of the axis. * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. + * If the grid is already curvilinear, a copy of the grid object is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." @@ -1405,7 +1434,7 @@ RectGrid Methods, Additional to HorizontalGrid Methods * Also see the function ``area_weights`` in module ``pcmdi.weighting``." ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. **Example:** @@ -1472,8 +1501,20 @@ Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. - * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." + * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. + * ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. + **Note:** this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. + * ``array`` is the data values: a Variable, masked array, or Numpy array. + * ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. + * ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. + * ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. + * ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. + * ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. + * ``grid`` is a rectilinear grid object. + * ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. + * ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. + * ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1541,12 +1582,12 @@ Variable Methods "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. **Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." - ,, "``newLevel`` is an axis of the result pressure levels." - ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" - ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" - ,, "See also: ``regrid``, ``crossSectionRegrid``." + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()`` + * See also: ``regrid``, ``crossSectionRegrid``." "Integer", "``rank()``", "The number of dimensions of the variable." "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. From 7d0bd025060004a451d1226dd623b1c7a133e2c6 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 7 Jun 2018 15:29:06 -0700 Subject: [PATCH 142/239] Changes made to Chapters 2, 3, 4,5 and 6 --- docs/source/manual/cdms_2.rst | 47 +++++++++++++++++-------------- docs/source/manual/cdms_3.rst | 52 ++++++++++++++++++----------------- docs/source/manual/cdms_4.rst | 50 ++++++++++++++++----------------- docs/source/manual/cdms_5.rst | 22 ++++++++------- docs/source/manual/cdms_6.rst | 22 +++++++-------- 5 files changed, 100 insertions(+), 93 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index a4c914e2..dd64eda2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -157,9 +157,12 @@ Cdms Module Functions * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. - * ``nlat`` is the axis length. The axis is not associated with a file or dataset." + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + , "Create a Gaussian latitude axis. Axis values range from north to south. + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. @@ -214,7 +217,7 @@ Cdms Module Functions * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. - * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * ``mode`` is the open mode. See `Open Modes <#id3>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` @@ -319,9 +322,9 @@ It may be contained in a file or dataset, or may be transient file, and referencing a file CoordinateAxis slice reads data from the file. Axis objects are also used to define the domain of a Variable. -CDMS defines several different types of CoordinateAxis objects. See `MV module <#id3>`_ +CDMS defines several different types of CoordinateAxis objects. See `MV module <#id5>`_ documents methods that are common to all CoordinateAxis -types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D +types. See `HorizontalGrid <#id7>`_ specifies methods that are unique to 1D Axis objects. CoordinateAxis Types @@ -381,7 +384,7 @@ CoordinateAxis Methods :align: left - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#id15>`_ for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." @@ -425,7 +428,9 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." - "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. + * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. + **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: * ``axis.topology == 'circular'``, or @@ -523,7 +528,7 @@ CdmsFile Constructors "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. * ``path`` is the file pathname, a string. - * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + * ``mode`` is the open mode indicator, as listed in `Open Modes <#id3>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." CdmsFile Methods Object Name Transient Variable @@ -536,7 +541,7 @@ CdmsFile Methods Object Name Transient Variable "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + ,, "object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -1106,7 +1111,7 @@ Dataset Constructors :widths: 50, 80 :align: left - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#id3>`__ . ``openDataset`` is a synonym for ``open``" Open Modes @@ -1130,7 +1135,7 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. **Example:** The following reads data for variable 'prc', year 1980: @@ -1206,7 +1211,7 @@ The command allows use of MV commands without any prefix. -Table `Variable Constructors in module MV <#table-variable-constructors-in-module-mv>`_, lists the constructors in MV. All functions return +Table `Variable Constructors in module MV <#id5>`_, lists the constructors in MV. All functions return a transient variable. In most cases the keywords axes, attributes, and id are available. axes is a list of axis objects which specifies the domain of the variable. attributes is a dictionary. id is a special @@ -1527,7 +1532,7 @@ Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." @@ -1598,7 +1603,7 @@ Variable Methods "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. - * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1739,7 +1744,7 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_. +ranges as defined in See `Index and Coordinate Intervals <#id11>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds @@ -1753,16 +1758,16 @@ Selector Keywords :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id11>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id11>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id11>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id11>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); = 1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id11>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For @@ -1776,7 +1781,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ are treated as positional. Such +form(s) listed in `Index and Coordinate Intervals <#id11>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index c2df2de6..784451b4 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -86,18 +86,20 @@ Table Time Constructors :widths: 10, 40, 80 :align: left - "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." - ,, "``value`` is an integer or floating point value." - ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" - ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" - - "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." - ,,"``year`` is an integer." - ,,"``month`` is an integer in the range 1 .. 12" - ,,"``day`` is an integer in the range 1 .. 31" - ,,"``hour`` is an integer in the range 0 .. 23" - ,,"``minute`` is an integer in the range 0 .. 59" - ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type. + * ``value`` is an integer or floating point value. + * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]`` + * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. + * The default basetime is 1979-1-1, if no ``since`` clause is specified. + **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + + "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type. + * ``year`` is an integer. + * ``month`` is an integer in the range 1 .. 12 + * ``day`` is an integer in the range 1 .. 31 + * ``hour`` is an integer in the range 0 .. 23 + * ``minute`` is an integer in the range 0 .. 59 + * ``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" Relative Time @@ -146,19 +148,19 @@ Table Time Methods :widths: 20, 75, 80 :align: left - "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" - ,, "``calendar`` is the calendar type." - "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." - ,, "``t2`` is the time to compare." - ,, "``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" - ,, "``calendar`` is the calendar type. " - "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." - ,, "``calendar`` is the calendar type." + "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]`` + * ``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively. + * ``t2`` is the time to compare. + * ``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)] + * ``calendar`` is the calendar type. " + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time. + * ``calendar`` is the calendar type." "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 4f639f7f..9b2987cd 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -319,21 +319,21 @@ function: Table SCRIP Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. csv-table:: :header: "Constructor", "Description" :widths: 80, 90 :align: left - "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object." - "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." - "", "``mapMethod`` is one of:" - "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." - "", "- ``'bilinear'``: bilinear interpolation" - "", "- ``'bicubic'``: bicubic interpolation" - "", "- ``'distwgt'``: distance-weighted interpolation." - "", "It is only necessary to specify the map method if it is not defined in the file." - "", "" - "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object. + * ``fileobj`` is a CDMS file object, as returned from ``cdms.open``. + * ``mapMethod`` is one of: + * ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved. + * ``'bilinear'``: bilinear interpolation + * ``'bicubic'``: bicubic interpolation + * ``'distwgt'``: distance-weighted interpolation. + * It is only necessary to specify the map method if it is not defined in the file. + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." Regridder Functions ^^^^^^^^^^^^^^^^^^^ @@ -407,17 +407,15 @@ Table CDMS Regridder Function :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." - , , "``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4." - , , - , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." - , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." - , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" - , , "- ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." - , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." - "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." - , , "``dataArray`` is the result data array." - , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). + * ``dataArray`` is the result data array. + * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." SCRIP Regridder Functions ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -469,11 +467,11 @@ Table SCRIP Regridder Functions :align: left "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable." - ,,"``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - ,,"``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``." - ,,"``gradientLon``: df/dj. Same shape as ``array``." - ,,"``gradientLatLon``: d(df)/(di)(dj). Same shape as array." + "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. + * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. + * ``gradientLon``: df/dj. Same shape as ``array``. + * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array." "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid." "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid." "CurveGrid or Generic-Grid", "``getInputGrid()``", "Return the input grid, or None if no input grid is associated with the regridder." diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index b53c45ea..0831ec8a 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -187,27 +187,29 @@ Table Plot Keywords "``comment1``", "string", "Comment plotted above ``file_comment``" "``comment2``", "string", "Comment plotted above ``comment1``" "``comment3``", "string", "Comment plotted above ``comment2``" - "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if ``xaxis`` is longitude, ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" + "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if + * ``xaxis`` is longitude, + * ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" "``file_comment``", "string", "Comment, defaults to ``variable.parent.comment``" "``grid``", "CDMS grid object", "Grid associated with the data. Defaults to ``variable.getGrid()``" "``hms``", "string", "Hour, minute, second" "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" "``name``", "string", "Variable name, defaults to ``variable.id``" - "``time``", "cdtime relative or absolute", "Time associated with the data." - ,,"Example:" - ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" + "``time``", "cdtime relative or absolute", "Time associated with the data. + **Example:** + ``cdtime.reltime(30.0, 'days since 1978-1-1').``" "``units``", "string", "Data units. Defaults to ``variable.units``" "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" - "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. + * ``xaxis`` defaults to ``grid.getAxis(0)`` + * ``yaxis`` defaults to ``grid.getAxis(1)``" "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." - "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" - "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions:" - ,,"- If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1" - ,,"- If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." - + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions: + * If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1 + * If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index ade53ebe..1c73923e 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -235,12 +235,12 @@ Table Axis Elements :widths: 18,1,1,1,80 "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates." - "``axis``", "N", "Y", "Y", "The spatial type of the axis:" - ,,,,"- 'T' - time" - ,,,,"- 'X' - longitude" - ,,,,"- 'Y' - latitude" - ,,,,"- 'Z' - vertical level" - ,,,,"- '-' - not spatiotemporal" + "``axis``", "N", "Y", "Y", "The spatial type of the axis: + * 'T' - time + * 'X' - longitude + * 'Y' - latitude + * 'Z' - vertical level + * '-' - not spatiotemporal" "``bounds``", "N", "Y", "Y", "ID of the boundary variable" "``calendar``", "N", "Y", "N", "See dataset.calendar" "``climatology``", "N", "Y", "N", "Range of dates to which climatological statistics apply." @@ -251,9 +251,9 @@ Table Axis Elements "``expand``", "N", "N", "Y", "Coordinates prior to contraction" "``formula_terms``", "N", "Y", "N", "Variables that correspond to the terms in a formula." "``id``", "Y", "N", "N", "Axis identifier. Also the name of the axis in the underlying file(s), if name_in_file is undefined." - "``isvar``", "N", "N", "N", "* 'true' | 'false'" - ,,,,"- 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s)." - ,,,,"- Default: 'true'" + "``isvar``", "N", "N", "N", "'true' | 'false' + * 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s). + * Default: 'true'" "``leap_month``", "N", "Y", "N", "For a user-defined calendar, the month which is lengthened by a day in leap years." "``leap_year``", "N", "Y", "N", "An example of a leap year for a user-defined calendar. All years that differ from this year by a multiple of four are leap years." "``length``", "N", "N", "N", "Number of axis values, including values for which no data is defined. Cf. partition_length." @@ -265,8 +265,8 @@ Table Axis Elements "``partition_length``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." "``positive``", "N", "Y", "Y", "Direction of positive for a vertical axis" "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." - "``topology``", "N", "N", "Y", "- Axis topology." - ,,,,"- 'circular' | 'linear'" + "``topology``", "N", "N", "Y", "Axis topology. + * 'circular' | 'linear'" "``units``", "Y", "Y", "Y", "Units of a physical quantity" "``weights``", "N", "N", "N", "Name of the weights array" From 4523dc23026fc11faa77179d37c271ba555e29ef Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 11 Jun 2018 15:43:35 -0700 Subject: [PATCH 143/239] Changes made to Sections 2, 4, 7 and Appendix --- docs/source/manual/cdms_2.rst | 112 ++++++++++++++------------- docs/source/manual/cdms_4.rst | 4 +- docs/source/manual/cdms_7.rst | 67 +++++++++------- docs/source/manual/cdms_appendix.rst | 81 ++++++++++++------- 4 files changed, 153 insertions(+), 111 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index dd64eda2..449e02e4 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -143,77 +143,78 @@ Cdms Module Functions :align: left - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. + "``Variable``", "``asVariable(s)``: + Transform ``s`` into a transient variable. * ``s`` is a masked array, Numpy array, or Variable. * If ``s`` is already a transient variable, ``s`` is returned. * See also: ``isVariable``." - "``Axis``", "``createAxis(data, bounds=None)``:" - , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. + "``Axis``", "``createAxis(data, bounds=None)``: + Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. * ``data`` is a one-dimensional, monotonic Numpy array. * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. * If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" - "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + "``Axis``", "``createEqualAreaAxis(nlat)``: + Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." - "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. + "``Axis``", "``createGaussianAxis(nlat)``: + Create a Gaussian latitude axis. Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." - "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: + Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. * ``xorigin`` is the origin of the longitude axis. * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" - "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``: + Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." - "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + "``RectGrid``", "``createGlobalMeanGrid(grid)``: + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. * ``grid`` is a RectGrid." - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" - , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: + Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. * ``lon`` is a longitude axis, created by ``cdms.createAxis``. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" - , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: + Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``. * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" - , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: + Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." - "``RectGrid``","``createZonalGrid(grid)``:" - ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + "``RectGrid``","``createZonalGrid(grid)``: + Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." - "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" - , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: + Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." - , " * See ``setAutoBounds``." - "``Integer``", "``isVariable(s)``: " - , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``:" - , "Open or create a ``Dataset`` or ``CdmsFile``. + "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. + * See ``setAutoBounds``." + "``Integer``", "``isVariable(s)``: + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + "``Dataset``", "``open(url,mode='r')``: + Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. @@ -222,30 +223,30 @@ Cdms Module Functions * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" - "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. + "``List``", "``order2index (axes, orderstring)``: + Find the index permutation of axes to match order. Return a list of indices. * ``axes`` is a list of axis objects. * ``orderstring`` is defined as in ``orderparse``." - "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: + "``List``", "``orderparse(orderstring)``: + Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: * Letters t, x, y, z meaning time, longitude, latitude, level * Numbers 0-9 representing position in axes * Dash (-) meaning insert the next available axis here. * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" - "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: + "``None``", "``setAutoBounds(mode)``: + Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." - "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. + "``None``", "``setClassifyGrids(mode)``: + Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." - "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. + "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: + Write a grid to a SCRIP grid file. * ``path`` is a string, the path of the SCRIP file to be created. * ``grid`` is a CDMS grid object. It may be rectangular. * ``gridTitle`` is a string ID for the grid." @@ -305,10 +306,14 @@ Getting and Setting Attributes :header: "Type", "Definition" :widths: 20, 80 - "various", "``value = obj.attname``" - , "Get an internal or external attribute value. If the attribute is external, it is read from the database. If the attribute is not already in the database, it is created as an external attribute. Internal attributes cannot be created, only referenced." - "various", "``obj.attname = value``" - , "Set an internal or external attribute value. If the attribute is external, it is written to the database." + "various", "``value = obj.attname`` + Get an internal or external attribute value. + * If the attribute is external, it is read from the database. + * If the attribute is not already in the database, it is created as an external attribute. + * Internal attributes cannot be created, only referenced." + "various", "``obj.attname = value`` + St an internal or external attribute value. + * If the attribute is external, it is written to the database." @@ -540,8 +545,7 @@ CdmsFile Methods Object Name Transient Variable :align: left - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -966,7 +970,8 @@ ResultEntry Attributes :widths: 20, 30, 80 "String", "``name``", "The name of this entry in the database." - "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" + "Dictionary", "``attributes``", "The attributes returned from the search. + * ``attributes[key]`` is a list of all string values associated with the key" ResultEntry Methods @@ -976,8 +981,8 @@ ResultEntry Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry." - ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." + "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. + **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." Accessing data @@ -1375,8 +1380,8 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." - "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + "Tuple", "``getBounds()``", "Get the grid boundary arrays. + * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). @@ -1434,10 +1439,9 @@ RectGrid Methods, Additional to HorizontalGrid Methods * Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``. * from cdms import MV - * latwts, lonwts = gri d.getWeights() - * weights = MV.outerproduct(latwts, lonwts) + * ``latwts``, ``lonwts`` = ``grid.getWeights()`` + * weights = MV.outerproduct(``latwts``, ``lonwts``) * Also see the function ``area_weights`` in module ``pcmdi.weighting``." - ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. @@ -1534,7 +1538,7 @@ Variable Methods "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 9b2987cd..d089ca99 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -466,7 +466,9 @@ Table SCRIP Regridder Functions :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." + "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. + * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable. * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 0e311778..04a90c7c 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -67,40 +67,55 @@ Table CDScan Command Options :header: "Option:, "Description" :widths: 20, 80 - "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. ``variable_id`` is the ID of the variable in the file, and ``alias`` is the name that will be substituted for it in the output dataset. Only variables with entries in the ``alias_file`` are renamed." - "``-c calendar``", "Specify the dataset calendar attribute. One of:" - , "- gregorian (default)" - , "- julian" - , "- noleap" - , "- proleptic_gregorian" - , "- standard" - , "- 360_day" + "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. + * ``variable_id`` is the ID of the variable in the file, and + * ``alias`` is the name that will be substituted for it in the output dataset. + * Only variables with entries in the ``alias_file`` are renamed." + "``-c calendar``", "Specify the dataset calendar attribute. One of: + * gregorian (default) + * julian + * noleap + * proleptic_gregorian + * standard + * 360_day" "``-d dataset_id``", "String identifier of the dataset. Should not contain blanks or non-printing characters. Default: 'None'" - "``-e newattr``", "Add or modify attributes of a file, variable, or axis." - ,"- The form of ``newattr`` is either:" - ," - ``var.attr = value`` to modify a variable or attribute, or" - ," - ``.attr = value`` to modify a global (file) attribute. In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." + "``-e newattr``", "Add or modify attributes of a file, variable, or axis. The form of ``newattr`` is either: + * ``var.attr = value`` to modify a variable or attribute, or + * ``.attr = value`` to modify a global (file) attribute. + * In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. + * If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." "``--exclude var,var,...``", "Exclude specified variables. The argument is a comma-separated list of variables containing no blanks. Also see ``--include``." "``-f file_list``", "File containing a list of absolute data file names, one per line." "``-h``", "Print a help message." - "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. ``time_delta`` is a float or integer. For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." + "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. + * ``time_delta`` is a float or integer. + * For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." "``--include var,var,...``", "Only include specified variables in the output. The argument is a comma-separated list of variables containing no blanks. Also see ``--exclude``." - "``-j``", "Scan time as a vector dimension. Time values are listed individually." - ,"- **Note:** Turns off the -i option." - "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." + "``-j``", "Scan time as a vector dimension. Time values are listed individually. + **Note:** Turns off the -i option." + "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. + * ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." "``-m levelid``", "Name of the vertical level dimension. The default is the vertical dimension as determined by CDMS. See Note 3." - "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. ``cdimport -h`` describes template strings." + "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. + * ``cdimport -h`` describes template strings." "``-q``", "Quiet mode." - "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." - "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. Each line consists of two blank-separated fields: ``directory suffix``. Each file path is compared to the directories in the suffix file. If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. If more than one such directory is found, the first directory found is used. If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." + "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where + * ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." + "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. + * ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. + * Each line consists of two blank-separated fields: ``directory suffix``. + * Each file path is compared to the directories in the suffix file. + * If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. + * If more than one such directory is found, the first directory found is used. + * If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." "``-t timeid``", "ID of the partitioned time dimension. The default is the name of the time dimension as determined by CDMS. See Note 1." - "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list:" - , "- zero is the initial time point, a floating-point value." - , "- delta is the time delta, floating-point." - , "- units are time units as specified in the [-r] option." - , "- calendar is optional, and is specified as in the [-c] option." - , "If omitted, it defaults to the value specified by [-c], otherwise as specified in the file." - , "**Example:** ``--time-linear '0,1,months since 1980,noleap'``" + "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list: + * zero is the initial time point, a floating-point value. + * delta is the time delta, floating-point. + * units are time units as specified in the [-r] option. + * calendar is optional, and is specified as in the [-c] option. + * If omitted, it defaults to the value specified by [-c], otherwise as specified in the file. + **Example:** ``--time-linear '0,1,months since 1980,noleap'``" "``-x xmlfile``", "Output file name. By default, output is written to standard output." **Notes:** diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 13bba1f8..6605166e 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -219,12 +219,23 @@ Table Slab Methods :widths: 20,50,80 :align: left - "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." - "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." - "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." - "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." + "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. + * ``dim`` is the dimension number, an integer in the range 0..rank- 1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getattribute(name)``", "Get the value of an attribute. + * ``name`` is the string name of the attribute. + The following special names can always be used: + ``filename``, ``comments``, ``grid_name``, ``grid_type``. ``time_statistic``, ``long_name``, ``units``." + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. + * If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." + "List", "``listall(all=None)``", "Print slab information. + * If ``all`` is nonzero, dimension values, weights, and bounds are also printed." + "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. + * ``dim`` is the dimension number, an integer in the range 0..rank-1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "None", "``setattribute(name, value)``", "Set an attribute. + * ``name`` is the string name of the attribute. + * ``value`` is the value of the attribute." @@ -241,34 +252,44 @@ Table cuDataset Methods :align: left "None", "``cleardefault()``", "Clear the default variable name." - "None", "``default_variable(vname``)", "Set the default variable name." - ,,"vname is the string variable name." - "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname." - ,,"dname is the string axis name." - ,,"vname is the string variable name. The default is the variable name set by default_variable." - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." + "None", "``default_variable(vname``)", "Set the default variable name. + * ``vname`` is the string variable name." + "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname. + * ``dname`` is the string axis name. + * ``vname`` is the string variable name. + * The default is the variable name set by ``default_variable.``" + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by ``default_variable.``" "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." - "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension." - ,,"dname is the string name of an axis." - ,,"vname is a string variable name. The default is the variable name set by default_variable." + "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. + * ``dname`` is the string name of an axis. + * ``vname`` is a string variable name. + * The default is the variable name set by ``default_variable``." "Various", "``getglobal (attribute)``", "Get the value of the global attribute. attribute is the string attribute name." - "Variable", "``getslab (vname, \*args)``", "Read data for a variable." - ,, "vname is the string name of the variable." - ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" - ,, "- ':' or None -- select the entire dimension" - ,, "- Ellipsis -- select entire dimensions between the ones given." - ,, "- a pair of successive arguments giving an interval in world coordinates." - ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" - "List", "``listall (vname=None, all=None)``", "Get info about data from the file." - ,, "vname is the string name of the variable." - ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" - "List", "``listattribute (vname=None )``", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." - "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "Variable", "``getslab (vname, \*args)``", "Read data for a variable. + * ``vname`` is the string name of the variable. + * ``args`` is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be: + * ':' or None -- select the entire dimension + * Ellipsis -- select entire dimensions between the ones given. + * a pair of successive arguments giving an interval in world coordinates. + * a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" + "List", "``listall (vname=None, all=None)``", "Get info about data from the file. + * ``vname`` is the string name of the variable. + * If all is non-zero, dimension values, weights, and bounds are returned as well" + "List", "``listattribute (vname=None )``", "Return a list of attribute names. + * ``vname`` is the name of the variable. + * The default is the variable name set by ``default_variable.``" + "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. + * ``vname`` is the name of the variable. + * The default is the variable name set by ``default_variable.``" "List", "``listglobal ()``", "Return a list of the global attribute names." "List", "``listvariable ()``", "Return a list of the variables in the file." - "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." - "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." - "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. + * ``vname`` is the string name of the variable. + * If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. + * ``vname`` is the string name of the variable. Output is sent to device." + "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. + * ``vname`` is the string name of the variable. Output is sent to device." "None", "``showglobal (device=sys.stdout)``", "Print the global file attributes. Output is sent to device." "None", "``showvariable (device=sys.stdout)``", "Print the list of variables in the file." From e550c14ff18ce3cf2a4ca80247a21b0bbecddba1 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 12 Jun 2018 15:46:39 -0700 Subject: [PATCH 144/239] Changes made to Chapter 6 and Appendix --- docs/source/manual/cdms_6.rst | 6 +++--- docs/source/manual/cdms_appendix.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 1c73923e..5d9e6b5e 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -162,9 +162,9 @@ Dataset Attributes :widths: 10,5,5,5,80 "appendices", "N", "N", "Y", "Version number" - "calendar", "N", "N", "Y", "Calendar used for encoding time axes." - ,,,,"``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard``" - ,,,,"Note: for the CF convention, the calendar attribute is placed on the time axis." + "calendar", "N", "N", "Y", "Calendar used for encoding time axes. + * ``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard`` + * Note: for the CF convention, the calendar attribute is placed on the time axis." "comment", "N", "Y", "Y", "Additional dataset information" "conventions", "Y", "Y", "Y", "The netCDF metadata standard. Example: 'CF-1.0'" "cdms_filemap", "Y", "N", "N", "Map of partitioned axes to files. See note below." diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 6605166e..0f3ceb76 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -258,8 +258,8 @@ Table cuDataset Methods * ``dname`` is the string axis name. * ``vname`` is the string variable name. * The default is the variable name set by ``default_variable.``" - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by ``default_variable.``" - "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. ``dname`` is the string name of an axis. ``vname`` is a string variable name. The default is the variable name set by ``default_variable.``" + "Various", "``getattribute (vname, attribute``)", "Get an attribute value. ``vname`` is a string variable name. attribute is the string attribute name." "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. * ``dname`` is the string name of an axis. * ``vname`` is a string variable name. From 554bd4c99a8c0b507e56864dc488822a66f82681 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 13 Jun 2018 15:41:46 -0700 Subject: [PATCH 145/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 278 +++++++++++++++++++--------------- 1 file changed, 157 insertions(+), 121 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 449e02e4..c667c97f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -178,7 +178,7 @@ Cdms Module Functions * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``: - Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of the input grid. * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. @@ -202,22 +202,24 @@ Cdms Module Functions * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. - * ``grid`` is a RectGrid." + * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. - * See ``setAutoBounds``." + "``Integer``", "``getAutoBounds()``: + Get the current autobounds mode. Returns 0, 1, or 2. + * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: - * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. - * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. + * If the protocol is 'file' or is omitted, a local file or dataset is opened. * ``mode`` is the open mode. See `Open Modes <#id3>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` @@ -246,10 +248,10 @@ Cdms Module Functions * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: - Write a grid to a SCRIP grid file. - * ``path`` is a string, the path of the SCRIP file to be created. - * ``grid`` is a CDMS grid object. It may be rectangular. - * ``gridTitle`` is a string ID for the grid." + Write a grid to a SCRIP grid file. + * ``path`` is a string, the path of the SCRIP file to be created. + * ``grid`` is a CDMS grid object. It may be rectangular. + * ``gridTitle`` is a string ID for the grid." : @@ -374,10 +376,10 @@ CoordinateAxis Constructors * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` - * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. - * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. - * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. - * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." + * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. + * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. + * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. + * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." CoordinateAxis Methods @@ -389,30 +391,42 @@ CoordinateAxis Methods :align: left - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#id15>`_ for a description of slice operators." - "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." - "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." - "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." - "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. + * Data is returned in the physical ordering defined in the dataset. + * See `Variable Slice Operators <#id15>`_ for a description of slice operators." + "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. + * Dataset axes are read-only." + "``None``", "``assignValue(array)``", "Set the entire value of the axis. + * ``array`` is a Numpy array, of the same dimensionality as the axis." + "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. + * If copyData is 1 (the default) the data itself is copied." + "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. + * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. + * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. + * ``modulo`` is the modulus value. Any given axis value + * ``x`` is treated as equivalent to ``x + modulus``. + *If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. + * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. + * ``calendar`` is defined as in ``getCalendar()``." "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: - * ``Axis``: ``(n,2)`` * ``Axis2D``: ``(i,j,4)`` * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. - * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. + * See ``setAutoBounds``." "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: - * ``cdtime.GregorianCalendar``: the standard Gregorian calendar - * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar - * ``cdtime.JulianCalendar``: years divisible by 4 are leap years - * ``cdtime.NoLeapCalendar``: a year is 365 days - * ``cdtime.Calendar360``: a year is 360 days - * ``None``: no calendar can be identified + * ``cdtime.GregorianCalendar``: the standard Gregorian calendar + * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar + * ``cdtime.JulianCalendar``: years divisible by 4 are leap years + * ``cdtime.NoLeapCalendar``: a year is 365 days + * ``cdtime.Calendar360``: a year is 360 days + * ``None``: no calendar can be identified + **Note** If the axis is not a time axis, the global, file-related calendar is returned." - * **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." @@ -435,7 +449,7 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. - **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: * ``axis.topology == 'circular'``, or @@ -444,24 +458,24 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: - * ``(x,y)`` - * ``(x,y,indicator)`` - * ``(x,y,indicator,cycle)`` - * ``None or ':'`` - * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: - * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi - * ``'n'`` - select node values which are contained in the interva - * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval - * ``'e'`` - same as n, but include an extra node on either sid - * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval - * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. - * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. - * An interval of ``None`` or ``':'`` returns the full index interval of the axis. - * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. - * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` - * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. - * otherwise the interval wraps around the axis endpoint. - * see also: ``mapinterval``, ``variable.subregion()``" + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None or ':'`` + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: + * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi + * ``'n'`` - select node values which are contained in the interva + * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval + * ``'e'`` - same as n, but include an extra node on either sid + * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval + * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * An interval of ``None`` or ``':'`` returns the full index interval of the axis. + * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. + * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` + * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. + * otherwise the interval wraps around the axis endpoint. + * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." CoordinateAxis Slice Operators @@ -549,8 +563,8 @@ CdmsFile Methods Object Name Transient Variable **Example:** The following reads data for variable 'prc', year 1980: - * >>> f = cdms.open('test.nc') - * >>> x = f('prc', time=('1980-1','1981-1'))" + * >>> f = cdms.open('test.nc') + * >>> x = f('prc', time=('1980-1','1981-1'))" CdmsFile Methods Object Identifier Variable, Axis or Grid --------------------------------------------------------- @@ -564,15 +578,15 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid **Example:** The following gets the persistent variable - * ``v``, equivalent to - * ``v = f.variables['prc']``. - * f = cdms.open('sample.nc') - * v = f['prc'] + * ``v``, equivalent to + * ``v = f.variables['prc']``. + * f = cdms.open('sample.nc') + * v = f['prc'] **Example:** The following gets the axis named time, equivalent to - * ``t = f.axes['time']``. - * ``t = f['time']``" + * ``t = f.axes['time']``. + * ``t = f['time']``" "``None``", "``close()``", "Close the file." CdmsFile Methods Copy Axis, Grid @@ -584,13 +598,13 @@ CdmsFile Methods Copy Axis, Grid :align: left "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. - * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. - * ``axis`` is the axis object to be copied. - * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. + * ``axis`` is the axis object to be copied. + * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. - * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. - * ``grid`` is the grid object to be copied. - * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. + * ``grid`` is the grid object to be copied. + * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." CdmsFile Methods Create Axis, RectGrid and Variable ---------------------------------------------------- @@ -605,19 +619,19 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``ar`` is the one-dimensional axis array. * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. - * ``lat`` is a latitude axis in the file. - * ``lon`` is a longitude axis in the file. - * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). - * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. - * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + * ``lat`` is a latitude axis in the file. + * ``lon`` is a longitude axis in the file. + * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). + * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. * ``id`` is a String name which is unique with respect to all other objects in the file. * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. * ``axes`` is a list of Axis and/or Grid objects. * ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. - * ``var`` is the ``Variable`` to be copied. - * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." @@ -633,7 +647,7 @@ CdmsFile Methods Read CurveGrid, Generic-Grid "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. - * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." @@ -794,13 +808,13 @@ Database Methods "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." "Dataset", "``open(dsetid, mode='r')``", "Open a dataset. - * ``dsetid``, is the string dataset identifier + * ``dsetid``, is the string dataset identifier - * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. - * ``openDataset``, is a synonym for ``open``." + * ``openDataset``, is a synonym for ``open``." "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database. - * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. **Example:** * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. @@ -949,9 +963,9 @@ SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. - * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. - * ``tag`` restricts the search to objects of the class denoted by the tag. - **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. + * ``tag`` restricts the search to objects of the class denoted by the tag. + **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -982,7 +996,7 @@ ResultEntry Methods :widths: 20, 30, 80 "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. - **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." + **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." Accessing data @@ -1142,26 +1156,25 @@ Dataset Methods "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. - **Example:** The following reads data for variable 'prc', year 1980: - - * f = cdms.open('test. xml') + **Example:** The following reads data for variable 'prc', year 1980: - * x = f('prc', time=('1980-1','1981-1'))" + * f = cdms.open('test. xml') + * x = f('prc', time=('1980-1','1981-1'))" "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. - **Example:** + **Example:** - * f = cdms.open('sampl e.xml') - * v = f['prc'] + * f = cdms.open('sampl e.xml') + * v = f['prc'] - * gets the persistent variable v equivalent to ``v=f.variables['prc']``. + * gets the persistent variable v equivalent to ``v=f.variables['prc']``. - **Example:** + **Example:** - * t = f['time'] + * t = f['time'] - * gets the axis named time, equivalent to ``t=f.axes['time']``" + * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. * ``lat`` is a latitude axis in the dataset. @@ -1381,22 +1394,24 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." "Tuple", "``getBounds()``", "Get the grid boundary arrays. - * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: - * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). - * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). - * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. - * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. - * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. - * ``lonBounds`` is defined similarly for the longitude array. - **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." - "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." + * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. + * ``lonBounds`` is defined similarly for the longitude array. + **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setMask(mask, persistent=0)``", "Set the grid mask. + * If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. + * ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` * ``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively. @@ -1409,13 +1424,18 @@ HorizontalGrid Methods * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: * ``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co'). - * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. - * An interval of ``None`` returns the full index interval of the axis. - * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. + * An interval of ``None`` returns the full index interval of the axis. + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. - * If the grid is already curvilinear, a copy of the grid object is returned. - * ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. - **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + * If the grid is already curvilinear, a copy of the grid object is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied. + **Note:** This method does not apply to generic grids. + * Transient-GenericGrid, ``toGenericGrid(gridid=None)`` Convert to a generic grid. + * If the grid is already generic, a copy of the grid is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied." RectGrid Methods, Additional to HorizontalGrid Methods @@ -1425,7 +1445,11 @@ RectGrid Methods, Additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees. + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. + * String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. + + * (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. + **Note** It is assumed that the latitude and longitude axes are defined in degrees. * The latitude weights are defined as: * ``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`` @@ -1442,18 +1466,19 @@ RectGrid Methods, Additional to HorizontalGrid Methods * ``latwts``, ``lonwts`` = ``grid.getWeights()`` * weights = MV.outerproduct(``latwts``, ``lonwts``) * Also see the function ``area_weights`` in module ``pcmdi.weighting``." - "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." + "None", "``setType(gridtype)``", "Set the grid type. + * ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. **Example:** - * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. - * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` - * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. + * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. **Note:** The result grid is not associated with any file or dataset." "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. - **Note:** The result grid is not associated with any file or dataset." + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1566,8 +1591,12 @@ Variable Methods * an axis object; will match if it is the same object as axis. * ``order`` can be a string containing the characters t,x,y,z, or * . * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." - "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." - "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." + "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for ``getAxisList``." + "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, + * ``start`` is the start index of the domain relative to the axis object, + * ``length`` is the length of the axis, and + * ``true\_length`` is the actual number of (defined) points in the domain. + * *See also:* ``getAxisList``." "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." @@ -1583,9 +1612,10 @@ Variable Methods A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude). **Note:** The order string is of the form required for the order argument of a regridder function. - * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned. + * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. + * If no ``argument(s)`` are present, all file paths associated with the variable are returned. - * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. + * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." @@ -1600,14 +1630,20 @@ Variable Methods "Integer", "``rank()``", "The number of dimensions of the variable." "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. - * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. - * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. - * See also: ``crossSectionRegrid``, ``pressureRegrid``." + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. + * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. + * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. - * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. + * If trailing dimensions are omitted, all values of those dimensions are retrieved. + * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." From 506ccb829d8d864ebf456bbd03fc591176b11112 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 13 Jun 2018 17:53:07 -0700 Subject: [PATCH 146/239] update summary table for API --- Lib/avariable.py | 11 ++- Lib/tvariable.py | 1 + docs/source/API.rst | 39 +++++++- docs/source/CDML.rst | 2 + docs/source/CDMLParser.rst | 2 + docs/source/MV2.rst | 93 ++++++++++++++++++- docs/source/avariable.rst | 105 +++++++++++++++------ docs/source/axis.rst | 156 +++++++++++++++++++++++++++++++- docs/source/bindex.rst | 10 +- docs/source/cache.rst | 2 + docs/source/cdmsNode.rst | 2 + docs/source/cdmsobj.rst | 2 + docs/source/cdscan.rst | 2 + docs/source/cdurllib.rst | 2 + docs/source/cdurlparse.rst | 2 + docs/source/cdxmllib.rst | 2 + docs/source/convention.rst | 2 + docs/source/coord.rst | 2 + docs/source/crossSection.rst | 2 + docs/source/cudsinterface.rst | 2 + docs/source/database.rst | 2 + docs/source/dataset .rst | 7 -- docs/source/esmf.rst | 2 + docs/source/forecast.rst | 2 + docs/source/fvariable.rst | 59 +++++++++++- docs/source/gengrid.rst | 2 + docs/source/grid.rst | 2 + docs/source/gsRegrid.rst | 2 + docs/source/gs_horizontal.rst | 2 + docs/source/hgrid.rst | 4 +- docs/source/horizontal.rst | 2 + docs/source/index.rst | 23 ----- docs/source/mvBaseWriter.rst | 2 + docs/source/mvCdmsRegrid.rst | 2 + docs/source/mvESMFRegrid.rst | 2 + docs/source/mvGenericRegrid.rst | 2 + docs/source/mvLibCFRegrid.rst | 2 + docs/source/mvSphereMesh.rst | 2 + docs/source/mvVTKSGWriter.rst | 2 + docs/source/mvVTKUGWriter.rst | 2 + docs/source/mvVsWriter.rst | 2 + docs/source/mySphereMesh.rst | 2 + docs/source/pressure.rst | 2 + docs/source/restApi.rst | 2 + docs/source/scrip.rst | 2 + docs/source/selectors.rst | 2 + docs/source/slabinterface.rst | 2 + docs/source/tanya_2.rst | 7 -- docs/source/tvariable.rst | 135 ++++++++++++++++++++++++++- docs/source/variable.rst | 68 +++++++++++++- 50 files changed, 706 insertions(+), 84 deletions(-) delete mode 100644 docs/source/dataset .rst delete mode 100644 docs/source/tanya_2.rst diff --git a/Lib/avariable.py b/Lib/avariable.py index 33c2d620..ba38c886 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -476,16 +476,21 @@ def hasCellData(self): return False def getAxisListIndex(self, axes=None, omit=None, order=None): - """Return a list of indices of axis objects; + """ - Note - ---- + Parameters + ---------- + axes If axes is **not** `None`, include only certain axes. less the ones specified in omit. If axes is `None`, use all axes of this variable. Other specificiations are as for axisMatchIndex. + + Returns + ------- + a list of indices of axis objects; """ return axisMatchIndex(self.getAxisList(), axes, omit, order) diff --git a/Lib/tvariable.py b/Lib/tvariable.py index a3866bdd..54d6206b 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -85,6 +85,7 @@ def ascontiguousarray(self): ascontiguous = ascontiguousarray def asma(self): + "Convert a Transient Variable into a numpy masked array." return numpy.ma.array(self._data, mask=self._mask) def _update_from(self, obj): diff --git a/docs/source/API.rst b/docs/source/API.rst index a1a9e70c..19a0495d 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -5,8 +5,43 @@ API Classes ------- -.. autosummary:: - :toctree: generated/ +.. csv-table:: + :header: "Type", "Constructor" + :widths: 10, 40 + :align: left + + ":ref:`avariable`", "CDMS Variable objects, abstract interface" + ":ref:`axis`", "CDMS Axis objects" + ":ref:`fvariable`", "CDMS File-based variables." + ":ref:`bindex`", "Bin index for non-rectilinear grids" + ":ref:`variable`", "DatasetVariable: Dataset-based variables" + ":ref:`cache`", "CDMS cache management and file movement objects" + ":ref:`CDML`", "CDML Document Type Definition This defines the CDML language" + ":ref:`cdurllib`", "Customized URLopener" + ":ref:`cdurlparse`", "Parse (absolute and relative) URLs." + ":ref:`cdxmllib`", "A parser for XML, using the derived class as static DTD." + ":ref:`convention`", "metadata conventions" + ":ref:`coord`", "CDMS CoordinateAxis objects" + ":ref:`cudsinterface`", "Emulation of old cu package" + ":ref:`database`", "CDMS database objects" + ":ref:`dataset`", "CDMS dataset and file objects" + ":ref:`forecast`", "CDMS Forecast" + ":ref:`gengrid`", "CDMS Generic Grids" + ":ref:`grid`", "CDMS Grid objects" + ":ref:`hgrid`", "CDMS HorizontalGrid objects" + ":ref:`MV2`", "CDMS Variable objects, MaskedArray interface" + ":ref:`mvCdmsRegrid`", "Cdms2 interface to multiple regridders" + ":ref:`selectors`", "Classes to support easy selection of climate data" + ":ref:`tvariable`", "TransientVariable (created by createVariable) is a child of both AbstractVariable and the masked array class." + ":ref:`mvBaseWriter`", "Abstract class for writing data into file" + ":ref:`mvSphereMesh`", "Class for representing grids on the sphere" + ":ref:`mvVsWriter`", "Write data to VizSchema compliant file" + ":ref:`mvVTKSGWriter`", "Write data to VTK file format using the structured grid format" + ":ref:`mvVTKUGWriter`", "Write data to VTK file format using the unstructured grid format" + ":ref:`restApi`", "" + ":ref:`slabinterface`", "Read part of the old cu slab interface implemented over CDMS" + +.. autosummary:: avariable axis diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst index 68263fb5..8a6c880f 100644 --- a/docs/source/CDML.rst +++ b/docs/source/CDML.rst @@ -1,3 +1,5 @@ +.. _CDML: + CDML ==== diff --git a/docs/source/CDMLParser.rst b/docs/source/CDMLParser.rst index d417412e..f2d801d9 100644 --- a/docs/source/CDMLParser.rst +++ b/docs/source/CDMLParser.rst @@ -1,3 +1,5 @@ +.. _CDMLParser: + CDMLParser ========== diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst index d729f973..8c86924f 100644 --- a/docs/source/MV2.rst +++ b/docs/source/MV2.rst @@ -1,7 +1,96 @@ +.. _MV2: + MV2 === -.. automodule:: cdms2.MV2 - :members: +.. currentmodule:: MV2 + +.. autosummary:: + :toctree: ./generated + allclose + allequal + arange + argsort + arrayrange + asarray + as_masked + asVariable + average + axisAllclose + axisConcatenate + axisTake + choose + commonAxes + commonDomain + common_fill_value + commonGrid1 + commonGrid + compress + concatenate + count + create_mask + diagonal + dot + filled + fill_value + fromfunction + getmaskarray + getmask + getNumericCompatibility + get_print_limit + get_printoptions + indices + innerproduct + isarray + is_floating + is_integer + isMA + isMaskedArray + is_masked + isMaskedVariable + is_mask + left_shift + make_mask_none + make_mask + masked_array + masked_equal + masked_greater_equal + masked_greater + masked_inside + masked_less_equal + masked_less + masked_not_equal + masked_object + masked_outside + masked_values + masked_where + mask_or + max + min + ones + outerproduct + power + product + putmask + put + rank + repeat + reshape + resize + right_shift + sctype2char + set_default_fill_value + set_fill_value + set_print_limit + set_printoptions + shape + size + sort + squeeze + sum + take + transpose + where + zeros diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index ef4f86ea..2ddbd830 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -1,34 +1,85 @@ +.. _avariable: + avariable ========= -#.. automodule:: cdms2.avariable -# :members: - -.. currentmodule:: cdms2 +.. currentmodule:: cdms2.avariable -.. autosummary:: +.. autosummary:: :toctree: generated/ - avariable.splitSlice - avariable.splitSliceExt - avariable.setNumericCompatibility - avariable.orderparse - avariable.order2index - avariable.guessPeriodicity - avariable.getNumericCompatibility - avariable.getMinHorizontalMask - avariable._getCoordList - avariable.getBoundList - avariable.axisMatchIndex - avariable.axisMatches - avariable.axisMatchAxis - avariable.TransientVariable - avariable.Slab - avariable.CdmsRegrid - avariable.CdmsObj - avariable.CDMSError - avariable.AbstractVariable - avariable.AbstractRectGrid - avariable.AbstractAxis - + AbstractVariable.assignValue + AbstractVariable.astype + AbstractVariable.__call__ + AbstractVariable.createattribute + AbstractVariable.crossSectionRegrid + AbstractVariable.decode + AbstractVariable.deleteattribute + AbstractVariable.dump + AbstractVariable.expertSlice + AbstractVariable.generateGridkey + AbstractVariable.generateRectGridkey + AbstractVariable.getattribute + AbstractVariable.getAxisIds + AbstractVariable.getAxisIndex + AbstractVariable.getAxisListIndex + AbstractVariable.getAxisList + AbstractVariable.getAxis + AbstractVariable.getConvention + AbstractVariable.getdimattribute + AbstractVariable.getDomain + AbstractVariable.getForecast + AbstractVariable.getForecastTime + AbstractVariable.getGridIndices + AbstractVariable.getGrid + AbstractVariable.getLatitude + AbstractVariable.getLevel + AbstractVariable.getLongitude + AbstractVariable.getMissing + AbstractVariable.getOrder + AbstractVariable.getRegion + AbstractVariable.getSlice + AbstractVariable.getTime + AbstractVariable.getValue + AbstractVariable.hasCellData + AbstractVariable.info + AbstractVariable.isAbstractCoordinate + AbstractVariable.isEncoded + AbstractVariable.listall + AbstractVariable.listattributes + AbstractVariable.listdimattributes + AbstractVariable.listdimnames + AbstractVariable.matchone + AbstractVariable.matchPattern + AbstractVariable.pressureRegrid + AbstractVariable._process_specs + AbstractVariable.rank + AbstractVariable.regrid + AbstractVariable.reg_specs2slices + AbstractVariable.reorder + AbstractVariable.searchone + AbstractVariable.searchPattern + AbstractVariable.searchPredicate + AbstractVariable.select + AbstractVariable.setattribute + AbstractVariable.setGrid + AbstractVariable.setMissing + AbstractVariable.showdim + AbstractVariable.specs2slices + AbstractVariable.squeeze + AbstractVariable.subRegion + AbstractVariable.subSlice + AbstractVariable.typecode + axisMatchAxis + axisMatches + axisMatchIndex + getBoundList + getMinHorizontalMask + getNumericCompatibility + guessPeriodicity + order2index + orderparse + setNumericCompatibility + splitSliceExt + splitSlice diff --git a/docs/source/axis.rst b/docs/source/axis.rst index e032851f..ab4f1427 100644 --- a/docs/source/axis.rst +++ b/docs/source/axis.rst @@ -1,7 +1,159 @@ +.. _axis: + axis ==== -.. automodule:: cdms2.axis - :members: +.. currentmodule:: cdms2.axis + +.. autosummary:: + :toctree: generated/ + + allclose + axisMatchAxis + axisMatches + axisMatchIndex + concatenate + createAxis + createEqualAreaAxis + createGaussianAxis + createUniformLatitudeAxis + createUniformLongitudeAxis + getAutoBounds + isOverlapVector + isSubsetVector + lookupArray + mapLinearExt + mapLinearIntersection + reverseSlice + setAutoBounds + splitSliceExt + splitSlice + take + AbstractAxis.asComponentTime + AbstractAxis.asdatetime + AbstractAxis.asDTGTime + AbstractAxis.asRelativeTime + AbstractAxis.clone + AbstractAxis.dump + AbstractAxis.getBoundsForDualGrid + AbstractAxis.getBounds + AbstractAxis.getExplicitBounds + AbstractAxis.info + AbstractAxis.isVirtual + AbstractAxis.listall + AbstractAxis.mapIntervalExt + AbstractAxis.mapInterval + AbstractAxis.matchone + AbstractAxis.matchPattern + AbstractAxis.searchone + AbstractAxis.searchPattern + AbstractAxis.searchPredicate + AbstractAxis.subaxis + AbstractAxis.subAxis + AbstractAxis.toRelativeTime + Axis.asComponentTime + Axis.asdatetime + Axis.asDTGTime + Axis.asRelativeTime + Axis.clone + Axis.dump + Axis.getBoundsForDualGrid + Axis.getBounds + Axis.info + Axis.isVirtual + Axis.listall + Axis.mapIntervalExt + Axis.mapInterval + Axis.matchone + Axis.matchPattern + Axis.searchone + Axis.searchPattern + Axis.searchPredicate + Axis.subaxis + Axis.subAxis + Axis.toRelativeTime + FileAxis.asComponentTime + FileAxis.asdatetime + FileAxis.asDTGTime + FileAxis.asRelativeTime + FileAxis.clone + FileAxis.dump + FileAxis.getBoundsForDualGrid + FileAxis.info + FileAxis.isUnlimited + FileAxis.isVirtual + FileAxis.listall + FileAxis.mapIntervalExt + FileAxis.mapInterval + FileAxis.matchone + FileAxis.matchPattern + FileAxis.searchone + FileAxis.searchPattern + FileAxis.searchPredicate + FileAxis.subaxis + FileAxis.subAxis + FileAxis.toRelativeTime + FileVirtualAxis.asComponentTime + FileVirtualAxis.asdatetime + FileVirtualAxis.asDTGTime + FileVirtualAxis.asRelativeTime + FileVirtualAxis.clone + FileVirtualAxis.dump + FileVirtualAxis.getBoundsForDualGrid + FileVirtualAxis.info + FileVirtualAxis.isUnlimited + FileVirtualAxis.isVirtual + FileVirtualAxis.listall + FileVirtualAxis.mapIntervalExt + FileVirtualAxis.mapInterval + FileVirtualAxis.matchone + FileVirtualAxis.matchPattern + FileVirtualAxis.searchone + FileVirtualAxis.searchPattern + FileVirtualAxis.searchPredicate + FileVirtualAxis.subaxis + FileVirtualAxis.subAxis + FileVirtualAxis.toRelativeTime + TransientAxis.asComponentTime + TransientAxis.asdatetime + TransientAxis.asDTGTime + TransientAxis.asRelativeTime + TransientAxis.clone + TransientAxis.dump + TransientAxis.getBoundsForDualGrid + TransientAxis.info + TransientAxis.isVirtual + TransientAxis.listall + TransientAxis.mapIntervalExt + TransientAxis.mapInterval + TransientAxis.matchone + TransientAxis.matchPattern + TransientAxis.searchone + TransientAxis.searchPattern + TransientAxis.searchPredicate + TransientAxis.subaxis + TransientAxis.subAxis + TransientAxis.toRelativeTime + TransientVirtualAxis.asComponentTime + TransientVirtualAxis.asdatetime + TransientVirtualAxis.asDTGTime + TransientVirtualAxis.asRelativeTime + TransientVirtualAxis.clone + TransientVirtualAxis.dump + TransientVirtualAxis.getBoundsForDualGrid + TransientVirtualAxis.info + TransientVirtualAxis.isVirtual + TransientVirtualAxis.listall + TransientVirtualAxis.mapIntervalExt + TransientVirtualAxis.mapInterval + TransientVirtualAxis.matchone + TransientVirtualAxis.matchPattern + TransientVirtualAxis.searchone + TransientVirtualAxis.searchPattern + TransientVirtualAxis.searchPredicate + TransientVirtualAxis.setBounds + TransientVirtualAxis.subaxis + TransientVirtualAxis.subAxis + TransientVirtualAxis.toRelativeTime diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst index af8b0dd1..8b905daf 100644 --- a/docs/source/bindex.rst +++ b/docs/source/bindex.rst @@ -1,7 +1,13 @@ +.. _bindex: + bindex ====== -.. automodule:: cdms2.bindex - :members: +.. currentmodule:: cdms2.bindex +.. autosummary:: + :toctree: ./generated + bindexHorizontalGrid + intersectHorizontalGrid + diff --git a/docs/source/cache.rst b/docs/source/cache.rst index 41f2ad72..84e95ed5 100644 --- a/docs/source/cache.rst +++ b/docs/source/cache.rst @@ -1,3 +1,5 @@ +.. _cache: + cache ===== diff --git a/docs/source/cdmsNode.rst b/docs/source/cdmsNode.rst index ba0d72ae..7213f237 100644 --- a/docs/source/cdmsNode.rst +++ b/docs/source/cdmsNode.rst @@ -1,3 +1,5 @@ +.. _cdmsobj: + cdmsobj ======= diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst index ba0d72ae..7213f237 100644 --- a/docs/source/cdmsobj.rst +++ b/docs/source/cdmsobj.rst @@ -1,3 +1,5 @@ +.. _cdmsobj: + cdmsobj ======= diff --git a/docs/source/cdscan.rst b/docs/source/cdscan.rst index 8646afff..62f1d863 100644 --- a/docs/source/cdscan.rst +++ b/docs/source/cdscan.rst @@ -1,3 +1,5 @@ +.. _cdscan: + cdscan ====== diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst index 3ed5b1be..4ac7dd53 100644 --- a/docs/source/cdurllib.rst +++ b/docs/source/cdurllib.rst @@ -1,3 +1,5 @@ +.. _cdurllib: + cdurllib ======== diff --git a/docs/source/cdurlparse.rst b/docs/source/cdurlparse.rst index fe4fd974..55f07539 100644 --- a/docs/source/cdurlparse.rst +++ b/docs/source/cdurlparse.rst @@ -1,3 +1,5 @@ +.. _cdurlparse: + cdurlparse ========== diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index 1603fab5..60d12953 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -1,3 +1,5 @@ +.. _cdxmllib: + cdxmllib ======== diff --git a/docs/source/convention.rst b/docs/source/convention.rst index 92a8984f..6f079ae2 100644 --- a/docs/source/convention.rst +++ b/docs/source/convention.rst @@ -1,3 +1,5 @@ +.. _convention: + convention ========== diff --git a/docs/source/coord.rst b/docs/source/coord.rst index 40375359..a8ccc3d3 100644 --- a/docs/source/coord.rst +++ b/docs/source/coord.rst @@ -1,3 +1,5 @@ +.. _coord: + coord ===== diff --git a/docs/source/crossSection.rst b/docs/source/crossSection.rst index 97c5f7bb..e6b9de3d 100644 --- a/docs/source/crossSection.rst +++ b/docs/source/crossSection.rst @@ -1,3 +1,5 @@ +.. _regrid2: + regrid2- crossSection ===================== diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst index 20837af2..10268c59 100644 --- a/docs/source/cudsinterface.rst +++ b/docs/source/cudsinterface.rst @@ -1,3 +1,5 @@ +.. _cudsinterface: + cudsinterface ============= diff --git a/docs/source/database.rst b/docs/source/database.rst index 33736863..1c450df0 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -1,3 +1,5 @@ +.. _database: + database ======== diff --git a/docs/source/dataset .rst b/docs/source/dataset .rst deleted file mode 100644 index 66ed5f06..00000000 --- a/docs/source/dataset .rst +++ /dev/null @@ -1,7 +0,0 @@ -dataset -======= - -.. automodule:: cdms2.dataset - :members: - - diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst index 1f58c9ab..2efb436a 100644 --- a/docs/source/esmf.rst +++ b/docs/source/esmf.rst @@ -1,3 +1,5 @@ +.. _regrid2.esmf: + regrid2- esmf ============= diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index fc0ad421..a3941cb2 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -1,3 +1,5 @@ +.. _forecast: + forecast ======== diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst index 4ba233f3..ab0a0652 100644 --- a/docs/source/fvariable.rst +++ b/docs/source/fvariable.rst @@ -1,14 +1,65 @@ +.. _fvariable: + fvariable ========= -.. automodule:: cdms2.fvariable - :members: - -.. currentmodule:: numpy +.. currentmodule:: cdms2.fvariable .. autosummary:: :toctree: generated/ + FileVariable.astype + FileVariable.createattribute + FileVariable.crossSectionRegrid + FileVariable.decode + FileVariable.deleteattribute + FileVariable.dump + FileVariable.expertPaths + FileVariable.generateGridkey + FileVariable.generateRectGridkey + FileVariable.genMatch + FileVariable.getattribute + FileVariable.getAxisIds + FileVariable.getAxisIndex + FileVariable.getAxisListIndex + FileVariable.getAxisList + FileVariable.getConvention + FileVariable.getdimattribute + FileVariable.getFilePath + FileVariable.getForecastTime + FileVariable.getGridIndices + FileVariable.getLatitude + FileVariable.getLevel + FileVariable.getLongitude + FileVariable.getMissing + FileVariable.getOrder + FileVariable.getPartition + FileVariable.getRegion + FileVariable.getSlice + FileVariable.getTime + FileVariable.getValue + FileVariable.hasCellData + FileVariable.initDomain + FileVariable.isEncoded + FileVariable.listall + FileVariable.listattributes + FileVariable.listdimattributes + FileVariable.listdimnames + FileVariable.matchone + FileVariable.matchPattern + FileVariable.pressureRegrid + FileVariable.regrid + FileVariable.reorder + FileVariable.searchone + FileVariable.searchPattern + FileVariable.searchPredicate + FileVariable.select + FileVariable.setattribute + FileVariable.setMissing + FileVariable.showdim + FileVariable.size + FileVariable.specs2slices + FileVariable.typecode diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst index 90e1adca..6f81c80c 100644 --- a/docs/source/gengrid.rst +++ b/docs/source/gengrid.rst @@ -1,3 +1,5 @@ +.. _gengrid: + gengrid ======= diff --git a/docs/source/grid.rst b/docs/source/grid.rst index 0130759b..1b51b75e 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -1,3 +1,5 @@ +.. _grid: + grid ==== diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst index c64632c7..07ecedd7 100644 --- a/docs/source/gsRegrid.rst +++ b/docs/source/gsRegrid.rst @@ -1,3 +1,5 @@ +.. _regrid2-gsRegrid: + regrid2-gsRegrid ================ diff --git a/docs/source/gs_horizontal.rst b/docs/source/gs_horizontal.rst index 250f5357..d0e0439b 100644 --- a/docs/source/gs_horizontal.rst +++ b/docs/source/gs_horizontal.rst @@ -1,3 +1,5 @@ +.. _regrid2.gs_horizontal: + regrid2-gs_horizontal ===================== diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst index 2f84a891..8fe97cf4 100644 --- a/docs/source/hgrid.rst +++ b/docs/source/hgrid.rst @@ -1,3 +1,5 @@ +.. _hgrid: + hgrid ===== @@ -6,4 +8,4 @@ hgrid .. automodule:: cdms2.hgrid.AbstractHorizontalGrid - :members: \ No newline at end of file + :members: diff --git a/docs/source/horizontal.rst b/docs/source/horizontal.rst index 806572a3..8af38184 100644 --- a/docs/source/horizontal.rst +++ b/docs/source/horizontal.rst @@ -1,3 +1,5 @@ +.. _regrid2.horizontal: + regrid2-horizontal ================== diff --git a/docs/source/index.rst b/docs/source/index.rst index b5fe5bca..9734fb4f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,29 +21,6 @@ API -# AbstractAxis -# AbstractVariable -# bindex -# cache -# cdmsfile -# cdmsobj -# database -# dataset -# fvariable -# gengrid -# grid -# gsHost -# gsStaticVariable -# gsTimeVariable -# hgrid -# MV2 -# mvSphereMesh -# mvCdmsRegrid -# selectors -# sliceut -# tvariable - - Indices and tables ================== diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst index 70b0f35e..6fd6ecaa 100644 --- a/docs/source/mvBaseWriter.rst +++ b/docs/source/mvBaseWriter.rst @@ -1,3 +1,5 @@ +.. _mvBaseWriter: + mvBaseWriter ============ diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst index 5375a055..476abe7a 100644 --- a/docs/source/mvCdmsRegrid.rst +++ b/docs/source/mvCdmsRegrid.rst @@ -1,3 +1,5 @@ +.. _mvCdmsRegrid: + mvCdmsRegrid ============ diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst index 33d86c32..72170a0c 100644 --- a/docs/source/mvESMFRegrid.rst +++ b/docs/source/mvESMFRegrid.rst @@ -1,3 +1,5 @@ +.. _regrid2.mvESMFRegrid: + regrid2-mvESMFRegrid ==================== diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst index 24fa7077..e5c55212 100644 --- a/docs/source/mvGenericRegrid.rst +++ b/docs/source/mvGenericRegrid.rst @@ -1,3 +1,5 @@ +.. _regrid2.mvGenericRegrid: + regrid2-mvGenericRegrid ======================= diff --git a/docs/source/mvLibCFRegrid.rst b/docs/source/mvLibCFRegrid.rst index a886c78b..c5c4555f 100644 --- a/docs/source/mvLibCFRegrid.rst +++ b/docs/source/mvLibCFRegrid.rst @@ -1,3 +1,5 @@ +.. _regrid2.mvcdms2.FRegrid: + regrid2-mvcdms2.FRegrid ===================== diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst index 7c2374e6..401ba3ea 100644 --- a/docs/source/mvSphereMesh.rst +++ b/docs/source/mvSphereMesh.rst @@ -1,3 +1,5 @@ +.. _mvSphereMesh: + mvSphereMesh ============ diff --git a/docs/source/mvVTKSGWriter.rst b/docs/source/mvVTKSGWriter.rst index 1e13b950..fc41b0c7 100644 --- a/docs/source/mvVTKSGWriter.rst +++ b/docs/source/mvVTKSGWriter.rst @@ -1,3 +1,5 @@ +.. _mvVTKSGWriter: + mvVTKSGWriter ============= diff --git a/docs/source/mvVTKUGWriter.rst b/docs/source/mvVTKUGWriter.rst index 708ba9b9..6952831a 100644 --- a/docs/source/mvVTKUGWriter.rst +++ b/docs/source/mvVTKUGWriter.rst @@ -1,3 +1,5 @@ +.. _mvVTKUGWriter: + mvVTKUGWriter ============= diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst index e36bc344..442800a8 100644 --- a/docs/source/mvVsWriter.rst +++ b/docs/source/mvVsWriter.rst @@ -1,3 +1,5 @@ +.. _mvVsWriter: + mvVsWriter ========== diff --git a/docs/source/mySphereMesh.rst b/docs/source/mySphereMesh.rst index 70b0f35e..6fd6ecaa 100644 --- a/docs/source/mySphereMesh.rst +++ b/docs/source/mySphereMesh.rst @@ -1,3 +1,5 @@ +.. _mvBaseWriter: + mvBaseWriter ============ diff --git a/docs/source/pressure.rst b/docs/source/pressure.rst index cc9d1641..d04d999a 100644 --- a/docs/source/pressure.rst +++ b/docs/source/pressure.rst @@ -1,3 +1,5 @@ +.. _regrid2.pressure: + regrid2-pressure ================ diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst index 3840f053..54a44536 100644 --- a/docs/source/restApi.rst +++ b/docs/source/restApi.rst @@ -1,3 +1,5 @@ +.. _restApi: + restApi ======= diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst index 941a36c0..1e509a60 100644 --- a/docs/source/scrip.rst +++ b/docs/source/scrip.rst @@ -1,3 +1,5 @@ +.. _regrid2.scrip: + regrid2-scrip ============= diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst index 994f7ed3..df088133 100644 --- a/docs/source/selectors.rst +++ b/docs/source/selectors.rst @@ -1,3 +1,5 @@ +.. _selectors: + selectors ========= diff --git a/docs/source/slabinterface.rst b/docs/source/slabinterface.rst index dd0c8550..40865db7 100644 --- a/docs/source/slabinterface.rst +++ b/docs/source/slabinterface.rst @@ -1,3 +1,5 @@ +.. _slabinterface: + slabinterface ============= diff --git a/docs/source/tanya_2.rst b/docs/source/tanya_2.rst deleted file mode 100644 index 13ad6282..00000000 --- a/docs/source/tanya_2.rst +++ /dev/null @@ -1,7 +0,0 @@ -bindex -====== - -.. automodule:: cdms2. bindex - :members: - - diff --git a/docs/source/tvariable.rst b/docs/source/tvariable.rst index 9d2aed0b..8b0f7d13 100644 --- a/docs/source/tvariable.rst +++ b/docs/source/tvariable.rst @@ -1,5 +1,136 @@ +.. _tvariable: + tvariable ========= -.. automodule:: cdms2.tvariable - :members: +.. currentmodule:: cdms2.tvariable + +.. autosummary:: + :toctree: generated/ + + asVariable + createAxis + createRectGrid + createVariable + fromJSON + isVariable + sctype2char + TransientVariable.all + TransientVariable.anom + TransientVariable.any + TransientVariable.argmax + TransientVariable.argmin + TransientVariable.argsort + TransientVariable.asma + TransientVariable.astype + TransientVariable.clip + TransientVariable.clone + TransientVariable.compressed + TransientVariable.compress + TransientVariable.copyAxis + TransientVariable.copydimension + TransientVariable.copyDomain + TransientVariable.count + TransientVariable.createattribute + TransientVariable.crossSectionRegrid + TransientVariable.cumprod + TransientVariable.cumsum + TransientVariable.decode + TransientVariable.deleteattribute + TransientVariable.diagonal + TransientVariable.dot + TransientVariable.dump + TransientVariable.dumps + TransientVariable.exposeHalo + TransientVariable.fetchHaloData + TransientVariable.filled + TransientVariable.flatten + TransientVariable.freeHalo + TransientVariable.generateGridkey + TransientVariable.generateRectGridkey + TransientVariable.getattribute + TransientVariable.getAxisIds + TransientVariable.getAxisIndex + TransientVariable.getAxisListIndex + TransientVariable.getAxisList + TransientVariable.getConvention + TransientVariable.getdimattribute + TransientVariable.get_fill_value + TransientVariable.getForecastTime + TransientVariable.getGridIndices + TransientVariable.getHaloEllipsis + TransientVariable.get_imag + TransientVariable.getLatitude + TransientVariable.getLevel + TransientVariable.getLongitude + TransientVariable.getMissing + TransientVariable.getMPIRank + TransientVariable.getMPISize + TransientVariable.getOrder + TransientVariable.get_real + TransientVariable.getRegion + TransientVariable.getSlice + TransientVariable.getTileIndex + TransientVariable.getTime + TransientVariable.harden_mask + TransientVariable.hasCellData + TransientVariable.ids + TransientVariable.isEncoded + TransientVariable.listall + TransientVariable.listattributes + TransientVariable.listdimattributes + TransientVariable.listdimnames + TransientVariable.matchone + TransientVariable.matchPattern + TransientVariable.max + TransientVariable.mean + TransientVariable.mini + TransientVariable.min + TransientVariable.nonzero + TransientVariable.pressureRegrid + TransientVariable.prod + TransientVariable.product + TransientVariable.ptp + TransientVariable.put + TransientVariable.ravel + TransientVariable.regrid + TransientVariable.reorder + TransientVariable.repeat + TransientVariable.reshape + TransientVariable.resize + TransientVariable.round + TransientVariable.searchone + TransientVariable.searchPattern + TransientVariable.searchPredicate + TransientVariable.select + TransientVariable.setattribute + TransientVariable.setAxisList + TransientVariable.setAxis + TransientVariable.setdimattribute + TransientVariable.set_fill_value + TransientVariable.setMaskFromGridMask + TransientVariable.setMissing + TransientVariable.setMPIComm + TransientVariable.setTileIndex + TransientVariable.showdim + TransientVariable.shrink_mask + TransientVariable.soften_mask + TransientVariable.sort + TransientVariable.specs2slices + TransientVariable.std + TransientVariable.sum + TransientVariable.swapaxes + TransientVariable.take + TransientVariable.tobytes + TransientVariable.tofile + TransientVariable.toflex + TransientVariable.tolist + TransientVariable.torecords + TransientVariable.tostring + TransientVariable.toVisit + TransientVariable.trace + TransientVariable.transpose + TransientVariable.unshare_mask + TransientVariable.var + TransientVariable.view + diff --git a/docs/source/variable.rst b/docs/source/variable.rst index db52728d..94b1f385 100644 --- a/docs/source/variable.rst +++ b/docs/source/variable.rst @@ -1,7 +1,71 @@ +.. _variable: + variable ======== -.. automodule:: cdms2.variable - :members: +.. currentmodule:: cdms2.variable + +.. autosummary:: + :toctree: generated/ + + DatasetVariable.astype + DatasetVariable.createattribute + DatasetVariable.crossSectionRegrid + DatasetVariable.decode + DatasetVariable.deleteattribute + DatasetVariable.dump + DatasetVariable.expertPaths + DatasetVariable.generateGridkey + DatasetVariable.generateRectGridkey + DatasetVariable.genMatch + DatasetVariable.getattribute + DatasetVariable.getAxisIds + DatasetVariable.getAxisIndex + DatasetVariable.getAxisListIndex + DatasetVariable.getAxisList + DatasetVariable.getConvention + DatasetVariable.getdimattribute + DatasetVariable.getFilePath + DatasetVariable.getForecastTime + DatasetVariable.getGridIndices + DatasetVariable.getLatitude + DatasetVariable.getLevel + DatasetVariable.getLongitude + DatasetVariable.getMissing + DatasetVariable.getOrder + DatasetVariable.getPartition + DatasetVariable.getRegion + DatasetVariable.getSlice + DatasetVariable.getTime + DatasetVariable.getValue + DatasetVariable.hasCellData + DatasetVariable.initDomain + DatasetVariable.isEncoded + DatasetVariable.listall + DatasetVariable.listattributes + DatasetVariable.listdimattributes + DatasetVariable.listdimnames + DatasetVariable.matchone + DatasetVariable.matchPattern + DatasetVariable.pressureRegrid + DatasetVariable.regrid + DatasetVariable.reorder + DatasetVariable.searchone + DatasetVariable.searchPattern + DatasetVariable.searchPredicate + DatasetVariable.select + DatasetVariable.setattribute + DatasetVariable.setMissing + DatasetVariable.showdim + DatasetVariable.size + DatasetVariable.specs2slices + getPathFromTemplate + lenSlice + reverseSlice + sliceIntersect + slicePartition + timeindex + + From 16f6fdd5301f6576bc494b4e5dec2e9bb6a6e3da Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Wed, 13 Jun 2018 18:02:39 -0700 Subject: [PATCH 147/239] add generated files --- docs/generatedRST.py | 68 +++++++++++ docs/source/_static/copybutton.js | 63 ++++++++++ docs/source/dataset.rst | 112 ++++++++++++++++++ docs/source/generated/MV2.allclose.rst | 6 + docs/source/generated/MV2.allequal.rst | 6 + docs/source/generated/MV2.arange.rst | 6 + docs/source/generated/MV2.argsort.rst | 6 + docs/source/generated/MV2.arrayrange.rst | 6 + docs/source/generated/MV2.asVariable.rst | 6 + docs/source/generated/MV2.as_masked.rst | 6 + docs/source/generated/MV2.asarray.rst | 6 + docs/source/generated/MV2.average.rst | 6 + docs/source/generated/MV2.axisAllclose.rst | 6 + docs/source/generated/MV2.axisConcatenate.rst | 6 + docs/source/generated/MV2.axisTake.rst | 6 + docs/source/generated/MV2.choose.rst | 6 + docs/source/generated/MV2.commonAxes.rst | 6 + docs/source/generated/MV2.commonDomain.rst | 6 + docs/source/generated/MV2.commonGrid.rst | 6 + docs/source/generated/MV2.commonGrid1.rst | 6 + .../generated/MV2.common_fill_value.rst | 6 + docs/source/generated/MV2.compress.rst | 6 + docs/source/generated/MV2.concatenate.rst | 6 + docs/source/generated/MV2.count.rst | 6 + docs/source/generated/MV2.create_mask.rst | 6 + docs/source/generated/MV2.diagonal.rst | 6 + docs/source/generated/MV2.dot.rst | 6 + docs/source/generated/MV2.fill_value.rst | 6 + docs/source/generated/MV2.filled.rst | 6 + docs/source/generated/MV2.fromfunction.rst | 6 + .../generated/MV2.getNumericCompatibility.rst | 6 + docs/source/generated/MV2.get_print_limit.rst | 6 + .../source/generated/MV2.get_printoptions.rst | 6 + docs/source/generated/MV2.getmask.rst | 6 + docs/source/generated/MV2.getmaskarray.rst | 6 + docs/source/generated/MV2.indices.rst | 6 + docs/source/generated/MV2.innerproduct.rst | 6 + docs/source/generated/MV2.isMA.rst | 6 + docs/source/generated/MV2.isMaskedArray.rst | 6 + .../source/generated/MV2.isMaskedVariable.rst | 6 + docs/source/generated/MV2.is_floating.rst | 6 + docs/source/generated/MV2.is_integer.rst | 6 + docs/source/generated/MV2.is_mask.rst | 6 + docs/source/generated/MV2.is_masked.rst | 6 + docs/source/generated/MV2.isarray.rst | 6 + docs/source/generated/MV2.left_shift.rst | 6 + docs/source/generated/MV2.make_mask.rst | 6 + docs/source/generated/MV2.make_mask_none.rst | 6 + docs/source/generated/MV2.mask_or.rst | 6 + docs/source/generated/MV2.masked_array.rst | 6 + docs/source/generated/MV2.masked_equal.rst | 6 + docs/source/generated/MV2.masked_greater.rst | 6 + .../generated/MV2.masked_greater_equal.rst | 6 + docs/source/generated/MV2.masked_inside.rst | 6 + docs/source/generated/MV2.masked_less.rst | 6 + .../generated/MV2.masked_less_equal.rst | 6 + .../source/generated/MV2.masked_not_equal.rst | 6 + docs/source/generated/MV2.masked_object.rst | 6 + docs/source/generated/MV2.masked_outside.rst | 6 + docs/source/generated/MV2.masked_values.rst | 6 + docs/source/generated/MV2.masked_where.rst | 6 + docs/source/generated/MV2.max.rst | 6 + docs/source/generated/MV2.min.rst | 6 + docs/source/generated/MV2.ones.rst | 6 + docs/source/generated/MV2.outerproduct.rst | 6 + docs/source/generated/MV2.power.rst | 6 + docs/source/generated/MV2.product.rst | 6 + docs/source/generated/MV2.put.rst | 6 + docs/source/generated/MV2.putmask.rst | 6 + docs/source/generated/MV2.rank.rst | 6 + docs/source/generated/MV2.repeat.rst | 6 + docs/source/generated/MV2.reshape.rst | 6 + docs/source/generated/MV2.resize.rst | 6 + docs/source/generated/MV2.right_shift.rst | 6 + docs/source/generated/MV2.sctype2char.rst | 6 + .../generated/MV2.set_default_fill_value.rst | 6 + docs/source/generated/MV2.set_fill_value.rst | 6 + docs/source/generated/MV2.set_print_limit.rst | 6 + .../source/generated/MV2.set_printoptions.rst | 6 + docs/source/generated/MV2.shape.rst | 6 + docs/source/generated/MV2.size.rst | 6 + docs/source/generated/MV2.sort.rst | 6 + docs/source/generated/MV2.squeeze.rst | 6 + docs/source/generated/MV2.sum.rst | 6 + docs/source/generated/MV2.take.rst | 6 + docs/source/generated/MV2.transpose.rst | 6 + docs/source/generated/MV2.where.rst | 6 + docs/source/generated/MV2.zeros.rst | 6 + ...ms2.avariable.AbstractVariable.__abs__.rst | 6 + ...ms2.avariable.AbstractVariable.__add__.rst | 6 + ...2.avariable.AbstractVariable.__array__.rst | 6 + ...s2.avariable.AbstractVariable.__call__.rst | 6 + ...s2.avariable.AbstractVariable.__copy__.rst | 6 + ...ms2.avariable.AbstractVariable.__div__.rst | 6 + ...dms2.avariable.AbstractVariable.__eq__.rst | 6 + ...variable.AbstractVariable.__floordiv__.rst | 6 + ...dms2.avariable.AbstractVariable.__ge__.rst | 6 + ...avariable.AbstractVariable.__getitem__.rst | 6 + ...variable.AbstractVariable.__getslice__.rst | 6 + ...dms2.avariable.AbstractVariable.__gt__.rst | 6 + ...s2.avariable.AbstractVariable.__iadd__.rst | 6 + ...s2.avariable.AbstractVariable.__idiv__.rst | 6 + ...s2.avariable.AbstractVariable.__imul__.rst | 6 + ...s2.avariable.AbstractVariable.__init__.rst | 6 + ...s2.avariable.AbstractVariable.__isub__.rst | 6 + ...dms2.avariable.AbstractVariable.__le__.rst | 6 + ....avariable.AbstractVariable.__lshift__.rst | 6 + ...dms2.avariable.AbstractVariable.__lt__.rst | 6 + ...ms2.avariable.AbstractVariable.__mul__.rst | 6 + ...dms2.avariable.AbstractVariable.__ne__.rst | 6 + ...ms2.avariable.AbstractVariable.__neg__.rst | 6 + ...ms2.avariable.AbstractVariable.__pow__.rst | 6 + ...s2.avariable.AbstractVariable.__radd__.rst | 6 + ...s2.avariable.AbstractVariable.__rdiv__.rst | 6 + ...s2.avariable.AbstractVariable.__rmul__.rst | 6 + ....avariable.AbstractVariable.__rshift__.rst | 6 + ...s2.avariable.AbstractVariable.__rsub__.rst | 6 + ...s2.avariable.AbstractVariable.__sqrt__.rst | 6 + ...ms2.avariable.AbstractVariable.__sub__.rst | 6 + ...avariable.AbstractVariable.__truediv__.rst | 6 + ...variable.AbstractVariable._decodedType.rst | 6 + ...ariable.AbstractVariable._getinternals.rst | 6 + ...2.avariable.AbstractVariable._listatts.rst | 6 + ...riable.AbstractVariable._process_specs.rst | 6 + ...variable.AbstractVariable._returnArray.rst | 6 + ...s2.avariable.AbstractVariable._setatts.rst | 6 + ...ariable.AbstractVariable._setinternals.rst | 6 + ...avariable.AbstractVariable._setmissing.rst | 6 + ...ariable.AbstractVariable._single_specs.rst | 6 + ...avariable.AbstractVariable.assignValue.rst | 6 + ...dms2.avariable.AbstractVariable.astype.rst | 6 + ...iable.AbstractVariable.createattribute.rst | 6 + ...le.AbstractVariable.crossSectionRegrid.rst | 6 + ...dms2.avariable.AbstractVariable.decode.rst | 6 + ...iable.AbstractVariable.deleteattribute.rst | 6 + .../cdms2.avariable.AbstractVariable.dump.rst | 6 + ...avariable.AbstractVariable.expertSlice.rst | 6 + ...iable.AbstractVariable.generateGridkey.rst | 6 + ...e.AbstractVariable.generateRectGridkey.rst | 6 + ...ms2.avariable.AbstractVariable.getAxis.rst | 6 + ....avariable.AbstractVariable.getAxisIds.rst | 6 + ...variable.AbstractVariable.getAxisIndex.rst | 6 + ...avariable.AbstractVariable.getAxisList.rst | 6 + ...able.AbstractVariable.getAxisListIndex.rst | 6 + ...ariable.AbstractVariable.getConvention.rst | 6 + ...2.avariable.AbstractVariable.getDomain.rst | 6 + ...avariable.AbstractVariable.getForecast.rst | 6 + ...iable.AbstractVariable.getForecastTime.rst | 6 + ...ms2.avariable.AbstractVariable.getGrid.rst | 6 + ...riable.AbstractVariable.getGridIndices.rst | 6 + ...avariable.AbstractVariable.getLatitude.rst | 6 + ...s2.avariable.AbstractVariable.getLevel.rst | 6 + ...variable.AbstractVariable.getLongitude.rst | 6 + ....avariable.AbstractVariable.getMissing.rst | 6 + ...s2.avariable.AbstractVariable.getOrder.rst | 6 + ...2.avariable.AbstractVariable.getRegion.rst | 6 + ...s2.avariable.AbstractVariable.getSlice.rst | 6 + ...ms2.avariable.AbstractVariable.getTime.rst | 6 + ...s2.avariable.AbstractVariable.getValue.rst | 6 + ...variable.AbstractVariable.getattribute.rst | 6 + ...iable.AbstractVariable.getdimattribute.rst | 6 + ...avariable.AbstractVariable.hasCellData.rst | 6 + .../cdms2.avariable.AbstractVariable.info.rst | 6 + ....AbstractVariable.isAbstractCoordinate.rst | 6 + ...2.avariable.AbstractVariable.isEncoded.rst | 6 + ...ms2.avariable.AbstractVariable.listall.rst | 6 + ...riable.AbstractVariable.listattributes.rst | 6 + ...ble.AbstractVariable.listdimattributes.rst | 6 + ...variable.AbstractVariable.listdimnames.rst | 6 + ...variable.AbstractVariable.matchPattern.rst | 6 + ...s2.avariable.AbstractVariable.matchone.rst | 6 + ...riable.AbstractVariable.pressureRegrid.rst | 6 + .../cdms2.avariable.AbstractVariable.rank.rst | 6 + ...able.AbstractVariable.reg_specs2slices.rst | 6 + ...dms2.avariable.AbstractVariable.regrid.rst | 6 + ...ms2.avariable.AbstractVariable.reorder.rst | 6 + ...ariable.AbstractVariable.searchPattern.rst | 6 + ...iable.AbstractVariable.searchPredicate.rst | 6 + ...2.avariable.AbstractVariable.searchone.rst | 6 + ...dms2.avariable.AbstractVariable.select.rst | 6 + ...ms2.avariable.AbstractVariable.setGrid.rst | 6 + ....avariable.AbstractVariable.setMissing.rst | 6 + ...variable.AbstractVariable.setattribute.rst | 6 + ...ms2.avariable.AbstractVariable.showdim.rst | 6 + ...variable.AbstractVariable.specs2slices.rst | 6 + ...ms2.avariable.AbstractVariable.squeeze.rst | 6 + ...2.avariable.AbstractVariable.subRegion.rst | 6 + ...s2.avariable.AbstractVariable.subSlice.rst | 6 + ...s2.avariable.AbstractVariable.typecode.rst | 6 + .../cdms2.avariable._getCoordList.rst | 6 + .../cdms2.avariable.axisMatchAxis.rst | 6 + .../cdms2.avariable.axisMatchIndex.rst | 6 + .../generated/cdms2.avariable.axisMatches.rst | 6 + .../cdms2.avariable.getBoundList.rst | 6 + .../cdms2.avariable.getMinHorizontalMask.rst | 6 + ...dms2.avariable.getNumericCompatibility.rst | 6 + .../cdms2.avariable.guessPeriodicity.rst | 6 + .../generated/cdms2.avariable.order2index.rst | 6 + .../generated/cdms2.avariable.orderparse.rst | 6 + ...dms2.avariable.setNumericCompatibility.rst | 6 + .../generated/cdms2.avariable.splitSlice.rst | 6 + .../cdms2.avariable.splitSliceExt.rst | 6 + .../cdms2.axis.AbstractAxis._time2value.rst | 6 + ...dms2.axis.AbstractAxis.asComponentTime.rst | 6 + .../cdms2.axis.AbstractAxis.asDTGTime.rst | 6 + ...cdms2.axis.AbstractAxis.asRelativeTime.rst | 6 + .../cdms2.axis.AbstractAxis.asdatetime.rst | 6 + .../cdms2.axis.AbstractAxis.clone.rst | 6 + .../cdms2.axis.AbstractAxis.dump.rst | 6 + .../cdms2.axis.AbstractAxis.getBounds.rst | 6 + ...axis.AbstractAxis.getBoundsForDualGrid.rst | 6 + ...s2.axis.AbstractAxis.getExplicitBounds.rst | 6 + .../cdms2.axis.AbstractAxis.info.rst | 6 + .../cdms2.axis.AbstractAxis.isVirtual.rst | 6 + .../cdms2.axis.AbstractAxis.listall.rst | 6 + .../cdms2.axis.AbstractAxis.mapInterval.rst | 6 + ...cdms2.axis.AbstractAxis.mapIntervalExt.rst | 6 + .../cdms2.axis.AbstractAxis.matchPattern.rst | 6 + .../cdms2.axis.AbstractAxis.matchone.rst | 6 + .../cdms2.axis.AbstractAxis.searchPattern.rst | 6 + ...dms2.axis.AbstractAxis.searchPredicate.rst | 6 + .../cdms2.axis.AbstractAxis.searchone.rst | 6 + .../cdms2.axis.AbstractAxis.subAxis.rst | 6 + .../cdms2.axis.AbstractAxis.subaxis.rst | 6 + ...cdms2.axis.AbstractAxis.toRelativeTime.rst | 6 + .../generated/cdms2.axis.Axis._time2value.rst | 6 + .../cdms2.axis.Axis.asComponentTime.rst | 6 + .../generated/cdms2.axis.Axis.asDTGTime.rst | 6 + .../cdms2.axis.Axis.asRelativeTime.rst | 6 + .../generated/cdms2.axis.Axis.asdatetime.rst | 6 + .../generated/cdms2.axis.Axis.clone.rst | 6 + .../source/generated/cdms2.axis.Axis.dump.rst | 6 + .../generated/cdms2.axis.Axis.getBounds.rst | 6 + .../cdms2.axis.Axis.getBoundsForDualGrid.rst | 6 + .../source/generated/cdms2.axis.Axis.info.rst | 6 + .../generated/cdms2.axis.Axis.isVirtual.rst | 6 + .../generated/cdms2.axis.Axis.listall.rst | 6 + .../generated/cdms2.axis.Axis.mapInterval.rst | 6 + .../cdms2.axis.Axis.mapIntervalExt.rst | 6 + .../cdms2.axis.Axis.matchPattern.rst | 6 + .../generated/cdms2.axis.Axis.matchone.rst | 6 + .../cdms2.axis.Axis.searchPattern.rst | 6 + .../cdms2.axis.Axis.searchPredicate.rst | 6 + .../generated/cdms2.axis.Axis.searchone.rst | 6 + .../generated/cdms2.axis.Axis.subAxis.rst | 6 + .../generated/cdms2.axis.Axis.subaxis.rst | 6 + .../cdms2.axis.Axis.toRelativeTime.rst | 6 + .../cdms2.axis.FileAxis._time2value.rst | 6 + .../cdms2.axis.FileAxis.asComponentTime.rst | 6 + .../cdms2.axis.FileAxis.asDTGTime.rst | 6 + .../cdms2.axis.FileAxis.asRelativeTime.rst | 6 + .../cdms2.axis.FileAxis.asdatetime.rst | 6 + .../generated/cdms2.axis.FileAxis.clone.rst | 6 + .../generated/cdms2.axis.FileAxis.dump.rst | 6 + ...ms2.axis.FileAxis.getBoundsForDualGrid.rst | 6 + .../generated/cdms2.axis.FileAxis.info.rst | 6 + .../cdms2.axis.FileAxis.isUnlimited.rst | 6 + .../cdms2.axis.FileAxis.isVirtual.rst | 6 + .../generated/cdms2.axis.FileAxis.listall.rst | 6 + .../cdms2.axis.FileAxis.mapInterval.rst | 6 + .../cdms2.axis.FileAxis.mapIntervalExt.rst | 6 + .../cdms2.axis.FileAxis.matchPattern.rst | 6 + .../cdms2.axis.FileAxis.matchone.rst | 6 + .../cdms2.axis.FileAxis.searchPattern.rst | 6 + .../cdms2.axis.FileAxis.searchPredicate.rst | 6 + .../cdms2.axis.FileAxis.searchone.rst | 6 + .../generated/cdms2.axis.FileAxis.subAxis.rst | 6 + .../generated/cdms2.axis.FileAxis.subaxis.rst | 6 + .../cdms2.axis.FileAxis.toRelativeTime.rst | 6 + ...cdms2.axis.FileVirtualAxis._time2value.rst | 6 + ...2.axis.FileVirtualAxis.asComponentTime.rst | 6 + .../cdms2.axis.FileVirtualAxis.asDTGTime.rst | 6 + ...s2.axis.FileVirtualAxis.asRelativeTime.rst | 6 + .../cdms2.axis.FileVirtualAxis.asdatetime.rst | 6 + .../cdms2.axis.FileVirtualAxis.clone.rst | 6 + .../cdms2.axis.FileVirtualAxis.dump.rst | 6 + ...s.FileVirtualAxis.getBoundsForDualGrid.rst | 6 + .../cdms2.axis.FileVirtualAxis.info.rst | 6 + ...cdms2.axis.FileVirtualAxis.isUnlimited.rst | 6 + .../cdms2.axis.FileVirtualAxis.isVirtual.rst | 6 + .../cdms2.axis.FileVirtualAxis.listall.rst | 6 + ...cdms2.axis.FileVirtualAxis.mapInterval.rst | 6 + ...s2.axis.FileVirtualAxis.mapIntervalExt.rst | 6 + ...dms2.axis.FileVirtualAxis.matchPattern.rst | 6 + .../cdms2.axis.FileVirtualAxis.matchone.rst | 6 + ...ms2.axis.FileVirtualAxis.searchPattern.rst | 6 + ...2.axis.FileVirtualAxis.searchPredicate.rst | 6 + .../cdms2.axis.FileVirtualAxis.searchone.rst | 6 + .../cdms2.axis.FileVirtualAxis.subAxis.rst | 6 + .../cdms2.axis.FileVirtualAxis.subaxis.rst | 6 + ...s2.axis.FileVirtualAxis.toRelativeTime.rst | 6 + .../cdms2.axis.TransientAxis.__init__.rst | 6 + .../cdms2.axis.TransientAxis._time2value.rst | 6 + ...ms2.axis.TransientAxis.asComponentTime.rst | 6 + .../cdms2.axis.TransientAxis.asDTGTime.rst | 6 + ...dms2.axis.TransientAxis.asRelativeTime.rst | 6 + .../cdms2.axis.TransientAxis.asdatetime.rst | 6 + .../cdms2.axis.TransientAxis.clone.rst | 6 + .../cdms2.axis.TransientAxis.dump.rst | 6 + ...xis.TransientAxis.getBoundsForDualGrid.rst | 6 + .../cdms2.axis.TransientAxis.info.rst | 6 + .../cdms2.axis.TransientAxis.isVirtual.rst | 6 + .../cdms2.axis.TransientAxis.listall.rst | 6 + .../cdms2.axis.TransientAxis.mapInterval.rst | 6 + ...dms2.axis.TransientAxis.mapIntervalExt.rst | 6 + .../cdms2.axis.TransientAxis.matchPattern.rst | 6 + .../cdms2.axis.TransientAxis.matchone.rst | 6 + ...cdms2.axis.TransientAxis.searchPattern.rst | 6 + ...ms2.axis.TransientAxis.searchPredicate.rst | 6 + .../cdms2.axis.TransientAxis.searchone.rst | 6 + .../cdms2.axis.TransientAxis.subAxis.rst | 6 + .../cdms2.axis.TransientAxis.subaxis.rst | 6 + ...dms2.axis.TransientAxis.toRelativeTime.rst | 6 + ....axis.TransientVirtualAxis._time2value.rst | 6 + ...s.TransientVirtualAxis.asComponentTime.rst | 6 + ...s2.axis.TransientVirtualAxis.asDTGTime.rst | 6 + ...is.TransientVirtualAxis.asRelativeTime.rst | 6 + ...2.axis.TransientVirtualAxis.asdatetime.rst | 6 + .../cdms2.axis.TransientVirtualAxis.clone.rst | 6 + .../cdms2.axis.TransientVirtualAxis.dump.rst | 6 + ...nsientVirtualAxis.getBoundsForDualGrid.rst | 6 + .../cdms2.axis.TransientVirtualAxis.info.rst | 6 + ...s2.axis.TransientVirtualAxis.isVirtual.rst | 6 + ...dms2.axis.TransientVirtualAxis.listall.rst | 6 + ....axis.TransientVirtualAxis.mapInterval.rst | 6 + ...is.TransientVirtualAxis.mapIntervalExt.rst | 6 + ...axis.TransientVirtualAxis.matchPattern.rst | 6 + ...ms2.axis.TransientVirtualAxis.matchone.rst | 6 + ...xis.TransientVirtualAxis.searchPattern.rst | 6 + ...s.TransientVirtualAxis.searchPredicate.rst | 6 + ...s2.axis.TransientVirtualAxis.searchone.rst | 6 + ...s2.axis.TransientVirtualAxis.setBounds.rst | 6 + ...dms2.axis.TransientVirtualAxis.subAxis.rst | 6 + ...dms2.axis.TransientVirtualAxis.subaxis.rst | 6 + ...is.TransientVirtualAxis.toRelativeTime.rst | 6 + docs/source/generated/cdms2.axis.allclose.rst | 6 + .../generated/cdms2.axis.axisMatchAxis.rst | 6 + .../generated/cdms2.axis.axisMatchIndex.rst | 6 + .../generated/cdms2.axis.axisMatches.rst | 6 + .../generated/cdms2.axis.concatenate.rst | 6 + .../generated/cdms2.axis.createAxis.rst | 6 + .../cdms2.axis.createEqualAreaAxis.rst | 6 + .../cdms2.axis.createGaussianAxis.rst | 6 + .../cdms2.axis.createUniformLatitudeAxis.rst | 6 + .../cdms2.axis.createUniformLongitudeAxis.rst | 6 + .../generated/cdms2.axis.getAutoBounds.rst | 6 + .../generated/cdms2.axis.isOverlapVector.rst | 6 + .../generated/cdms2.axis.isSubsetVector.rst | 6 + .../generated/cdms2.axis.lookupArray.rst | 6 + .../generated/cdms2.axis.mapLinearExt.rst | 6 + .../cdms2.axis.mapLinearIntersection.rst | 6 + .../generated/cdms2.axis.reverseSlice.rst | 6 + .../generated/cdms2.axis.setAutoBounds.rst | 6 + .../generated/cdms2.axis.splitSlice.rst | 6 + .../generated/cdms2.axis.splitSliceExt.rst | 6 + docs/source/generated/cdms2.axis.take.rst | 6 + .../cdms2.bindex.bindexHorizontalGrid.rst | 6 + .../cdms2.bindex.intersectHorizontalGrid.rst | 6 + .../cdms2.dataset.CdmsFile.__call__.rst | 6 + .../cdms2.dataset.CdmsFile.__getitem__.rst | 6 + .../generated/cdms2.dataset.CdmsFile._v.rst | 6 + .../cdms2.dataset.CdmsFile.cleardefault.rst | 6 + .../cdms2.dataset.CdmsFile.copyAxis.rst | 6 + .../cdms2.dataset.CdmsFile.copyGrid.rst | 6 + .../cdms2.dataset.CdmsFile.createAxis.rst | 6 + .../cdms2.dataset.CdmsFile.createRectGrid.rst | 6 + .../cdms2.dataset.CdmsFile.createVariable.rst | 6 + ...s2.dataset.CdmsFile.createVariableCopy.rst | 6 + ...ms2.dataset.CdmsFile.createVirtualAxis.rst | 6 + ...dms2.dataset.CdmsFile.default_variable.rst | 6 + .../cdms2.dataset.CdmsFile.dimensionarray.rst | 6 + ...cdms2.dataset.CdmsFile.dimensionobject.rst | 6 + .../generated/cdms2.dataset.CdmsFile.dump.rst | 6 + .../cdms2.dataset.CdmsFile.getAxis.rst | 6 + .../cdms2.dataset.CdmsFile.getBoundsAxis.rst | 6 + .../cdms2.dataset.CdmsFile.getGrid.rst | 6 + .../cdms2.dataset.CdmsFile.getVariable.rst | 6 + .../cdms2.dataset.CdmsFile.getVariables.rst | 6 + .../cdms2.dataset.CdmsFile.getattribute.rst | 6 + ...ms2.dataset.CdmsFile.getdimensionunits.rst | 6 + .../cdms2.dataset.CdmsFile.getglobal.rst | 6 + .../cdms2.dataset.CdmsFile.getslab.rst | 6 + .../cdms2.dataset.CdmsFile.listall.rst | 6 + .../cdms2.dataset.CdmsFile.listattribute.rst | 6 + .../cdms2.dataset.CdmsFile.listdimension.rst | 6 + .../cdms2.dataset.CdmsFile.listglobal.rst | 6 + .../cdms2.dataset.CdmsFile.listvariable.rst | 6 + .../cdms2.dataset.CdmsFile.listvariables.rst | 6 + .../cdms2.dataset.CdmsFile.matchPattern.rst | 6 + .../cdms2.dataset.CdmsFile.matchone.rst | 6 + .../cdms2.dataset.CdmsFile.readScripGrid.rst | 6 + .../cdms2.dataset.CdmsFile.searchPattern.rst | 6 + ...cdms2.dataset.CdmsFile.searchPredicate.rst | 6 + .../cdms2.dataset.CdmsFile.searchone.rst | 6 + .../cdms2.dataset.CdmsFile.showall.rst | 6 + .../cdms2.dataset.CdmsFile.showattribute.rst | 6 + .../cdms2.dataset.CdmsFile.showdimension.rst | 6 + .../cdms2.dataset.CdmsFile.showglobal.rst | 6 + .../cdms2.dataset.CdmsFile.showvariable.rst | 6 + .../generated/cdms2.dataset.CdmsFile.sync.rst | 6 + .../cdms2.dataset.CdmsFile.write.rst | 6 + ...ms2.dataset.CdmsFile.write_it_yourself.rst | 6 + .../cdms2.dataset.Dataset.__call__.rst | 6 + .../cdms2.dataset.Dataset.__getitem__.rst | 6 + .../generated/cdms2.dataset.Dataset._v.rst | 6 + .../cdms2.dataset.Dataset.cleardefault.rst | 6 + ...cdms2.dataset.Dataset.default_variable.rst | 6 + .../cdms2.dataset.Dataset.dimensionarray.rst | 6 + .../cdms2.dataset.Dataset.dimensionobject.rst | 6 + .../generated/cdms2.dataset.Dataset.dump.rst | 6 + .../cdms2.dataset.Dataset.getAxis.rst | 6 + .../cdms2.dataset.Dataset.getConvention.rst | 6 + .../cdms2.dataset.Dataset.getGrid.rst | 6 + ...dataset.Dataset.getLogicalCollectionDN.rst | 6 + .../cdms2.dataset.Dataset.getVariable.rst | 6 + .../cdms2.dataset.Dataset.getVariables.rst | 6 + .../cdms2.dataset.Dataset.getattribute.rst | 6 + ...dms2.dataset.Dataset.getdimensionunits.rst | 6 + .../cdms2.dataset.Dataset.getglobal.rst | 6 + .../cdms2.dataset.Dataset.getslab.rst | 6 + .../cdms2.dataset.Dataset.listall.rst | 6 + .../cdms2.dataset.Dataset.listattribute.rst | 6 + .../cdms2.dataset.Dataset.listdimension.rst | 6 + .../cdms2.dataset.Dataset.listglobal.rst | 6 + .../cdms2.dataset.Dataset.listvariable.rst | 6 + .../cdms2.dataset.Dataset.listvariables.rst | 6 + .../cdms2.dataset.Dataset.matchone.rst | 6 + .../cdms2.dataset.Dataset.readScripGrid.rst | 6 + .../cdms2.dataset.Dataset.searchone.rst | 6 + .../cdms2.dataset.Dataset.showall.rst | 6 + .../cdms2.dataset.Dataset.showattribute.rst | 6 + .../cdms2.dataset.Dataset.showdimension.rst | 6 + .../cdms2.dataset.Dataset.showglobal.rst | 6 + .../cdms2.dataset.Dataset.showvariable.rst | 6 + .../generated/cdms2.dataset.asVariable.rst | 6 + .../generated/cdms2.dataset.createDataset.rst | 6 + .../generated/cdms2.dataset.getMpiRank.rst | 6 + .../generated/cdms2.dataset.getMpiSize.rst | 6 + .../cdms2.dataset.getNetcdf4Flag.rst | 6 + .../cdms2.dataset.getNetcdfClassicFlag.rst | 6 + .../cdms2.dataset.getNetcdfDeflateFlag.rst | 6 + ...dms2.dataset.getNetcdfDeflateLevelFlag.rst | 6 + .../cdms2.dataset.getNetcdfShuffleFlag.rst | 6 + ...2.dataset.getNetcdfUseNCSwitchModeFlag.rst | 6 + ...cdms2.dataset.getNetcdfUseParallelFlag.rst | 6 + .../cdms2.dataset.isOverlapVector.rst | 6 + docs/source/generated/cdms2.dataset.load.rst | 6 + .../generated/cdms2.dataset.loadURI.rst | 6 + .../generated/cdms2.dataset.openDataset.rst | 6 + .../generated/cdms2.dataset.parseFileMap.rst | 6 + .../cdms2.dataset.parseIndexList.rst | 6 + .../generated/cdms2.dataset.parseName.rst | 6 + .../generated/cdms2.dataset.parseVarMap.rst | 6 + .../generated/cdms2.dataset.parselist.rst | 6 + .../cdms2.dataset.setCompressionWarnings.rst | 6 + .../cdms2.dataset.setNetcdf4Flag.rst | 6 + .../cdms2.dataset.setNetcdfClassicFlag.rst | 6 + .../cdms2.dataset.setNetcdfDeflateFlag.rst | 6 + ...dms2.dataset.setNetcdfDeflateLevelFlag.rst | 6 + .../cdms2.dataset.setNetcdfShuffleFlag.rst | 6 + ...2.dataset.setNetcdfUseNCSwitchModeFlag.rst | 6 + ...cdms2.dataset.setNetcdfUseParallelFlag.rst | 6 + .../generated/cdms2.dataset.urlparse.rst | 6 + .../generated/cdms2.dataset.urlunparse.rst | 6 + .../generated/cdms2.dataset.useNetcdf3.rst | 6 + .../cdms2.fvariable.FileVariable.__call__.rst | 6 + .../cdms2.fvariable.FileVariable.__iadd__.rst | 6 + .../cdms2.fvariable.FileVariable.__idiv__.rst | 6 + .../cdms2.fvariable.FileVariable.__imul__.rst | 6 + .../cdms2.fvariable.FileVariable.__isub__.rst | 6 + .../cdms2.fvariable.FileVariable.__len__.rst | 6 + ...s2.fvariable.FileVariable._decodedType.rst | 6 + ....fvariable.FileVariable._process_specs.rst | 6 + ...2.fvariable.FileVariable._single_specs.rst | 6 + .../cdms2.fvariable.FileVariable.astype.rst | 6 + ...fvariable.FileVariable.createattribute.rst | 6 + ...riable.FileVariable.crossSectionRegrid.rst | 6 + .../cdms2.fvariable.FileVariable.decode.rst | 6 + ...fvariable.FileVariable.deleteattribute.rst | 6 + .../cdms2.fvariable.FileVariable.dump.rst | 6 + ...ms2.fvariable.FileVariable.expertPaths.rst | 6 + .../cdms2.fvariable.FileVariable.genMatch.rst | 6 + ...fvariable.FileVariable.generateGridkey.rst | 6 + ...iable.FileVariable.generateRectGridkey.rst | 6 + ...dms2.fvariable.FileVariable.getAxisIds.rst | 6 + ...s2.fvariable.FileVariable.getAxisIndex.rst | 6 + ...ms2.fvariable.FileVariable.getAxisList.rst | 6 + ...variable.FileVariable.getAxisListIndex.rst | 6 + ...2.fvariable.FileVariable.getConvention.rst | 6 + ...ms2.fvariable.FileVariable.getFilePath.rst | 6 + ...fvariable.FileVariable.getForecastTime.rst | 6 + ....fvariable.FileVariable.getGridIndices.rst | 6 + ...ms2.fvariable.FileVariable.getLatitude.rst | 6 + .../cdms2.fvariable.FileVariable.getLevel.rst | 6 + ...s2.fvariable.FileVariable.getLongitude.rst | 6 + ...dms2.fvariable.FileVariable.getMissing.rst | 6 + .../cdms2.fvariable.FileVariable.getOrder.rst | 6 + ...s2.fvariable.FileVariable.getPartition.rst | 6 + ...cdms2.fvariable.FileVariable.getRegion.rst | 6 + .../cdms2.fvariable.FileVariable.getSlice.rst | 6 + .../cdms2.fvariable.FileVariable.getTime.rst | 6 + .../cdms2.fvariable.FileVariable.getValue.rst | 6 + ...s2.fvariable.FileVariable.getattribute.rst | 6 + ...fvariable.FileVariable.getdimattribute.rst | 6 + ...ms2.fvariable.FileVariable.hasCellData.rst | 6 + ...dms2.fvariable.FileVariable.initDomain.rst | 6 + ...cdms2.fvariable.FileVariable.isEncoded.rst | 6 + .../cdms2.fvariable.FileVariable.listall.rst | 6 + ....fvariable.FileVariable.listattributes.rst | 6 + ...ariable.FileVariable.listdimattributes.rst | 6 + ...s2.fvariable.FileVariable.listdimnames.rst | 6 + ...s2.fvariable.FileVariable.matchPattern.rst | 6 + .../cdms2.fvariable.FileVariable.matchone.rst | 6 + ....fvariable.FileVariable.pressureRegrid.rst | 6 + .../cdms2.fvariable.FileVariable.regrid.rst | 6 + .../cdms2.fvariable.FileVariable.reorder.rst | 6 + ...2.fvariable.FileVariable.searchPattern.rst | 6 + ...fvariable.FileVariable.searchPredicate.rst | 6 + ...cdms2.fvariable.FileVariable.searchone.rst | 6 + .../cdms2.fvariable.FileVariable.select.rst | 6 + ...dms2.fvariable.FileVariable.setMissing.rst | 6 + ...s2.fvariable.FileVariable.setattribute.rst | 6 + .../cdms2.fvariable.FileVariable.showdim.rst | 6 + .../cdms2.fvariable.FileVariable.size.rst | 6 + ...s2.fvariable.FileVariable.specs2slices.rst | 6 + .../cdms2.fvariable.FileVariable.typecode.rst | 6 + ...ariable._TransientVariable__getMPIType.rst | 6 + ...ntVariable._TransientVariable__getSlab.rst | 6 + ...iable.TransientVariable.__array_wrap__.rst | 6 + ...2.tvariable.TransientVariable.__call__.rst | 6 + ....tvariable.TransientVariable.__float__.rst | 6 + ...ariable.TransientVariable.__getstate__.rst | 6 + ...2.tvariable.TransientVariable.__iadd__.rst | 6 + ...2.tvariable.TransientVariable.__idiv__.rst | 6 + ...riable.TransientVariable.__ifloordiv__.rst | 6 + ...2.tvariable.TransientVariable.__imul__.rst | 6 + ...2.tvariable.TransientVariable.__init__.rst | 6 + ...s2.tvariable.TransientVariable.__int__.rst | 6 + ...2.tvariable.TransientVariable.__ipow__.rst | 6 + ...2.tvariable.TransientVariable.__isub__.rst | 6 + ...ariable.TransientVariable.__itruediv__.rst | 6 + ...s2.tvariable.TransientVariable.__len__.rst | 6 + ...2.tvariable.TransientVariable.__long__.rst | 6 + ...s2.tvariable.TransientVariable.__new__.rst | 6 + ...tvariable.TransientVariable.__reduce__.rst | 6 + ...riable.TransientVariable.__rfloordiv__.rst | 6 + ...2.tvariable.TransientVariable.__rpow__.rst | 6 + ...ariable.TransientVariable.__rtruediv__.rst | 6 + ...variable.TransientVariable.__setitem__.rst | 6 + ...variable.TransientVariable.__setmask__.rst | 6 + ...ariable.TransientVariable.__setstate__.rst | 6 + ...variable.TransientVariable._comparison.rst | 6 + ...ariable.TransientVariable._decodedType.rst | 6 + ....tvariable.TransientVariable._get_data.rst | 6 + ....tvariable.TransientVariable._get_flat.rst | 6 + ....tvariable.TransientVariable._get_mask.rst | 6 + ...able.TransientVariable._get_recordmask.rst | 6 + ...TransientVariable._insert_masked_print.rst | 6 + ...iable.TransientVariable._process_specs.rst | 6 + ....tvariable.TransientVariable._set_flat.rst | 6 + ....tvariable.TransientVariable._set_mask.rst | 6 + ...able.TransientVariable._set_recordmask.rst | 6 + ...riable.TransientVariable._single_specs.rst | 6 + .../cdms2.tvariable.TransientVariable.all.rst | 6 + ...cdms2.tvariable.TransientVariable.anom.rst | 6 + .../cdms2.tvariable.TransientVariable.any.rst | 6 + ...ms2.tvariable.TransientVariable.argmax.rst | 6 + ...ms2.tvariable.TransientVariable.argmin.rst | 6 + ...s2.tvariable.TransientVariable.argsort.rst | 6 + ...cdms2.tvariable.TransientVariable.asma.rst | 6 + ...ms2.tvariable.TransientVariable.astype.rst | 6 + ...cdms2.tvariable.TransientVariable.clip.rst | 6 + ...dms2.tvariable.TransientVariable.clone.rst | 6 + ...2.tvariable.TransientVariable.compress.rst | 6 + ...tvariable.TransientVariable.compressed.rst | 6 + ...2.tvariable.TransientVariable.copyAxis.rst | 6 + ...tvariable.TransientVariable.copyDomain.rst | 6 + ...riable.TransientVariable.copydimension.rst | 6 + ...dms2.tvariable.TransientVariable.count.rst | 6 + ...able.TransientVariable.createattribute.rst | 6 + ...e.TransientVariable.crossSectionRegrid.rst | 6 + ...s2.tvariable.TransientVariable.cumprod.rst | 6 + ...ms2.tvariable.TransientVariable.cumsum.rst | 6 + ...ms2.tvariable.TransientVariable.decode.rst | 6 + ...able.TransientVariable.deleteattribute.rst | 6 + ...2.tvariable.TransientVariable.diagonal.rst | 6 + .../cdms2.tvariable.TransientVariable.dot.rst | 6 + ...cdms2.tvariable.TransientVariable.dump.rst | 6 + ...dms2.tvariable.TransientVariable.dumps.rst | 6 + ...tvariable.TransientVariable.exposeHalo.rst | 6 + ...riable.TransientVariable.fetchHaloData.rst | 6 + ...ms2.tvariable.TransientVariable.filled.rst | 6 + ...s2.tvariable.TransientVariable.flatten.rst | 6 + ...2.tvariable.TransientVariable.freeHalo.rst | 6 + ...able.TransientVariable.generateGridkey.rst | 6 + ....TransientVariable.generateRectGridkey.rst | 6 + ...tvariable.TransientVariable.getAxisIds.rst | 6 + ...ariable.TransientVariable.getAxisIndex.rst | 6 + ...variable.TransientVariable.getAxisList.rst | 6 + ...ble.TransientVariable.getAxisListIndex.rst | 6 + ...riable.TransientVariable.getConvention.rst | 6 + ...able.TransientVariable.getForecastTime.rst | 6 + ...iable.TransientVariable.getGridIndices.rst | 6 + ...able.TransientVariable.getHaloEllipsis.rst | 6 + ...variable.TransientVariable.getLatitude.rst | 6 + ...2.tvariable.TransientVariable.getLevel.rst | 6 + ...ariable.TransientVariable.getLongitude.rst | 6 + ...tvariable.TransientVariable.getMPIRank.rst | 6 + ...tvariable.TransientVariable.getMPISize.rst | 6 + ...tvariable.TransientVariable.getMissing.rst | 6 + ...2.tvariable.TransientVariable.getOrder.rst | 6 + ....tvariable.TransientVariable.getRegion.rst | 6 + ...2.tvariable.TransientVariable.getSlice.rst | 6 + ...ariable.TransientVariable.getTileIndex.rst | 6 + ...s2.tvariable.TransientVariable.getTime.rst | 6 + ...iable.TransientVariable.get_fill_value.rst | 6 + ...2.tvariable.TransientVariable.get_imag.rst | 6 + ...2.tvariable.TransientVariable.get_real.rst | 6 + ...ariable.TransientVariable.getattribute.rst | 6 + ...able.TransientVariable.getdimattribute.rst | 6 + ...variable.TransientVariable.harden_mask.rst | 6 + ...variable.TransientVariable.hasCellData.rst | 6 + .../cdms2.tvariable.TransientVariable.ids.rst | 6 + ....tvariable.TransientVariable.isEncoded.rst | 6 + ...s2.tvariable.TransientVariable.listall.rst | 6 + ...iable.TransientVariable.listattributes.rst | 6 + ...le.TransientVariable.listdimattributes.rst | 6 + ...ariable.TransientVariable.listdimnames.rst | 6 + ...ariable.TransientVariable.matchPattern.rst | 6 + ...2.tvariable.TransientVariable.matchone.rst | 6 + .../cdms2.tvariable.TransientVariable.max.rst | 6 + ...cdms2.tvariable.TransientVariable.mean.rst | 6 + .../cdms2.tvariable.TransientVariable.min.rst | 6 + ...cdms2.tvariable.TransientVariable.mini.rst | 6 + ...s2.tvariable.TransientVariable.nonzero.rst | 6 + ...iable.TransientVariable.pressureRegrid.rst | 6 + ...cdms2.tvariable.TransientVariable.prod.rst | 6 + ...s2.tvariable.TransientVariable.product.rst | 6 + .../cdms2.tvariable.TransientVariable.ptp.rst | 6 + .../cdms2.tvariable.TransientVariable.put.rst | 6 + ...dms2.tvariable.TransientVariable.ravel.rst | 6 + ...ms2.tvariable.TransientVariable.regrid.rst | 6 + ...s2.tvariable.TransientVariable.reorder.rst | 6 + ...ms2.tvariable.TransientVariable.repeat.rst | 6 + ...s2.tvariable.TransientVariable.reshape.rst | 6 + ...ms2.tvariable.TransientVariable.resize.rst | 6 + ...dms2.tvariable.TransientVariable.round.rst | 6 + ...riable.TransientVariable.searchPattern.rst | 6 + ...able.TransientVariable.searchPredicate.rst | 6 + ....tvariable.TransientVariable.searchone.rst | 6 + ...ms2.tvariable.TransientVariable.select.rst | 6 + ...s2.tvariable.TransientVariable.setAxis.rst | 6 + ...variable.TransientVariable.setAxisList.rst | 6 + ...tvariable.TransientVariable.setMPIComm.rst | 6 + ....TransientVariable.setMaskFromGridMask.rst | 6 + ...tvariable.TransientVariable.setMissing.rst | 6 + ...ariable.TransientVariable.setTileIndex.rst | 6 + ...iable.TransientVariable.set_fill_value.rst | 6 + ...ariable.TransientVariable.setattribute.rst | 6 + ...able.TransientVariable.setdimattribute.rst | 6 + ...s2.tvariable.TransientVariable.showdim.rst | 6 + ...variable.TransientVariable.shrink_mask.rst | 6 + ...variable.TransientVariable.soften_mask.rst | 6 + ...cdms2.tvariable.TransientVariable.sort.rst | 6 + ...ariable.TransientVariable.specs2slices.rst | 6 + .../cdms2.tvariable.TransientVariable.std.rst | 6 + .../cdms2.tvariable.TransientVariable.sum.rst | 6 + ...2.tvariable.TransientVariable.swapaxes.rst | 6 + ...cdms2.tvariable.TransientVariable.take.rst | 6 + ...s2.tvariable.TransientVariable.toVisit.rst | 6 + ...s2.tvariable.TransientVariable.tobytes.rst | 6 + ...ms2.tvariable.TransientVariable.tofile.rst | 6 + ...ms2.tvariable.TransientVariable.toflex.rst | 6 + ...ms2.tvariable.TransientVariable.tolist.rst | 6 + ....tvariable.TransientVariable.torecords.rst | 6 + ...2.tvariable.TransientVariable.tostring.rst | 6 + ...dms2.tvariable.TransientVariable.trace.rst | 6 + ....tvariable.TransientVariable.transpose.rst | 6 + ...ariable.TransientVariable.unshare_mask.rst | 6 + .../cdms2.tvariable.TransientVariable.var.rst | 6 + ...cdms2.tvariable.TransientVariable.view.rst | 6 + .../generated/cdms2.tvariable.asVariable.rst | 6 + .../generated/cdms2.tvariable.createAxis.rst | 6 + .../cdms2.tvariable.createRectGrid.rst | 6 + .../cdms2.tvariable.createVariable.rst | 6 + .../generated/cdms2.tvariable.fromJSON.rst | 6 + .../generated/cdms2.tvariable.isVariable.rst | 6 + .../generated/cdms2.tvariable.sctype2char.rst | 6 + ...dms2.variable.DatasetVariable.__call__.rst | 6 + ...dms2.variable.DatasetVariable.__iadd__.rst | 6 + ...dms2.variable.DatasetVariable.__idiv__.rst | 6 + ...dms2.variable.DatasetVariable.__imul__.rst | 6 + ...dms2.variable.DatasetVariable.__init__.rst | 6 + ...dms2.variable.DatasetVariable.__isub__.rst | 6 + ...cdms2.variable.DatasetVariable.__len__.rst | 6 + ....variable.DatasetVariable._decodedType.rst | 6 + ...ariable.DatasetVariable._process_specs.rst | 6 + ...variable.DatasetVariable._single_specs.rst | 6 + .../cdms2.variable.DatasetVariable.astype.rst | 6 + ...riable.DatasetVariable.createattribute.rst | 6 + ...ble.DatasetVariable.crossSectionRegrid.rst | 6 + .../cdms2.variable.DatasetVariable.decode.rst | 6 + ...riable.DatasetVariable.deleteattribute.rst | 6 + .../cdms2.variable.DatasetVariable.dump.rst | 6 + ...2.variable.DatasetVariable.expertPaths.rst | 6 + ...dms2.variable.DatasetVariable.genMatch.rst | 6 + ...riable.DatasetVariable.generateGridkey.rst | 6 + ...le.DatasetVariable.generateRectGridkey.rst | 6 + ...s2.variable.DatasetVariable.getAxisIds.rst | 6 + ....variable.DatasetVariable.getAxisIndex.rst | 6 + ...2.variable.DatasetVariable.getAxisList.rst | 6 + ...iable.DatasetVariable.getAxisListIndex.rst | 6 + ...variable.DatasetVariable.getConvention.rst | 6 + ...2.variable.DatasetVariable.getFilePath.rst | 6 + ...riable.DatasetVariable.getForecastTime.rst | 6 + ...ariable.DatasetVariable.getGridIndices.rst | 6 + ...2.variable.DatasetVariable.getLatitude.rst | 6 + ...dms2.variable.DatasetVariable.getLevel.rst | 6 + ....variable.DatasetVariable.getLongitude.rst | 6 + ...s2.variable.DatasetVariable.getMissing.rst | 6 + ...dms2.variable.DatasetVariable.getOrder.rst | 6 + ....variable.DatasetVariable.getPartition.rst | 6 + ...ms2.variable.DatasetVariable.getRegion.rst | 6 + ...dms2.variable.DatasetVariable.getSlice.rst | 6 + ...cdms2.variable.DatasetVariable.getTime.rst | 6 + ...dms2.variable.DatasetVariable.getValue.rst | 6 + ....variable.DatasetVariable.getattribute.rst | 6 + ...riable.DatasetVariable.getdimattribute.rst | 6 + ...2.variable.DatasetVariable.hasCellData.rst | 6 + ...s2.variable.DatasetVariable.initDomain.rst | 6 + ...ms2.variable.DatasetVariable.isEncoded.rst | 6 + ...cdms2.variable.DatasetVariable.listall.rst | 6 + ...ariable.DatasetVariable.listattributes.rst | 6 + ...able.DatasetVariable.listdimattributes.rst | 6 + ....variable.DatasetVariable.listdimnames.rst | 6 + ....variable.DatasetVariable.matchPattern.rst | 6 + ...dms2.variable.DatasetVariable.matchone.rst | 6 + ...ariable.DatasetVariable.pressureRegrid.rst | 6 + .../cdms2.variable.DatasetVariable.regrid.rst | 6 + ...cdms2.variable.DatasetVariable.reorder.rst | 6 + ...variable.DatasetVariable.searchPattern.rst | 6 + ...riable.DatasetVariable.searchPredicate.rst | 6 + ...ms2.variable.DatasetVariable.searchone.rst | 6 + .../cdms2.variable.DatasetVariable.select.rst | 6 + ...s2.variable.DatasetVariable.setMissing.rst | 6 + ....variable.DatasetVariable.setattribute.rst | 6 + ...cdms2.variable.DatasetVariable.showdim.rst | 6 + .../cdms2.variable.DatasetVariable.size.rst | 6 + ....variable.DatasetVariable.specs2slices.rst | 6 + .../cdms2.variable.getPathFromTemplate.rst | 6 + .../generated/cdms2.variable.lenSlice.rst | 6 + .../generated/cdms2.variable.reverseSlice.rst | 6 + .../cdms2.variable.sliceIntersect.rst | 6 + .../cdms2.variable.slicePartition.rst | 6 + .../generated/cdms2.variable.timeindex.rst | 6 + docs/source/source/_static/copybutton.js | 63 ++++++++++ 756 files changed, 4818 insertions(+) create mode 100644 docs/generatedRST.py create mode 100644 docs/source/_static/copybutton.js create mode 100644 docs/source/dataset.rst create mode 100644 docs/source/generated/MV2.allclose.rst create mode 100644 docs/source/generated/MV2.allequal.rst create mode 100644 docs/source/generated/MV2.arange.rst create mode 100644 docs/source/generated/MV2.argsort.rst create mode 100644 docs/source/generated/MV2.arrayrange.rst create mode 100644 docs/source/generated/MV2.asVariable.rst create mode 100644 docs/source/generated/MV2.as_masked.rst create mode 100644 docs/source/generated/MV2.asarray.rst create mode 100644 docs/source/generated/MV2.average.rst create mode 100644 docs/source/generated/MV2.axisAllclose.rst create mode 100644 docs/source/generated/MV2.axisConcatenate.rst create mode 100644 docs/source/generated/MV2.axisTake.rst create mode 100644 docs/source/generated/MV2.choose.rst create mode 100644 docs/source/generated/MV2.commonAxes.rst create mode 100644 docs/source/generated/MV2.commonDomain.rst create mode 100644 docs/source/generated/MV2.commonGrid.rst create mode 100644 docs/source/generated/MV2.commonGrid1.rst create mode 100644 docs/source/generated/MV2.common_fill_value.rst create mode 100644 docs/source/generated/MV2.compress.rst create mode 100644 docs/source/generated/MV2.concatenate.rst create mode 100644 docs/source/generated/MV2.count.rst create mode 100644 docs/source/generated/MV2.create_mask.rst create mode 100644 docs/source/generated/MV2.diagonal.rst create mode 100644 docs/source/generated/MV2.dot.rst create mode 100644 docs/source/generated/MV2.fill_value.rst create mode 100644 docs/source/generated/MV2.filled.rst create mode 100644 docs/source/generated/MV2.fromfunction.rst create mode 100644 docs/source/generated/MV2.getNumericCompatibility.rst create mode 100644 docs/source/generated/MV2.get_print_limit.rst create mode 100644 docs/source/generated/MV2.get_printoptions.rst create mode 100644 docs/source/generated/MV2.getmask.rst create mode 100644 docs/source/generated/MV2.getmaskarray.rst create mode 100644 docs/source/generated/MV2.indices.rst create mode 100644 docs/source/generated/MV2.innerproduct.rst create mode 100644 docs/source/generated/MV2.isMA.rst create mode 100644 docs/source/generated/MV2.isMaskedArray.rst create mode 100644 docs/source/generated/MV2.isMaskedVariable.rst create mode 100644 docs/source/generated/MV2.is_floating.rst create mode 100644 docs/source/generated/MV2.is_integer.rst create mode 100644 docs/source/generated/MV2.is_mask.rst create mode 100644 docs/source/generated/MV2.is_masked.rst create mode 100644 docs/source/generated/MV2.isarray.rst create mode 100644 docs/source/generated/MV2.left_shift.rst create mode 100644 docs/source/generated/MV2.make_mask.rst create mode 100644 docs/source/generated/MV2.make_mask_none.rst create mode 100644 docs/source/generated/MV2.mask_or.rst create mode 100644 docs/source/generated/MV2.masked_array.rst create mode 100644 docs/source/generated/MV2.masked_equal.rst create mode 100644 docs/source/generated/MV2.masked_greater.rst create mode 100644 docs/source/generated/MV2.masked_greater_equal.rst create mode 100644 docs/source/generated/MV2.masked_inside.rst create mode 100644 docs/source/generated/MV2.masked_less.rst create mode 100644 docs/source/generated/MV2.masked_less_equal.rst create mode 100644 docs/source/generated/MV2.masked_not_equal.rst create mode 100644 docs/source/generated/MV2.masked_object.rst create mode 100644 docs/source/generated/MV2.masked_outside.rst create mode 100644 docs/source/generated/MV2.masked_values.rst create mode 100644 docs/source/generated/MV2.masked_where.rst create mode 100644 docs/source/generated/MV2.max.rst create mode 100644 docs/source/generated/MV2.min.rst create mode 100644 docs/source/generated/MV2.ones.rst create mode 100644 docs/source/generated/MV2.outerproduct.rst create mode 100644 docs/source/generated/MV2.power.rst create mode 100644 docs/source/generated/MV2.product.rst create mode 100644 docs/source/generated/MV2.put.rst create mode 100644 docs/source/generated/MV2.putmask.rst create mode 100644 docs/source/generated/MV2.rank.rst create mode 100644 docs/source/generated/MV2.repeat.rst create mode 100644 docs/source/generated/MV2.reshape.rst create mode 100644 docs/source/generated/MV2.resize.rst create mode 100644 docs/source/generated/MV2.right_shift.rst create mode 100644 docs/source/generated/MV2.sctype2char.rst create mode 100644 docs/source/generated/MV2.set_default_fill_value.rst create mode 100644 docs/source/generated/MV2.set_fill_value.rst create mode 100644 docs/source/generated/MV2.set_print_limit.rst create mode 100644 docs/source/generated/MV2.set_printoptions.rst create mode 100644 docs/source/generated/MV2.shape.rst create mode 100644 docs/source/generated/MV2.size.rst create mode 100644 docs/source/generated/MV2.sort.rst create mode 100644 docs/source/generated/MV2.squeeze.rst create mode 100644 docs/source/generated/MV2.sum.rst create mode 100644 docs/source/generated/MV2.take.rst create mode 100644 docs/source/generated/MV2.transpose.rst create mode 100644 docs/source/generated/MV2.where.rst create mode 100644 docs/source/generated/MV2.zeros.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__abs__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__add__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__array__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__call__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__copy__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__div__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__eq__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__floordiv__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__ge__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__getitem__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__getslice__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__gt__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__iadd__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__idiv__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__imul__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__init__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__isub__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__le__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__lshift__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__lt__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__mul__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__ne__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__neg__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__pow__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__radd__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__rdiv__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__rmul__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__rshift__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__rsub__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__sqrt__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__sub__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.__truediv__.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._decodedType.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._getinternals.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._listatts.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._process_specs.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._returnArray.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._setatts.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._setinternals.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._setmissing.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable._single_specs.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.assignValue.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.astype.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.createattribute.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.crossSectionRegrid.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.decode.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.deleteattribute.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.dump.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.expertSlice.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.generateGridkey.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.generateRectGridkey.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getAxis.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIndex.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getAxisList.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getAxisListIndex.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getConvention.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getDomain.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getForecast.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getForecastTime.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getGrid.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getGridIndices.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getLatitude.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getLevel.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getLongitude.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getMissing.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getOrder.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getRegion.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getSlice.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getTime.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getValue.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getattribute.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.getdimattribute.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.hasCellData.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.info.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.isAbstractCoordinate.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.isEncoded.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.listall.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.listattributes.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.listdimattributes.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.listdimnames.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.matchPattern.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.matchone.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.pressureRegrid.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.rank.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.reg_specs2slices.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.regrid.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.reorder.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.searchPattern.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.searchone.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.select.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.setGrid.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.setMissing.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.setattribute.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.showdim.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.specs2slices.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.squeeze.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.subRegion.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.subSlice.rst create mode 100644 docs/source/generated/cdms2.avariable.AbstractVariable.typecode.rst create mode 100644 docs/source/generated/cdms2.avariable._getCoordList.rst create mode 100644 docs/source/generated/cdms2.avariable.axisMatchAxis.rst create mode 100644 docs/source/generated/cdms2.avariable.axisMatchIndex.rst create mode 100644 docs/source/generated/cdms2.avariable.axisMatches.rst create mode 100644 docs/source/generated/cdms2.avariable.getBoundList.rst create mode 100644 docs/source/generated/cdms2.avariable.getMinHorizontalMask.rst create mode 100644 docs/source/generated/cdms2.avariable.getNumericCompatibility.rst create mode 100644 docs/source/generated/cdms2.avariable.guessPeriodicity.rst create mode 100644 docs/source/generated/cdms2.avariable.order2index.rst create mode 100644 docs/source/generated/cdms2.avariable.orderparse.rst create mode 100644 docs/source/generated/cdms2.avariable.setNumericCompatibility.rst create mode 100644 docs/source/generated/cdms2.avariable.splitSlice.rst create mode 100644 docs/source/generated/cdms2.avariable.splitSliceExt.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.getBounds.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.getExplicitBounds.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.info.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.AbstractAxis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.Axis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.getBounds.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.info.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.Axis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.info.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.isUnlimited.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.FileAxis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.info.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.isUnlimited.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.FileVirtualAxis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.__init__.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.info.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.TransientAxis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis._time2value.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.asComponentTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.asDTGTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.asRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.asdatetime.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.clone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.dump.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.getBoundsForDualGrid.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.info.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.isVirtual.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.listall.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.mapInterval.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.mapIntervalExt.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.matchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.matchone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPattern.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.searchone.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.setBounds.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.subAxis.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.subaxis.rst create mode 100644 docs/source/generated/cdms2.axis.TransientVirtualAxis.toRelativeTime.rst create mode 100644 docs/source/generated/cdms2.axis.allclose.rst create mode 100644 docs/source/generated/cdms2.axis.axisMatchAxis.rst create mode 100644 docs/source/generated/cdms2.axis.axisMatchIndex.rst create mode 100644 docs/source/generated/cdms2.axis.axisMatches.rst create mode 100644 docs/source/generated/cdms2.axis.concatenate.rst create mode 100644 docs/source/generated/cdms2.axis.createAxis.rst create mode 100644 docs/source/generated/cdms2.axis.createEqualAreaAxis.rst create mode 100644 docs/source/generated/cdms2.axis.createGaussianAxis.rst create mode 100644 docs/source/generated/cdms2.axis.createUniformLatitudeAxis.rst create mode 100644 docs/source/generated/cdms2.axis.createUniformLongitudeAxis.rst create mode 100644 docs/source/generated/cdms2.axis.getAutoBounds.rst create mode 100644 docs/source/generated/cdms2.axis.isOverlapVector.rst create mode 100644 docs/source/generated/cdms2.axis.isSubsetVector.rst create mode 100644 docs/source/generated/cdms2.axis.lookupArray.rst create mode 100644 docs/source/generated/cdms2.axis.mapLinearExt.rst create mode 100644 docs/source/generated/cdms2.axis.mapLinearIntersection.rst create mode 100644 docs/source/generated/cdms2.axis.reverseSlice.rst create mode 100644 docs/source/generated/cdms2.axis.setAutoBounds.rst create mode 100644 docs/source/generated/cdms2.axis.splitSlice.rst create mode 100644 docs/source/generated/cdms2.axis.splitSliceExt.rst create mode 100644 docs/source/generated/cdms2.axis.take.rst create mode 100644 docs/source/generated/cdms2.bindex.bindexHorizontalGrid.rst create mode 100644 docs/source/generated/cdms2.bindex.intersectHorizontalGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.__call__.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.__getitem__.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile._v.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.cleardefault.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.copyAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.copyGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.createAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.createRectGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.createVariable.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.createVariableCopy.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.createVirtualAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.default_variable.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.dimensionarray.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.dimensionobject.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.dump.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getBoundsAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getVariable.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getVariables.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getdimensionunits.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.getslab.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listall.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listdimension.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listvariable.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.listvariables.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.matchPattern.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.matchone.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.readScripGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.searchPattern.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.searchone.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.showall.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.showattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.showdimension.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.showglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.showvariable.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.sync.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.write.rst create mode 100644 docs/source/generated/cdms2.dataset.CdmsFile.write_it_yourself.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.__call__.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.__getitem__.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset._v.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.cleardefault.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.default_variable.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.dimensionarray.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.dimensionobject.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.dump.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getAxis.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getConvention.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getLogicalCollectionDN.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getVariable.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getVariables.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getdimensionunits.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.getslab.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listall.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listdimension.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listvariable.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.listvariables.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.matchone.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.readScripGrid.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.searchone.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.showall.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.showattribute.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.showdimension.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.showglobal.rst create mode 100644 docs/source/generated/cdms2.dataset.Dataset.showvariable.rst create mode 100644 docs/source/generated/cdms2.dataset.asVariable.rst create mode 100644 docs/source/generated/cdms2.dataset.createDataset.rst create mode 100644 docs/source/generated/cdms2.dataset.getMpiRank.rst create mode 100644 docs/source/generated/cdms2.dataset.getMpiSize.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdf4Flag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfClassicFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfDeflateFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfDeflateLevelFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfShuffleFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfUseNCSwitchModeFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.getNetcdfUseParallelFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.isOverlapVector.rst create mode 100644 docs/source/generated/cdms2.dataset.load.rst create mode 100644 docs/source/generated/cdms2.dataset.loadURI.rst create mode 100644 docs/source/generated/cdms2.dataset.openDataset.rst create mode 100644 docs/source/generated/cdms2.dataset.parseFileMap.rst create mode 100644 docs/source/generated/cdms2.dataset.parseIndexList.rst create mode 100644 docs/source/generated/cdms2.dataset.parseName.rst create mode 100644 docs/source/generated/cdms2.dataset.parseVarMap.rst create mode 100644 docs/source/generated/cdms2.dataset.parselist.rst create mode 100644 docs/source/generated/cdms2.dataset.setCompressionWarnings.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdf4Flag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfClassicFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfDeflateFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfDeflateLevelFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfShuffleFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfUseNCSwitchModeFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.setNetcdfUseParallelFlag.rst create mode 100644 docs/source/generated/cdms2.dataset.urlparse.rst create mode 100644 docs/source/generated/cdms2.dataset.urlunparse.rst create mode 100644 docs/source/generated/cdms2.dataset.useNetcdf3.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__call__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__iadd__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__idiv__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__imul__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__isub__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.__len__.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable._decodedType.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable._process_specs.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable._single_specs.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.astype.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.createattribute.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.crossSectionRegrid.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.decode.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.deleteattribute.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.dump.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.expertPaths.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.genMatch.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.generateGridkey.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.generateRectGridkey.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getAxisIndex.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getAxisList.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getAxisListIndex.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getConvention.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getFilePath.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getForecastTime.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getGridIndices.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getLatitude.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getLevel.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getLongitude.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getMissing.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getOrder.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getPartition.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getRegion.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getSlice.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getTime.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getValue.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getattribute.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.getdimattribute.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.hasCellData.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.initDomain.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.isEncoded.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.listall.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.listattributes.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.listdimattributes.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.listdimnames.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.matchPattern.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.matchone.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.pressureRegrid.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.regrid.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.reorder.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.searchPattern.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.searchone.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.select.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.setMissing.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.setattribute.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.showdim.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.size.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.specs2slices.rst create mode 100644 docs/source/generated/cdms2.fvariable.FileVariable.typecode.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getMPIType.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getSlab.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__array_wrap__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__call__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__float__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__getstate__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__iadd__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__idiv__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__ifloordiv__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__imul__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__init__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__int__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__ipow__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__isub__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__itruediv__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__len__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__long__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__new__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__reduce__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__rfloordiv__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__rpow__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__rtruediv__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__setitem__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__setmask__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.__setstate__.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._comparison.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._decodedType.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._get_data.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._get_flat.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._get_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._get_recordmask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._insert_masked_print.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._process_specs.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._set_flat.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._set_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._set_recordmask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable._single_specs.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.all.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.anom.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.any.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.argmax.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.argmin.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.argsort.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.asma.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.astype.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.clip.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.clone.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.compress.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.compressed.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.copyAxis.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.copyDomain.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.copydimension.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.count.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.createattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.crossSectionRegrid.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.cumprod.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.cumsum.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.decode.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.deleteattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.diagonal.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.dot.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.dump.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.dumps.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.exposeHalo.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.fetchHaloData.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.filled.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.flatten.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.freeHalo.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.generateGridkey.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.generateRectGridkey.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIndex.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getAxisList.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getAxisListIndex.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getConvention.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getForecastTime.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getGridIndices.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getHaloEllipsis.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getLatitude.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getLevel.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getLongitude.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getMPIRank.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getMPISize.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getMissing.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getOrder.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getRegion.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getSlice.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getTileIndex.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getTime.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.get_fill_value.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.get_imag.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.get_real.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.getdimattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.harden_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.hasCellData.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.ids.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.isEncoded.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.listall.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.listattributes.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.listdimattributes.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.listdimnames.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.matchPattern.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.matchone.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.max.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.mean.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.min.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.mini.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.nonzero.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.pressureRegrid.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.prod.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.product.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.ptp.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.put.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.ravel.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.regrid.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.reorder.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.repeat.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.reshape.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.resize.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.round.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.searchPattern.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.searchone.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.select.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setAxis.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setAxisList.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setMPIComm.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setMaskFromGridMask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setMissing.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setTileIndex.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.set_fill_value.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.setdimattribute.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.showdim.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.shrink_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.soften_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.sort.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.specs2slices.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.std.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.sum.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.swapaxes.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.take.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.toVisit.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.tobytes.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.tofile.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.toflex.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.tolist.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.torecords.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.tostring.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.trace.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.transpose.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.unshare_mask.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.var.rst create mode 100644 docs/source/generated/cdms2.tvariable.TransientVariable.view.rst create mode 100644 docs/source/generated/cdms2.tvariable.asVariable.rst create mode 100644 docs/source/generated/cdms2.tvariable.createAxis.rst create mode 100644 docs/source/generated/cdms2.tvariable.createRectGrid.rst create mode 100644 docs/source/generated/cdms2.tvariable.createVariable.rst create mode 100644 docs/source/generated/cdms2.tvariable.fromJSON.rst create mode 100644 docs/source/generated/cdms2.tvariable.isVariable.rst create mode 100644 docs/source/generated/cdms2.tvariable.sctype2char.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__call__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__iadd__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__idiv__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__imul__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__init__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__isub__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.__len__.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable._decodedType.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable._process_specs.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable._single_specs.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.astype.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.createattribute.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.crossSectionRegrid.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.decode.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.deleteattribute.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.dump.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.expertPaths.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.genMatch.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.generateGridkey.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.generateRectGridkey.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getAxisIndex.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getAxisList.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getAxisListIndex.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getConvention.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getFilePath.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getForecastTime.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getGridIndices.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getLatitude.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getLevel.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getLongitude.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getMissing.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getOrder.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getPartition.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getRegion.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getSlice.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getTime.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getValue.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getattribute.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.getdimattribute.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.hasCellData.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.initDomain.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.isEncoded.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.listall.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.listattributes.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.listdimattributes.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.listdimnames.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.matchPattern.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.matchone.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.pressureRegrid.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.regrid.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.reorder.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.searchPattern.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.searchone.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.select.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.setMissing.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.setattribute.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.showdim.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.size.rst create mode 100644 docs/source/generated/cdms2.variable.DatasetVariable.specs2slices.rst create mode 100644 docs/source/generated/cdms2.variable.getPathFromTemplate.rst create mode 100644 docs/source/generated/cdms2.variable.lenSlice.rst create mode 100644 docs/source/generated/cdms2.variable.reverseSlice.rst create mode 100644 docs/source/generated/cdms2.variable.sliceIntersect.rst create mode 100644 docs/source/generated/cdms2.variable.slicePartition.rst create mode 100644 docs/source/generated/cdms2.variable.timeindex.rst create mode 100644 docs/source/source/_static/copybutton.js diff --git a/docs/generatedRST.py b/docs/generatedRST.py new file mode 100644 index 00000000..bd2bf500 --- /dev/null +++ b/docs/generatedRST.py @@ -0,0 +1,68 @@ +#!/bin/env python +from inspect import getmembers, isfunction, isclass, ismethod, isbuiltin +import importlib +import sys +import cdms2 + +def getMember(imported_module): + member_list = [] +# member_list = [o for o in getmembers(imported_module) if isclass(o[1])] + member_list += [o for o in getmembers(imported_module) if isfunction(o[1])] + member_list += [o for o in getmembers(imported_module) if ismethod(o[1]) if o[1].__doc__ is not None] + return member_list + +def RSTwrite(module, memberlist): + if module.find(":") != -1: + currentmodule = ".".join(module.split(":")[:-1]) + else: + currentmodule = module + print currentmodule + auto = ".".join(module.split(":")[1:]) + for member in memberlist: + print member[0] + modulemember = module.replace(":",".") + "." + member[0] + f = open("/tmp/" + modulemember + ".rst", "w") + f.write(module+"\n") + f.write(len(module) * "="+"\n") + f.write("\n") + f.write(".. currentmodule:: " + currentmodule+"\n") + f.write("\n") + if isfunction(member[1]): + if auto == "": + f.write(".. autofunction:: " + member[0]+"\n") + else: + f.write(".. autofunction:: " + auto + "." + member[0]+"\n") + elif isclass(member[1]) and member[0] != "__class__": + f.write(".. autoclass:: " + member[0]+"\n") + sublist = getMember(modulemember) + print modulemember + createRSTfiles([modulemember]) + elif ismethod(member[1]): + f.write(".. automethod:: " + auto+"."+member[0]+"\n") + f.close() + +def createRSTfiles(modules): + for module in modules: + try: + import importlib + m=importlib.import_module(module.replace(":",".")) + except: + m = eval(module.replace(":",".")) + + cdms2_all_list = getMember(m) + print cdms2_all_list + RSTwrite(module, cdms2_all_list) + +if __name__ == "__main__": + modules = ["cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] + createRSTfiles(modules) + + +#numpy.ndarray.flags + +#=================== +# +#.. currentmodule:: numpy +# +#.. autoattribute:: ndarray.flags + diff --git a/docs/source/_static/copybutton.js b/docs/source/_static/copybutton.js new file mode 100644 index 00000000..3564e1da --- /dev/null +++ b/docs/source/_static/copybutton.js @@ -0,0 +1,63 @@ +$(document).ready(function() { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $('.highlight-python .highlight,' + + '.highlight-python3 .highlight' + ) + var pre = div.find('pre'); + + // get the styles from the current theme + pre.parent().parent().css('position', 'relative'); + var hide_text = 'Hide the prompts and output'; + var show_text = 'Show the prompts and output'; + var border_width = pre.css('border-top-width'); + var border_style = pre.css('border-top-style'); + var border_color = pre.css('border-top-color'); + var button_styles = { + 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', + 'border-color': border_color, 'border-style': border_style, + 'border-width': border_width, 'color': border_color, 'text-size': '75%', + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' + } + + // create and add the button to all the code blocks that contain >>> + div.each(function(index) { + var jthis = $(this); + if (jthis.find('.gp').length > 0) { + var button = $('>>>'); + button.css(button_styles) + button.attr('title', hide_text); + button.data('hidden', 'false'); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis.find('pre:has(.gt)').contents().filter(function() { + return ((this.nodeType == 3) && (this.data.trim().length > 0)); + }).wrap(''); + }); + + // define the behavior of the button when it's clicked + $('.copybutton').click(function(e){ + e.preventDefault(); + var button = $(this); + if (button.data('hidden') === 'false') { + // hide the code output + button.parent().find('.go, .gp, .gt').hide(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); + button.css('text-decoration', 'line-through'); + button.attr('title', show_text); + button.data('hidden', 'true'); + } else { + // show the code output + button.parent().find('.go, .gp, .gt').show(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); + button.css('text-decoration', 'none'); + button.attr('title', hide_text); + button.data('hidden', 'false'); + } + }); +}); + diff --git a/docs/source/dataset.rst b/docs/source/dataset.rst new file mode 100644 index 00000000..6156bc8c --- /dev/null +++ b/docs/source/dataset.rst @@ -0,0 +1,112 @@ +.. _dataset: + +dataset +======= + +.. currentmodule:: cdms2.dataset + +.. autosummary:: + :toctree: ./generated + + asVariable + createDataset + getMpiRank + getMpiSize + getNetcdf4Flag + getNetcdfClassicFlag + getNetcdfDeflateFlag + getNetcdfDeflateLevelFlag + getNetcdfShuffleFlag + getNetcdfUseNCSwitchModeFlag + getNetcdfUseParallelFlag + isOverlapVector + load + loadURI + openDataset + parseFileMap + parseIndexList + parselist + parseName + parseVarMap + setCompressionWarnings + setNetcdf4Flag + setNetcdfClassicFlag + setNetcdfDeflateFlag + setNetcdfDeflateLevelFlag + setNetcdfShuffleFlag + setNetcdfUseNCSwitchModeFlag + setNetcdfUseParallelFlag + urlparse + urlunparse + useNetcdf3 + CdmsFile.cleardefault + CdmsFile.copyAxis + CdmsFile.copyGrid + CdmsFile.createAxis + CdmsFile.createRectGrid + CdmsFile.createVariableCopy + CdmsFile.createVariable + CdmsFile.createVirtualAxis + CdmsFile.default_variable + CdmsFile.dimensionarray + CdmsFile.dimensionobject + CdmsFile.dump + CdmsFile.getattribute + CdmsFile.getAxis + CdmsFile.getBoundsAxis + CdmsFile.getdimensionunits + CdmsFile.getglobal + CdmsFile.getGrid + CdmsFile.getslab + CdmsFile.getVariable + CdmsFile.getVariables + CdmsFile.listall + CdmsFile.listattribute + CdmsFile.listdimension + CdmsFile.listglobal + CdmsFile.listvariable + CdmsFile.listvariables + CdmsFile.matchone + CdmsFile.matchPattern + CdmsFile.readScripGrid + CdmsFile.searchone + CdmsFile.searchPattern + CdmsFile.searchPredicate + CdmsFile.showall + CdmsFile.showattribute + CdmsFile.showdimension + CdmsFile.showglobal + CdmsFile.showvariable + CdmsFile.sync + CdmsFile.write_it_yourself + CdmsFile.write + Dataset.cleardefault + Dataset.default_variable + Dataset.dimensionarray + Dataset.dimensionobject + Dataset.dump + Dataset.getattribute + Dataset.getAxis + Dataset.getConvention + Dataset.getdimensionunits + Dataset.getglobal + Dataset.getGrid + Dataset.getLogicalCollectionDN + Dataset.getslab + Dataset.getVariable + Dataset.getVariables + Dataset.listall + Dataset.listattribute + Dataset.listdimension + Dataset.listglobal + Dataset.listvariable + Dataset.listvariables + Dataset.matchone + Dataset.readScripGrid + Dataset.searchone + Dataset.showall + Dataset.showattribute + Dataset.showdimension + Dataset.showglobal + Dataset.showvariable + diff --git a/docs/source/generated/MV2.allclose.rst b/docs/source/generated/MV2.allclose.rst new file mode 100644 index 00000000..5fbc0583 --- /dev/null +++ b/docs/source/generated/MV2.allclose.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: allclose diff --git a/docs/source/generated/MV2.allequal.rst b/docs/source/generated/MV2.allequal.rst new file mode 100644 index 00000000..0b6d7ca4 --- /dev/null +++ b/docs/source/generated/MV2.allequal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: allequal diff --git a/docs/source/generated/MV2.arange.rst b/docs/source/generated/MV2.arange.rst new file mode 100644 index 00000000..6449e8c6 --- /dev/null +++ b/docs/source/generated/MV2.arange.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: arange diff --git a/docs/source/generated/MV2.argsort.rst b/docs/source/generated/MV2.argsort.rst new file mode 100644 index 00000000..e6b4daca --- /dev/null +++ b/docs/source/generated/MV2.argsort.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: argsort diff --git a/docs/source/generated/MV2.arrayrange.rst b/docs/source/generated/MV2.arrayrange.rst new file mode 100644 index 00000000..f2cd007a --- /dev/null +++ b/docs/source/generated/MV2.arrayrange.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: arrayrange diff --git a/docs/source/generated/MV2.asVariable.rst b/docs/source/generated/MV2.asVariable.rst new file mode 100644 index 00000000..277ae8f0 --- /dev/null +++ b/docs/source/generated/MV2.asVariable.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: asVariable diff --git a/docs/source/generated/MV2.as_masked.rst b/docs/source/generated/MV2.as_masked.rst new file mode 100644 index 00000000..f020daec --- /dev/null +++ b/docs/source/generated/MV2.as_masked.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: as_masked diff --git a/docs/source/generated/MV2.asarray.rst b/docs/source/generated/MV2.asarray.rst new file mode 100644 index 00000000..c7034041 --- /dev/null +++ b/docs/source/generated/MV2.asarray.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: asarray diff --git a/docs/source/generated/MV2.average.rst b/docs/source/generated/MV2.average.rst new file mode 100644 index 00000000..404500c6 --- /dev/null +++ b/docs/source/generated/MV2.average.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: average diff --git a/docs/source/generated/MV2.axisAllclose.rst b/docs/source/generated/MV2.axisAllclose.rst new file mode 100644 index 00000000..9793667a --- /dev/null +++ b/docs/source/generated/MV2.axisAllclose.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: axisAllclose diff --git a/docs/source/generated/MV2.axisConcatenate.rst b/docs/source/generated/MV2.axisConcatenate.rst new file mode 100644 index 00000000..fa51745e --- /dev/null +++ b/docs/source/generated/MV2.axisConcatenate.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: axisConcatenate diff --git a/docs/source/generated/MV2.axisTake.rst b/docs/source/generated/MV2.axisTake.rst new file mode 100644 index 00000000..fd2af9db --- /dev/null +++ b/docs/source/generated/MV2.axisTake.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: axisTake diff --git a/docs/source/generated/MV2.choose.rst b/docs/source/generated/MV2.choose.rst new file mode 100644 index 00000000..da0257bc --- /dev/null +++ b/docs/source/generated/MV2.choose.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: choose diff --git a/docs/source/generated/MV2.commonAxes.rst b/docs/source/generated/MV2.commonAxes.rst new file mode 100644 index 00000000..cc1f3523 --- /dev/null +++ b/docs/source/generated/MV2.commonAxes.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: commonAxes diff --git a/docs/source/generated/MV2.commonDomain.rst b/docs/source/generated/MV2.commonDomain.rst new file mode 100644 index 00000000..276f5001 --- /dev/null +++ b/docs/source/generated/MV2.commonDomain.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: commonDomain diff --git a/docs/source/generated/MV2.commonGrid.rst b/docs/source/generated/MV2.commonGrid.rst new file mode 100644 index 00000000..fd3ae609 --- /dev/null +++ b/docs/source/generated/MV2.commonGrid.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: commonGrid diff --git a/docs/source/generated/MV2.commonGrid1.rst b/docs/source/generated/MV2.commonGrid1.rst new file mode 100644 index 00000000..16b80c3d --- /dev/null +++ b/docs/source/generated/MV2.commonGrid1.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: commonGrid1 diff --git a/docs/source/generated/MV2.common_fill_value.rst b/docs/source/generated/MV2.common_fill_value.rst new file mode 100644 index 00000000..2cefd34a --- /dev/null +++ b/docs/source/generated/MV2.common_fill_value.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: common_fill_value diff --git a/docs/source/generated/MV2.compress.rst b/docs/source/generated/MV2.compress.rst new file mode 100644 index 00000000..fa813644 --- /dev/null +++ b/docs/source/generated/MV2.compress.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: compress diff --git a/docs/source/generated/MV2.concatenate.rst b/docs/source/generated/MV2.concatenate.rst new file mode 100644 index 00000000..165f18a7 --- /dev/null +++ b/docs/source/generated/MV2.concatenate.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: concatenate diff --git a/docs/source/generated/MV2.count.rst b/docs/source/generated/MV2.count.rst new file mode 100644 index 00000000..539b9117 --- /dev/null +++ b/docs/source/generated/MV2.count.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: count diff --git a/docs/source/generated/MV2.create_mask.rst b/docs/source/generated/MV2.create_mask.rst new file mode 100644 index 00000000..a7defb16 --- /dev/null +++ b/docs/source/generated/MV2.create_mask.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: create_mask diff --git a/docs/source/generated/MV2.diagonal.rst b/docs/source/generated/MV2.diagonal.rst new file mode 100644 index 00000000..2d0e6d18 --- /dev/null +++ b/docs/source/generated/MV2.diagonal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: diagonal diff --git a/docs/source/generated/MV2.dot.rst b/docs/source/generated/MV2.dot.rst new file mode 100644 index 00000000..7c689f37 --- /dev/null +++ b/docs/source/generated/MV2.dot.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: dot diff --git a/docs/source/generated/MV2.fill_value.rst b/docs/source/generated/MV2.fill_value.rst new file mode 100644 index 00000000..36733479 --- /dev/null +++ b/docs/source/generated/MV2.fill_value.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: fill_value diff --git a/docs/source/generated/MV2.filled.rst b/docs/source/generated/MV2.filled.rst new file mode 100644 index 00000000..1f04ec2b --- /dev/null +++ b/docs/source/generated/MV2.filled.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: filled diff --git a/docs/source/generated/MV2.fromfunction.rst b/docs/source/generated/MV2.fromfunction.rst new file mode 100644 index 00000000..edcde72f --- /dev/null +++ b/docs/source/generated/MV2.fromfunction.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: fromfunction diff --git a/docs/source/generated/MV2.getNumericCompatibility.rst b/docs/source/generated/MV2.getNumericCompatibility.rst new file mode 100644 index 00000000..fa17e4e8 --- /dev/null +++ b/docs/source/generated/MV2.getNumericCompatibility.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: getNumericCompatibility diff --git a/docs/source/generated/MV2.get_print_limit.rst b/docs/source/generated/MV2.get_print_limit.rst new file mode 100644 index 00000000..6879bc7b --- /dev/null +++ b/docs/source/generated/MV2.get_print_limit.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: get_print_limit diff --git a/docs/source/generated/MV2.get_printoptions.rst b/docs/source/generated/MV2.get_printoptions.rst new file mode 100644 index 00000000..26ea6883 --- /dev/null +++ b/docs/source/generated/MV2.get_printoptions.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: get_printoptions diff --git a/docs/source/generated/MV2.getmask.rst b/docs/source/generated/MV2.getmask.rst new file mode 100644 index 00000000..c0b1e3d1 --- /dev/null +++ b/docs/source/generated/MV2.getmask.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: getmask diff --git a/docs/source/generated/MV2.getmaskarray.rst b/docs/source/generated/MV2.getmaskarray.rst new file mode 100644 index 00000000..3413694f --- /dev/null +++ b/docs/source/generated/MV2.getmaskarray.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: getmaskarray diff --git a/docs/source/generated/MV2.indices.rst b/docs/source/generated/MV2.indices.rst new file mode 100644 index 00000000..9cf9deaf --- /dev/null +++ b/docs/source/generated/MV2.indices.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: indices diff --git a/docs/source/generated/MV2.innerproduct.rst b/docs/source/generated/MV2.innerproduct.rst new file mode 100644 index 00000000..f8104042 --- /dev/null +++ b/docs/source/generated/MV2.innerproduct.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: innerproduct diff --git a/docs/source/generated/MV2.isMA.rst b/docs/source/generated/MV2.isMA.rst new file mode 100644 index 00000000..d15757aa --- /dev/null +++ b/docs/source/generated/MV2.isMA.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: isMA diff --git a/docs/source/generated/MV2.isMaskedArray.rst b/docs/source/generated/MV2.isMaskedArray.rst new file mode 100644 index 00000000..c3084e02 --- /dev/null +++ b/docs/source/generated/MV2.isMaskedArray.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: isMaskedArray diff --git a/docs/source/generated/MV2.isMaskedVariable.rst b/docs/source/generated/MV2.isMaskedVariable.rst new file mode 100644 index 00000000..a4dd8e72 --- /dev/null +++ b/docs/source/generated/MV2.isMaskedVariable.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: isMaskedVariable diff --git a/docs/source/generated/MV2.is_floating.rst b/docs/source/generated/MV2.is_floating.rst new file mode 100644 index 00000000..37e510f5 --- /dev/null +++ b/docs/source/generated/MV2.is_floating.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: is_floating diff --git a/docs/source/generated/MV2.is_integer.rst b/docs/source/generated/MV2.is_integer.rst new file mode 100644 index 00000000..50d6f6f2 --- /dev/null +++ b/docs/source/generated/MV2.is_integer.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: is_integer diff --git a/docs/source/generated/MV2.is_mask.rst b/docs/source/generated/MV2.is_mask.rst new file mode 100644 index 00000000..29b54004 --- /dev/null +++ b/docs/source/generated/MV2.is_mask.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: is_mask diff --git a/docs/source/generated/MV2.is_masked.rst b/docs/source/generated/MV2.is_masked.rst new file mode 100644 index 00000000..7b70344e --- /dev/null +++ b/docs/source/generated/MV2.is_masked.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: is_masked diff --git a/docs/source/generated/MV2.isarray.rst b/docs/source/generated/MV2.isarray.rst new file mode 100644 index 00000000..e716bb4b --- /dev/null +++ b/docs/source/generated/MV2.isarray.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: isarray diff --git a/docs/source/generated/MV2.left_shift.rst b/docs/source/generated/MV2.left_shift.rst new file mode 100644 index 00000000..4b161773 --- /dev/null +++ b/docs/source/generated/MV2.left_shift.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: left_shift diff --git a/docs/source/generated/MV2.make_mask.rst b/docs/source/generated/MV2.make_mask.rst new file mode 100644 index 00000000..2d0c55a5 --- /dev/null +++ b/docs/source/generated/MV2.make_mask.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: make_mask diff --git a/docs/source/generated/MV2.make_mask_none.rst b/docs/source/generated/MV2.make_mask_none.rst new file mode 100644 index 00000000..e62cc940 --- /dev/null +++ b/docs/source/generated/MV2.make_mask_none.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: make_mask_none diff --git a/docs/source/generated/MV2.mask_or.rst b/docs/source/generated/MV2.mask_or.rst new file mode 100644 index 00000000..114b5182 --- /dev/null +++ b/docs/source/generated/MV2.mask_or.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: mask_or diff --git a/docs/source/generated/MV2.masked_array.rst b/docs/source/generated/MV2.masked_array.rst new file mode 100644 index 00000000..748a31fb --- /dev/null +++ b/docs/source/generated/MV2.masked_array.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_array diff --git a/docs/source/generated/MV2.masked_equal.rst b/docs/source/generated/MV2.masked_equal.rst new file mode 100644 index 00000000..f40492ad --- /dev/null +++ b/docs/source/generated/MV2.masked_equal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_equal diff --git a/docs/source/generated/MV2.masked_greater.rst b/docs/source/generated/MV2.masked_greater.rst new file mode 100644 index 00000000..f328782b --- /dev/null +++ b/docs/source/generated/MV2.masked_greater.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_greater diff --git a/docs/source/generated/MV2.masked_greater_equal.rst b/docs/source/generated/MV2.masked_greater_equal.rst new file mode 100644 index 00000000..4975380a --- /dev/null +++ b/docs/source/generated/MV2.masked_greater_equal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_greater_equal diff --git a/docs/source/generated/MV2.masked_inside.rst b/docs/source/generated/MV2.masked_inside.rst new file mode 100644 index 00000000..9925f018 --- /dev/null +++ b/docs/source/generated/MV2.masked_inside.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_inside diff --git a/docs/source/generated/MV2.masked_less.rst b/docs/source/generated/MV2.masked_less.rst new file mode 100644 index 00000000..41abc999 --- /dev/null +++ b/docs/source/generated/MV2.masked_less.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_less diff --git a/docs/source/generated/MV2.masked_less_equal.rst b/docs/source/generated/MV2.masked_less_equal.rst new file mode 100644 index 00000000..fe5d1595 --- /dev/null +++ b/docs/source/generated/MV2.masked_less_equal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_less_equal diff --git a/docs/source/generated/MV2.masked_not_equal.rst b/docs/source/generated/MV2.masked_not_equal.rst new file mode 100644 index 00000000..71b1c01a --- /dev/null +++ b/docs/source/generated/MV2.masked_not_equal.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_not_equal diff --git a/docs/source/generated/MV2.masked_object.rst b/docs/source/generated/MV2.masked_object.rst new file mode 100644 index 00000000..79510532 --- /dev/null +++ b/docs/source/generated/MV2.masked_object.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_object diff --git a/docs/source/generated/MV2.masked_outside.rst b/docs/source/generated/MV2.masked_outside.rst new file mode 100644 index 00000000..741f6617 --- /dev/null +++ b/docs/source/generated/MV2.masked_outside.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_outside diff --git a/docs/source/generated/MV2.masked_values.rst b/docs/source/generated/MV2.masked_values.rst new file mode 100644 index 00000000..451da521 --- /dev/null +++ b/docs/source/generated/MV2.masked_values.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_values diff --git a/docs/source/generated/MV2.masked_where.rst b/docs/source/generated/MV2.masked_where.rst new file mode 100644 index 00000000..62afa492 --- /dev/null +++ b/docs/source/generated/MV2.masked_where.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: masked_where diff --git a/docs/source/generated/MV2.max.rst b/docs/source/generated/MV2.max.rst new file mode 100644 index 00000000..08eb49e7 --- /dev/null +++ b/docs/source/generated/MV2.max.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: max diff --git a/docs/source/generated/MV2.min.rst b/docs/source/generated/MV2.min.rst new file mode 100644 index 00000000..903d2ed1 --- /dev/null +++ b/docs/source/generated/MV2.min.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: min diff --git a/docs/source/generated/MV2.ones.rst b/docs/source/generated/MV2.ones.rst new file mode 100644 index 00000000..88b58b35 --- /dev/null +++ b/docs/source/generated/MV2.ones.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: ones diff --git a/docs/source/generated/MV2.outerproduct.rst b/docs/source/generated/MV2.outerproduct.rst new file mode 100644 index 00000000..54b4a603 --- /dev/null +++ b/docs/source/generated/MV2.outerproduct.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: outerproduct diff --git a/docs/source/generated/MV2.power.rst b/docs/source/generated/MV2.power.rst new file mode 100644 index 00000000..71c3af90 --- /dev/null +++ b/docs/source/generated/MV2.power.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: power diff --git a/docs/source/generated/MV2.product.rst b/docs/source/generated/MV2.product.rst new file mode 100644 index 00000000..cc6d4f7e --- /dev/null +++ b/docs/source/generated/MV2.product.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: product diff --git a/docs/source/generated/MV2.put.rst b/docs/source/generated/MV2.put.rst new file mode 100644 index 00000000..6790f9b3 --- /dev/null +++ b/docs/source/generated/MV2.put.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: put diff --git a/docs/source/generated/MV2.putmask.rst b/docs/source/generated/MV2.putmask.rst new file mode 100644 index 00000000..f29e29f9 --- /dev/null +++ b/docs/source/generated/MV2.putmask.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: putmask diff --git a/docs/source/generated/MV2.rank.rst b/docs/source/generated/MV2.rank.rst new file mode 100644 index 00000000..5b56754b --- /dev/null +++ b/docs/source/generated/MV2.rank.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: rank diff --git a/docs/source/generated/MV2.repeat.rst b/docs/source/generated/MV2.repeat.rst new file mode 100644 index 00000000..798be400 --- /dev/null +++ b/docs/source/generated/MV2.repeat.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: repeat diff --git a/docs/source/generated/MV2.reshape.rst b/docs/source/generated/MV2.reshape.rst new file mode 100644 index 00000000..dca80f1a --- /dev/null +++ b/docs/source/generated/MV2.reshape.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: reshape diff --git a/docs/source/generated/MV2.resize.rst b/docs/source/generated/MV2.resize.rst new file mode 100644 index 00000000..0fee71f1 --- /dev/null +++ b/docs/source/generated/MV2.resize.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: resize diff --git a/docs/source/generated/MV2.right_shift.rst b/docs/source/generated/MV2.right_shift.rst new file mode 100644 index 00000000..7fc8cfb9 --- /dev/null +++ b/docs/source/generated/MV2.right_shift.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: right_shift diff --git a/docs/source/generated/MV2.sctype2char.rst b/docs/source/generated/MV2.sctype2char.rst new file mode 100644 index 00000000..00662dca --- /dev/null +++ b/docs/source/generated/MV2.sctype2char.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: sctype2char diff --git a/docs/source/generated/MV2.set_default_fill_value.rst b/docs/source/generated/MV2.set_default_fill_value.rst new file mode 100644 index 00000000..bb4f9e99 --- /dev/null +++ b/docs/source/generated/MV2.set_default_fill_value.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: set_default_fill_value diff --git a/docs/source/generated/MV2.set_fill_value.rst b/docs/source/generated/MV2.set_fill_value.rst new file mode 100644 index 00000000..fdc87e1e --- /dev/null +++ b/docs/source/generated/MV2.set_fill_value.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: set_fill_value diff --git a/docs/source/generated/MV2.set_print_limit.rst b/docs/source/generated/MV2.set_print_limit.rst new file mode 100644 index 00000000..478d9ff8 --- /dev/null +++ b/docs/source/generated/MV2.set_print_limit.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: set_print_limit diff --git a/docs/source/generated/MV2.set_printoptions.rst b/docs/source/generated/MV2.set_printoptions.rst new file mode 100644 index 00000000..759a163c --- /dev/null +++ b/docs/source/generated/MV2.set_printoptions.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: set_printoptions diff --git a/docs/source/generated/MV2.shape.rst b/docs/source/generated/MV2.shape.rst new file mode 100644 index 00000000..b200e939 --- /dev/null +++ b/docs/source/generated/MV2.shape.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: shape diff --git a/docs/source/generated/MV2.size.rst b/docs/source/generated/MV2.size.rst new file mode 100644 index 00000000..7b5cfcf5 --- /dev/null +++ b/docs/source/generated/MV2.size.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: size diff --git a/docs/source/generated/MV2.sort.rst b/docs/source/generated/MV2.sort.rst new file mode 100644 index 00000000..36c9bfe9 --- /dev/null +++ b/docs/source/generated/MV2.sort.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: sort diff --git a/docs/source/generated/MV2.squeeze.rst b/docs/source/generated/MV2.squeeze.rst new file mode 100644 index 00000000..6e54f068 --- /dev/null +++ b/docs/source/generated/MV2.squeeze.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: squeeze diff --git a/docs/source/generated/MV2.sum.rst b/docs/source/generated/MV2.sum.rst new file mode 100644 index 00000000..d69e6706 --- /dev/null +++ b/docs/source/generated/MV2.sum.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: sum diff --git a/docs/source/generated/MV2.take.rst b/docs/source/generated/MV2.take.rst new file mode 100644 index 00000000..e8b3a1b3 --- /dev/null +++ b/docs/source/generated/MV2.take.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: take diff --git a/docs/source/generated/MV2.transpose.rst b/docs/source/generated/MV2.transpose.rst new file mode 100644 index 00000000..af535336 --- /dev/null +++ b/docs/source/generated/MV2.transpose.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: transpose diff --git a/docs/source/generated/MV2.where.rst b/docs/source/generated/MV2.where.rst new file mode 100644 index 00000000..2fce7afa --- /dev/null +++ b/docs/source/generated/MV2.where.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: where diff --git a/docs/source/generated/MV2.zeros.rst b/docs/source/generated/MV2.zeros.rst new file mode 100644 index 00000000..555dd5a6 --- /dev/null +++ b/docs/source/generated/MV2.zeros.rst @@ -0,0 +1,6 @@ +MV2 +=== + +.. currentmodule:: MV2 + +.. autofunction:: zeros diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__abs__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__abs__.rst new file mode 100644 index 00000000..b7717f5e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__abs__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__abs__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__add__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__add__.rst new file mode 100644 index 00000000..9139044b --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__add__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__add__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__array__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__array__.rst new file mode 100644 index 00000000..031e2500 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__array__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__array__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__call__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__call__.rst new file mode 100644 index 00000000..d5bf8209 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__call__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__call__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__copy__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__copy__.rst new file mode 100644 index 00000000..4eb87f68 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__copy__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__copy__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__div__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__div__.rst new file mode 100644 index 00000000..cf110a26 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__div__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__div__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__eq__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__eq__.rst new file mode 100644 index 00000000..a61b5b20 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__eq__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__eq__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__floordiv__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__floordiv__.rst new file mode 100644 index 00000000..58b7e07a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__floordiv__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__floordiv__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__ge__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__ge__.rst new file mode 100644 index 00000000..cec7e79a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__ge__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__ge__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__getitem__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__getitem__.rst new file mode 100644 index 00000000..43c085d9 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__getitem__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__getslice__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__getslice__.rst new file mode 100644 index 00000000..2061e4ee --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__getslice__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__getslice__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__gt__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__gt__.rst new file mode 100644 index 00000000..2dca2280 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__gt__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__gt__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__iadd__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__iadd__.rst new file mode 100644 index 00000000..3d2e3a16 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__iadd__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__iadd__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__idiv__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__idiv__.rst new file mode 100644 index 00000000..aaf14003 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__idiv__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__idiv__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__imul__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__imul__.rst new file mode 100644 index 00000000..baf3cec9 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__imul__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__imul__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__init__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__init__.rst new file mode 100644 index 00000000..d9f1aa0c --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__init__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__init__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__isub__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__isub__.rst new file mode 100644 index 00000000..e968b455 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__isub__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__isub__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__le__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__le__.rst new file mode 100644 index 00000000..e5156841 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__le__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__le__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__lshift__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__lshift__.rst new file mode 100644 index 00000000..ddbf54ad --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__lshift__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__lshift__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__lt__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__lt__.rst new file mode 100644 index 00000000..7a1a3567 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__lt__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__lt__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__mul__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__mul__.rst new file mode 100644 index 00000000..5599ff27 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__mul__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__mul__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__ne__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__ne__.rst new file mode 100644 index 00000000..6e1c3fd0 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__ne__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__ne__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__neg__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__neg__.rst new file mode 100644 index 00000000..9f472d7b --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__neg__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__neg__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__pow__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__pow__.rst new file mode 100644 index 00000000..5cbdd904 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__pow__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__pow__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__radd__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__radd__.rst new file mode 100644 index 00000000..0851bdec --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__radd__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__radd__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__rdiv__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__rdiv__.rst new file mode 100644 index 00000000..55e39e58 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__rdiv__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__rdiv__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__rmul__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__rmul__.rst new file mode 100644 index 00000000..6c773a11 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__rmul__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__rmul__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__rshift__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__rshift__.rst new file mode 100644 index 00000000..ceb6fda9 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__rshift__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__rshift__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__rsub__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__rsub__.rst new file mode 100644 index 00000000..e0ae6d2f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__rsub__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__rsub__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__sqrt__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__sqrt__.rst new file mode 100644 index 00000000..311a32f1 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__sqrt__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__sqrt__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__sub__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__sub__.rst new file mode 100644 index 00000000..f995fef7 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__sub__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__sub__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.__truediv__.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.__truediv__.rst new file mode 100644 index 00000000..cd8e21ac --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.__truediv__.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.__truediv__ diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._decodedType.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._decodedType.rst new file mode 100644 index 00000000..38ab1067 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._decodedType.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._decodedType diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._getinternals.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._getinternals.rst new file mode 100644 index 00000000..b0712a9a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._getinternals.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._getinternals diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._listatts.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._listatts.rst new file mode 100644 index 00000000..52a05c02 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._listatts.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._listatts diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._process_specs.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._process_specs.rst new file mode 100644 index 00000000..6115f74e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._process_specs.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._process_specs diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._returnArray.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._returnArray.rst new file mode 100644 index 00000000..14d0ad07 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._returnArray.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._returnArray diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._setatts.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._setatts.rst new file mode 100644 index 00000000..828ff0b0 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._setatts.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._setatts diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._setinternals.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._setinternals.rst new file mode 100644 index 00000000..2143bee7 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._setinternals.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._setinternals diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._setmissing.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._setmissing.rst new file mode 100644 index 00000000..89634134 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._setmissing.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._setmissing diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable._single_specs.rst b/docs/source/generated/cdms2.avariable.AbstractVariable._single_specs.rst new file mode 100644 index 00000000..101ee8f4 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable._single_specs.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable._single_specs diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.assignValue.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.assignValue.rst new file mode 100644 index 00000000..d3975a79 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.assignValue.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.assignValue diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.astype.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.astype.rst new file mode 100644 index 00000000..a19c8f95 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.astype.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.astype diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.createattribute.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.createattribute.rst new file mode 100644 index 00000000..dc005044 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.createattribute.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.createattribute diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.crossSectionRegrid.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.crossSectionRegrid.rst new file mode 100644 index 00000000..86cb1a32 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.crossSectionRegrid.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.crossSectionRegrid diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.decode.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.decode.rst new file mode 100644 index 00000000..76e6ac2e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.decode.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.decode diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.deleteattribute.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.deleteattribute.rst new file mode 100644 index 00000000..5653ed4f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.deleteattribute.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.deleteattribute diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.dump.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.dump.rst new file mode 100644 index 00000000..feeb3ff4 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.dump.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.dump diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.expertSlice.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.expertSlice.rst new file mode 100644 index 00000000..bb560a12 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.expertSlice.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.expertSlice diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.generateGridkey.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.generateGridkey.rst new file mode 100644 index 00000000..1291681e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.generateGridkey.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.generateGridkey diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.generateRectGridkey.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.generateRectGridkey.rst new file mode 100644 index 00000000..a48499a7 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.generateRectGridkey.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.generateRectGridkey diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getAxis.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxis.rst new file mode 100644 index 00000000..3f980fa5 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getAxis diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIds.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIds.rst new file mode 100644 index 00000000..3a8b1579 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getAxisIds diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIndex.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIndex.rst new file mode 100644 index 00000000..f3f2b62c --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisIndex.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getAxisIndex diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisList.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisList.rst new file mode 100644 index 00000000..96cd2442 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getAxisList diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisListIndex.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisListIndex.rst new file mode 100644 index 00000000..28133d4b --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getAxisListIndex.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getAxisListIndex diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getConvention.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getConvention.rst new file mode 100644 index 00000000..1fbe9c34 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getConvention.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getConvention diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getDomain.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getDomain.rst new file mode 100644 index 00000000..b0fab98a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getDomain.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getDomain diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getForecast.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getForecast.rst new file mode 100644 index 00000000..d9c4f7b2 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getForecast.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getForecast diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getForecastTime.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getForecastTime.rst new file mode 100644 index 00000000..b980a1b2 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getForecastTime.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getForecastTime diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getGrid.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getGrid.rst new file mode 100644 index 00000000..f3536e33 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getGrid.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getGrid diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getGridIndices.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getGridIndices.rst new file mode 100644 index 00000000..0e156bc4 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getGridIndices.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getGridIndices diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getLatitude.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getLatitude.rst new file mode 100644 index 00000000..042076c7 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getLatitude diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getLevel.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getLevel.rst new file mode 100644 index 00000000..db4f0a9e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getLevel.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getLevel diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getLongitude.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getLongitude.rst new file mode 100644 index 00000000..f42b62c3 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getLongitude diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getMissing.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getMissing.rst new file mode 100644 index 00000000..761e27a6 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getMissing.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getMissing diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getOrder.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getOrder.rst new file mode 100644 index 00000000..d544f1d2 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getOrder diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getRegion.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getRegion.rst new file mode 100644 index 00000000..50223013 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getRegion.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getRegion diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getSlice.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getSlice.rst new file mode 100644 index 00000000..36c150cb --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getSlice.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getSlice diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getTime.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getTime.rst new file mode 100644 index 00000000..2b63fe7d --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getTime.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getTime diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getValue.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getValue.rst new file mode 100644 index 00000000..69aebf51 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getValue.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getValue diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getattribute.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getattribute.rst new file mode 100644 index 00000000..5ce117a0 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getattribute diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.getdimattribute.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.getdimattribute.rst new file mode 100644 index 00000000..02f09331 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.getdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.getdimattribute diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.hasCellData.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.hasCellData.rst new file mode 100644 index 00000000..8e010bbe --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.hasCellData.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.hasCellData diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.info.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.info.rst new file mode 100644 index 00000000..cf0aa2c3 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.info.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.info diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.isAbstractCoordinate.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.isAbstractCoordinate.rst new file mode 100644 index 00000000..c2fea681 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.isAbstractCoordinate.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.isAbstractCoordinate diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.isEncoded.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.isEncoded.rst new file mode 100644 index 00000000..577b61c9 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.isEncoded.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.isEncoded diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.listall.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.listall.rst new file mode 100644 index 00000000..58cb4da9 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.listall.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.listall diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.listattributes.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.listattributes.rst new file mode 100644 index 00000000..e1b7f66d --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.listattributes.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.listattributes diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.listdimattributes.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.listdimattributes.rst new file mode 100644 index 00000000..e6fefffb --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.listdimattributes.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.listdimattributes diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.listdimnames.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.listdimnames.rst new file mode 100644 index 00000000..a134c880 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.listdimnames.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.listdimnames diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.matchPattern.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.matchPattern.rst new file mode 100644 index 00000000..5fabdfbd --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.matchPattern diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.matchone.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.matchone.rst new file mode 100644 index 00000000..dd369e7f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.matchone.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.matchone diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.pressureRegrid.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.pressureRegrid.rst new file mode 100644 index 00000000..85794e1f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.pressureRegrid.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.pressureRegrid diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.rank.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.rank.rst new file mode 100644 index 00000000..f9cb3d95 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.rank.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.rank diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.reg_specs2slices.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.reg_specs2slices.rst new file mode 100644 index 00000000..b5a63987 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.reg_specs2slices.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.reg_specs2slices diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.regrid.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.regrid.rst new file mode 100644 index 00000000..90dd444a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.regrid.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.regrid diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.reorder.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.reorder.rst new file mode 100644 index 00000000..dfd4910e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.reorder.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.reorder diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.searchPattern.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.searchPattern.rst new file mode 100644 index 00000000..aece680b --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.searchPattern diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.searchPredicate.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.searchPredicate.rst new file mode 100644 index 00000000..ca20073a --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.searchPredicate diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.searchone.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.searchone.rst new file mode 100644 index 00000000..8993c626 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.searchone.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.searchone diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.select.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.select.rst new file mode 100644 index 00000000..94173b97 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.select.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.select diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.setGrid.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.setGrid.rst new file mode 100644 index 00000000..47abc406 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.setGrid.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.setGrid diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.setMissing.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.setMissing.rst new file mode 100644 index 00000000..2cfd9d27 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.setMissing.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.setMissing diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.setattribute.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.setattribute.rst new file mode 100644 index 00000000..2b082b0f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.setattribute.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.setattribute diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.showdim.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.showdim.rst new file mode 100644 index 00000000..86ac6e81 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.showdim.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.showdim diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.specs2slices.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.specs2slices.rst new file mode 100644 index 00000000..ab555cb5 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.specs2slices.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.specs2slices diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.squeeze.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.squeeze.rst new file mode 100644 index 00000000..bd8bf461 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.squeeze.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.squeeze diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.subRegion.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.subRegion.rst new file mode 100644 index 00000000..a5c672bd --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.subRegion.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.subRegion diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.subSlice.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.subSlice.rst new file mode 100644 index 00000000..b28aa6cb --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.subSlice diff --git a/docs/source/generated/cdms2.avariable.AbstractVariable.typecode.rst b/docs/source/generated/cdms2.avariable.AbstractVariable.typecode.rst new file mode 100644 index 00000000..0db68a26 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.AbstractVariable.typecode.rst @@ -0,0 +1,6 @@ +cdms2.avariable:AbstractVariable +================================ + +.. currentmodule:: cdms2.avariable + +.. automethod:: AbstractVariable.typecode diff --git a/docs/source/generated/cdms2.avariable._getCoordList.rst b/docs/source/generated/cdms2.avariable._getCoordList.rst new file mode 100644 index 00000000..7af13d25 --- /dev/null +++ b/docs/source/generated/cdms2.avariable._getCoordList.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: _getCoordList diff --git a/docs/source/generated/cdms2.avariable.axisMatchAxis.rst b/docs/source/generated/cdms2.avariable.axisMatchAxis.rst new file mode 100644 index 00000000..5ec1c90f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.axisMatchAxis.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: axisMatchAxis diff --git a/docs/source/generated/cdms2.avariable.axisMatchIndex.rst b/docs/source/generated/cdms2.avariable.axisMatchIndex.rst new file mode 100644 index 00000000..70c815d1 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.axisMatchIndex.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: axisMatchIndex diff --git a/docs/source/generated/cdms2.avariable.axisMatches.rst b/docs/source/generated/cdms2.avariable.axisMatches.rst new file mode 100644 index 00000000..6ef05e2f --- /dev/null +++ b/docs/source/generated/cdms2.avariable.axisMatches.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: axisMatches diff --git a/docs/source/generated/cdms2.avariable.getBoundList.rst b/docs/source/generated/cdms2.avariable.getBoundList.rst new file mode 100644 index 00000000..c79bec26 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.getBoundList.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: getBoundList diff --git a/docs/source/generated/cdms2.avariable.getMinHorizontalMask.rst b/docs/source/generated/cdms2.avariable.getMinHorizontalMask.rst new file mode 100644 index 00000000..270a42c5 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.getMinHorizontalMask.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: getMinHorizontalMask diff --git a/docs/source/generated/cdms2.avariable.getNumericCompatibility.rst b/docs/source/generated/cdms2.avariable.getNumericCompatibility.rst new file mode 100644 index 00000000..42e36ed7 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.getNumericCompatibility.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: getNumericCompatibility diff --git a/docs/source/generated/cdms2.avariable.guessPeriodicity.rst b/docs/source/generated/cdms2.avariable.guessPeriodicity.rst new file mode 100644 index 00000000..0a887dda --- /dev/null +++ b/docs/source/generated/cdms2.avariable.guessPeriodicity.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: guessPeriodicity diff --git a/docs/source/generated/cdms2.avariable.order2index.rst b/docs/source/generated/cdms2.avariable.order2index.rst new file mode 100644 index 00000000..a4360461 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.order2index.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: order2index diff --git a/docs/source/generated/cdms2.avariable.orderparse.rst b/docs/source/generated/cdms2.avariable.orderparse.rst new file mode 100644 index 00000000..c6dd57c2 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.orderparse.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: orderparse diff --git a/docs/source/generated/cdms2.avariable.setNumericCompatibility.rst b/docs/source/generated/cdms2.avariable.setNumericCompatibility.rst new file mode 100644 index 00000000..4071aa05 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.setNumericCompatibility.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: setNumericCompatibility diff --git a/docs/source/generated/cdms2.avariable.splitSlice.rst b/docs/source/generated/cdms2.avariable.splitSlice.rst new file mode 100644 index 00000000..4015769e --- /dev/null +++ b/docs/source/generated/cdms2.avariable.splitSlice.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: splitSlice diff --git a/docs/source/generated/cdms2.avariable.splitSliceExt.rst b/docs/source/generated/cdms2.avariable.splitSliceExt.rst new file mode 100644 index 00000000..f65e2780 --- /dev/null +++ b/docs/source/generated/cdms2.avariable.splitSliceExt.rst @@ -0,0 +1,6 @@ +cdms2.avariable +=============== + +.. currentmodule:: cdms2.avariable + +.. autofunction:: splitSliceExt diff --git a/docs/source/generated/cdms2.axis.AbstractAxis._time2value.rst b/docs/source/generated/cdms2.axis.AbstractAxis._time2value.rst new file mode 100644 index 00000000..422cdcfe --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis._time2value diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.asComponentTime.rst b/docs/source/generated/cdms2.axis.AbstractAxis.asComponentTime.rst new file mode 100644 index 00000000..efd6d376 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.asDTGTime.rst b/docs/source/generated/cdms2.axis.AbstractAxis.asDTGTime.rst new file mode 100644 index 00000000..f9ddafdd --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.AbstractAxis.asRelativeTime.rst new file mode 100644 index 00000000..8e35fd82 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.asdatetime.rst b/docs/source/generated/cdms2.axis.AbstractAxis.asdatetime.rst new file mode 100644 index 00000000..7ebae688 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.asdatetime diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.clone.rst b/docs/source/generated/cdms2.axis.AbstractAxis.clone.rst new file mode 100644 index 00000000..39180536 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.clone diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.dump.rst b/docs/source/generated/cdms2.axis.AbstractAxis.dump.rst new file mode 100644 index 00000000..9bd12c1f --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.dump diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.getBounds.rst b/docs/source/generated/cdms2.axis.AbstractAxis.getBounds.rst new file mode 100644 index 00000000..6dfb5c51 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.getBounds diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.AbstractAxis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..f741cad6 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.getExplicitBounds.rst b/docs/source/generated/cdms2.axis.AbstractAxis.getExplicitBounds.rst new file mode 100644 index 00000000..0dae4875 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.getExplicitBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.getExplicitBounds diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.info.rst b/docs/source/generated/cdms2.axis.AbstractAxis.info.rst new file mode 100644 index 00000000..89f0b32d --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.info diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.isVirtual.rst b/docs/source/generated/cdms2.axis.AbstractAxis.isVirtual.rst new file mode 100644 index 00000000..00f2a408 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.isVirtual diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.listall.rst b/docs/source/generated/cdms2.axis.AbstractAxis.listall.rst new file mode 100644 index 00000000..a35e3a14 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.listall diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.mapInterval.rst b/docs/source/generated/cdms2.axis.AbstractAxis.mapInterval.rst new file mode 100644 index 00000000..0b3f3378 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.mapInterval diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.AbstractAxis.mapIntervalExt.rst new file mode 100644 index 00000000..75195d6f --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.matchPattern.rst b/docs/source/generated/cdms2.axis.AbstractAxis.matchPattern.rst new file mode 100644 index 00000000..62ff929b --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.matchPattern diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.matchone.rst b/docs/source/generated/cdms2.axis.AbstractAxis.matchone.rst new file mode 100644 index 00000000..c5ab5dfb --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.matchone diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.searchPattern.rst b/docs/source/generated/cdms2.axis.AbstractAxis.searchPattern.rst new file mode 100644 index 00000000..1fd815a6 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.searchPattern diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.searchPredicate.rst b/docs/source/generated/cdms2.axis.AbstractAxis.searchPredicate.rst new file mode 100644 index 00000000..9047d0ee --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.searchone.rst b/docs/source/generated/cdms2.axis.AbstractAxis.searchone.rst new file mode 100644 index 00000000..ab82e14f --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.searchone diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.subAxis.rst b/docs/source/generated/cdms2.axis.AbstractAxis.subAxis.rst new file mode 100644 index 00000000..86a20082 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.subAxis diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.subaxis.rst b/docs/source/generated/cdms2.axis.AbstractAxis.subaxis.rst new file mode 100644 index 00000000..4a7cb8c1 --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.subaxis diff --git a/docs/source/generated/cdms2.axis.AbstractAxis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.AbstractAxis.toRelativeTime.rst new file mode 100644 index 00000000..e98d209d --- /dev/null +++ b/docs/source/generated/cdms2.axis.AbstractAxis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:AbstractAxis +======================= + +.. currentmodule:: cdms2.axis + +.. automethod:: AbstractAxis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.Axis._time2value.rst b/docs/source/generated/cdms2.axis.Axis._time2value.rst new file mode 100644 index 00000000..afa7333e --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis._time2value diff --git a/docs/source/generated/cdms2.axis.Axis.asComponentTime.rst b/docs/source/generated/cdms2.axis.Axis.asComponentTime.rst new file mode 100644 index 00000000..8e309b11 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.Axis.asDTGTime.rst b/docs/source/generated/cdms2.axis.Axis.asDTGTime.rst new file mode 100644 index 00000000..f9820a64 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.Axis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.Axis.asRelativeTime.rst new file mode 100644 index 00000000..36b122d7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.Axis.asdatetime.rst b/docs/source/generated/cdms2.axis.Axis.asdatetime.rst new file mode 100644 index 00000000..d6535aab --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.asdatetime diff --git a/docs/source/generated/cdms2.axis.Axis.clone.rst b/docs/source/generated/cdms2.axis.Axis.clone.rst new file mode 100644 index 00000000..53b8e7c7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.clone diff --git a/docs/source/generated/cdms2.axis.Axis.dump.rst b/docs/source/generated/cdms2.axis.Axis.dump.rst new file mode 100644 index 00000000..c6315752 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.dump diff --git a/docs/source/generated/cdms2.axis.Axis.getBounds.rst b/docs/source/generated/cdms2.axis.Axis.getBounds.rst new file mode 100644 index 00000000..1e328b97 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.getBounds diff --git a/docs/source/generated/cdms2.axis.Axis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.Axis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..b0d3a217 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.Axis.info.rst b/docs/source/generated/cdms2.axis.Axis.info.rst new file mode 100644 index 00000000..f42ed2ae --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.info diff --git a/docs/source/generated/cdms2.axis.Axis.isVirtual.rst b/docs/source/generated/cdms2.axis.Axis.isVirtual.rst new file mode 100644 index 00000000..7ab9d96c --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.isVirtual diff --git a/docs/source/generated/cdms2.axis.Axis.listall.rst b/docs/source/generated/cdms2.axis.Axis.listall.rst new file mode 100644 index 00000000..03c3e34f --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.listall diff --git a/docs/source/generated/cdms2.axis.Axis.mapInterval.rst b/docs/source/generated/cdms2.axis.Axis.mapInterval.rst new file mode 100644 index 00000000..06850f4b --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.mapInterval diff --git a/docs/source/generated/cdms2.axis.Axis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.Axis.mapIntervalExt.rst new file mode 100644 index 00000000..844ea2c7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.Axis.matchPattern.rst b/docs/source/generated/cdms2.axis.Axis.matchPattern.rst new file mode 100644 index 00000000..c02e85ae --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.matchPattern diff --git a/docs/source/generated/cdms2.axis.Axis.matchone.rst b/docs/source/generated/cdms2.axis.Axis.matchone.rst new file mode 100644 index 00000000..cd6dc19e --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.matchone diff --git a/docs/source/generated/cdms2.axis.Axis.searchPattern.rst b/docs/source/generated/cdms2.axis.Axis.searchPattern.rst new file mode 100644 index 00000000..0f64f232 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.searchPattern diff --git a/docs/source/generated/cdms2.axis.Axis.searchPredicate.rst b/docs/source/generated/cdms2.axis.Axis.searchPredicate.rst new file mode 100644 index 00000000..8bc8cfc3 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.Axis.searchone.rst b/docs/source/generated/cdms2.axis.Axis.searchone.rst new file mode 100644 index 00000000..aaa94ea7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.searchone diff --git a/docs/source/generated/cdms2.axis.Axis.subAxis.rst b/docs/source/generated/cdms2.axis.Axis.subAxis.rst new file mode 100644 index 00000000..59c9b47c --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.subAxis diff --git a/docs/source/generated/cdms2.axis.Axis.subaxis.rst b/docs/source/generated/cdms2.axis.Axis.subaxis.rst new file mode 100644 index 00000000..8dee5345 --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.subaxis diff --git a/docs/source/generated/cdms2.axis.Axis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.Axis.toRelativeTime.rst new file mode 100644 index 00000000..9da6dbbb --- /dev/null +++ b/docs/source/generated/cdms2.axis.Axis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:Axis +=============== + +.. currentmodule:: cdms2.axis + +.. automethod:: Axis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.FileAxis._time2value.rst b/docs/source/generated/cdms2.axis.FileAxis._time2value.rst new file mode 100644 index 00000000..823a2b51 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis._time2value diff --git a/docs/source/generated/cdms2.axis.FileAxis.asComponentTime.rst b/docs/source/generated/cdms2.axis.FileAxis.asComponentTime.rst new file mode 100644 index 00000000..4bbc8a5b --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.FileAxis.asDTGTime.rst b/docs/source/generated/cdms2.axis.FileAxis.asDTGTime.rst new file mode 100644 index 00000000..534875be --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.FileAxis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.FileAxis.asRelativeTime.rst new file mode 100644 index 00000000..b7669d21 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.FileAxis.asdatetime.rst b/docs/source/generated/cdms2.axis.FileAxis.asdatetime.rst new file mode 100644 index 00000000..aa52e23c --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.asdatetime diff --git a/docs/source/generated/cdms2.axis.FileAxis.clone.rst b/docs/source/generated/cdms2.axis.FileAxis.clone.rst new file mode 100644 index 00000000..f51a20ed --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.clone diff --git a/docs/source/generated/cdms2.axis.FileAxis.dump.rst b/docs/source/generated/cdms2.axis.FileAxis.dump.rst new file mode 100644 index 00000000..b686660b --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.dump diff --git a/docs/source/generated/cdms2.axis.FileAxis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.FileAxis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..092abcce --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.FileAxis.info.rst b/docs/source/generated/cdms2.axis.FileAxis.info.rst new file mode 100644 index 00000000..77fd71a5 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.info diff --git a/docs/source/generated/cdms2.axis.FileAxis.isUnlimited.rst b/docs/source/generated/cdms2.axis.FileAxis.isUnlimited.rst new file mode 100644 index 00000000..c52436d7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.isUnlimited.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.isUnlimited diff --git a/docs/source/generated/cdms2.axis.FileAxis.isVirtual.rst b/docs/source/generated/cdms2.axis.FileAxis.isVirtual.rst new file mode 100644 index 00000000..2196efd5 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.isVirtual diff --git a/docs/source/generated/cdms2.axis.FileAxis.listall.rst b/docs/source/generated/cdms2.axis.FileAxis.listall.rst new file mode 100644 index 00000000..d6a08661 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.listall diff --git a/docs/source/generated/cdms2.axis.FileAxis.mapInterval.rst b/docs/source/generated/cdms2.axis.FileAxis.mapInterval.rst new file mode 100644 index 00000000..3a98e3a7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.mapInterval diff --git a/docs/source/generated/cdms2.axis.FileAxis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.FileAxis.mapIntervalExt.rst new file mode 100644 index 00000000..b5edf15f --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.FileAxis.matchPattern.rst b/docs/source/generated/cdms2.axis.FileAxis.matchPattern.rst new file mode 100644 index 00000000..fb8d0b82 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.matchPattern diff --git a/docs/source/generated/cdms2.axis.FileAxis.matchone.rst b/docs/source/generated/cdms2.axis.FileAxis.matchone.rst new file mode 100644 index 00000000..9e73b177 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.matchone diff --git a/docs/source/generated/cdms2.axis.FileAxis.searchPattern.rst b/docs/source/generated/cdms2.axis.FileAxis.searchPattern.rst new file mode 100644 index 00000000..28a0320a --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.searchPattern diff --git a/docs/source/generated/cdms2.axis.FileAxis.searchPredicate.rst b/docs/source/generated/cdms2.axis.FileAxis.searchPredicate.rst new file mode 100644 index 00000000..48d4a6e2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.FileAxis.searchone.rst b/docs/source/generated/cdms2.axis.FileAxis.searchone.rst new file mode 100644 index 00000000..59664ab9 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.searchone diff --git a/docs/source/generated/cdms2.axis.FileAxis.subAxis.rst b/docs/source/generated/cdms2.axis.FileAxis.subAxis.rst new file mode 100644 index 00000000..5952ef6a --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.subAxis diff --git a/docs/source/generated/cdms2.axis.FileAxis.subaxis.rst b/docs/source/generated/cdms2.axis.FileAxis.subaxis.rst new file mode 100644 index 00000000..a1e3d767 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.subaxis diff --git a/docs/source/generated/cdms2.axis.FileAxis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.FileAxis.toRelativeTime.rst new file mode 100644 index 00000000..2729cbdb --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileAxis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileAxis +=================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileAxis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis._time2value.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis._time2value.rst new file mode 100644 index 00000000..139dcf0c --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis._time2value diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.asComponentTime.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.asComponentTime.rst new file mode 100644 index 00000000..824683c7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.asDTGTime.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.asDTGTime.rst new file mode 100644 index 00000000..445a735d --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.asRelativeTime.rst new file mode 100644 index 00000000..b0201027 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.asdatetime.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.asdatetime.rst new file mode 100644 index 00000000..172856e2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.asdatetime diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.clone.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.clone.rst new file mode 100644 index 00000000..f18fe28d --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.clone diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.dump.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.dump.rst new file mode 100644 index 00000000..ded958a3 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.dump diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..1245c644 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.info.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.info.rst new file mode 100644 index 00000000..85e37c24 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.info diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.isUnlimited.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.isUnlimited.rst new file mode 100644 index 00000000..1aef8d73 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.isUnlimited.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.isUnlimited diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.isVirtual.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.isVirtual.rst new file mode 100644 index 00000000..ce4124fd --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.isVirtual diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.listall.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.listall.rst new file mode 100644 index 00000000..478d0eac --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.listall diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.mapInterval.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.mapInterval.rst new file mode 100644 index 00000000..c1b162d0 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.mapInterval diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.mapIntervalExt.rst new file mode 100644 index 00000000..9a18a55a --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.matchPattern.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.matchPattern.rst new file mode 100644 index 00000000..c1aa2f1c --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.matchPattern diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.matchone.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.matchone.rst new file mode 100644 index 00000000..1a05a1fe --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.matchone diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPattern.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPattern.rst new file mode 100644 index 00000000..d990eb86 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.searchPattern diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPredicate.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPredicate.rst new file mode 100644 index 00000000..832161b6 --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.searchone.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchone.rst new file mode 100644 index 00000000..064dfc5d --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.searchone diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.subAxis.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.subAxis.rst new file mode 100644 index 00000000..dbce232d --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.subAxis diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.subaxis.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.subaxis.rst new file mode 100644 index 00000000..d0d241ab --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.subaxis diff --git a/docs/source/generated/cdms2.axis.FileVirtualAxis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.FileVirtualAxis.toRelativeTime.rst new file mode 100644 index 00000000..0f36145d --- /dev/null +++ b/docs/source/generated/cdms2.axis.FileVirtualAxis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:FileVirtualAxis +========================== + +.. currentmodule:: cdms2.axis + +.. automethod:: FileVirtualAxis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.TransientAxis.__init__.rst b/docs/source/generated/cdms2.axis.TransientAxis.__init__.rst new file mode 100644 index 00000000..b4a88a18 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.__init__.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.__init__ diff --git a/docs/source/generated/cdms2.axis.TransientAxis._time2value.rst b/docs/source/generated/cdms2.axis.TransientAxis._time2value.rst new file mode 100644 index 00000000..1a83c1e4 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis._time2value diff --git a/docs/source/generated/cdms2.axis.TransientAxis.asComponentTime.rst b/docs/source/generated/cdms2.axis.TransientAxis.asComponentTime.rst new file mode 100644 index 00000000..790b30ba --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.TransientAxis.asDTGTime.rst b/docs/source/generated/cdms2.axis.TransientAxis.asDTGTime.rst new file mode 100644 index 00000000..7b36d83a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.TransientAxis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.TransientAxis.asRelativeTime.rst new file mode 100644 index 00000000..e3d1335a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.TransientAxis.asdatetime.rst b/docs/source/generated/cdms2.axis.TransientAxis.asdatetime.rst new file mode 100644 index 00000000..6c690f7c --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.asdatetime diff --git a/docs/source/generated/cdms2.axis.TransientAxis.clone.rst b/docs/source/generated/cdms2.axis.TransientAxis.clone.rst new file mode 100644 index 00000000..322ac2e2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.clone diff --git a/docs/source/generated/cdms2.axis.TransientAxis.dump.rst b/docs/source/generated/cdms2.axis.TransientAxis.dump.rst new file mode 100644 index 00000000..0589036f --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.dump diff --git a/docs/source/generated/cdms2.axis.TransientAxis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.TransientAxis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..7165ef59 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.TransientAxis.info.rst b/docs/source/generated/cdms2.axis.TransientAxis.info.rst new file mode 100644 index 00000000..d2edfc54 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.info diff --git a/docs/source/generated/cdms2.axis.TransientAxis.isVirtual.rst b/docs/source/generated/cdms2.axis.TransientAxis.isVirtual.rst new file mode 100644 index 00000000..4f00e26e --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.isVirtual diff --git a/docs/source/generated/cdms2.axis.TransientAxis.listall.rst b/docs/source/generated/cdms2.axis.TransientAxis.listall.rst new file mode 100644 index 00000000..141ca39b --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.listall diff --git a/docs/source/generated/cdms2.axis.TransientAxis.mapInterval.rst b/docs/source/generated/cdms2.axis.TransientAxis.mapInterval.rst new file mode 100644 index 00000000..5a4c14b3 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.mapInterval diff --git a/docs/source/generated/cdms2.axis.TransientAxis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.TransientAxis.mapIntervalExt.rst new file mode 100644 index 00000000..2e871ae2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.TransientAxis.matchPattern.rst b/docs/source/generated/cdms2.axis.TransientAxis.matchPattern.rst new file mode 100644 index 00000000..335f74b2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.matchPattern diff --git a/docs/source/generated/cdms2.axis.TransientAxis.matchone.rst b/docs/source/generated/cdms2.axis.TransientAxis.matchone.rst new file mode 100644 index 00000000..ffd6423a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.matchone diff --git a/docs/source/generated/cdms2.axis.TransientAxis.searchPattern.rst b/docs/source/generated/cdms2.axis.TransientAxis.searchPattern.rst new file mode 100644 index 00000000..be157b6b --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.searchPattern diff --git a/docs/source/generated/cdms2.axis.TransientAxis.searchPredicate.rst b/docs/source/generated/cdms2.axis.TransientAxis.searchPredicate.rst new file mode 100644 index 00000000..f0df569a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.TransientAxis.searchone.rst b/docs/source/generated/cdms2.axis.TransientAxis.searchone.rst new file mode 100644 index 00000000..69a67688 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.searchone diff --git a/docs/source/generated/cdms2.axis.TransientAxis.subAxis.rst b/docs/source/generated/cdms2.axis.TransientAxis.subAxis.rst new file mode 100644 index 00000000..9a6add4e --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.subAxis diff --git a/docs/source/generated/cdms2.axis.TransientAxis.subaxis.rst b/docs/source/generated/cdms2.axis.TransientAxis.subaxis.rst new file mode 100644 index 00000000..58478b88 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.subaxis diff --git a/docs/source/generated/cdms2.axis.TransientAxis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.TransientAxis.toRelativeTime.rst new file mode 100644 index 00000000..bc54e97b --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientAxis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientAxis +======================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientAxis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis._time2value.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis._time2value.rst new file mode 100644 index 00000000..0901ee7e --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis._time2value.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis._time2value diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.asComponentTime.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asComponentTime.rst new file mode 100644 index 00000000..b91e597a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asComponentTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.asComponentTime diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.asDTGTime.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asDTGTime.rst new file mode 100644 index 00000000..abee5e41 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asDTGTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.asDTGTime diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.asRelativeTime.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asRelativeTime.rst new file mode 100644 index 00000000..b45f4b59 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.asRelativeTime diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.asdatetime.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asdatetime.rst new file mode 100644 index 00000000..ad4c4338 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.asdatetime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.asdatetime diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.clone.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.clone.rst new file mode 100644 index 00000000..0ac1f309 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.clone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.clone diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.dump.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.dump.rst new file mode 100644 index 00000000..6a9f13ea --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.dump.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.dump diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.getBoundsForDualGrid.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.getBoundsForDualGrid.rst new file mode 100644 index 00000000..d441a7ef --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.getBoundsForDualGrid.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.getBoundsForDualGrid diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.info.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.info.rst new file mode 100644 index 00000000..f88be415 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.info.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.info diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.isVirtual.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.isVirtual.rst new file mode 100644 index 00000000..83483395 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.isVirtual.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.isVirtual diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.listall.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.listall.rst new file mode 100644 index 00000000..3d777530 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.listall.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.listall diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapInterval.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapInterval.rst new file mode 100644 index 00000000..dbf81033 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapInterval.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.mapInterval diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapIntervalExt.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapIntervalExt.rst new file mode 100644 index 00000000..992d03d7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.mapIntervalExt.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.mapIntervalExt diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchPattern.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchPattern.rst new file mode 100644 index 00000000..34ac2fa2 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.matchPattern diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchone.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchone.rst new file mode 100644 index 00000000..a9d51b1a --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.matchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.matchone diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPattern.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPattern.rst new file mode 100644 index 00000000..d94381dc --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.searchPattern diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPredicate.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPredicate.rst new file mode 100644 index 00000000..e873ea84 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.searchPredicate diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchone.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchone.rst new file mode 100644 index 00000000..7ea19dac --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.searchone.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.searchone diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.setBounds.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.setBounds.rst new file mode 100644 index 00000000..ef0a552f --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.setBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.setBounds diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.subAxis.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.subAxis.rst new file mode 100644 index 00000000..b3329059 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.subAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.subAxis diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.subaxis.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.subaxis.rst new file mode 100644 index 00000000..4971b10d --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.subaxis.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.subaxis diff --git a/docs/source/generated/cdms2.axis.TransientVirtualAxis.toRelativeTime.rst b/docs/source/generated/cdms2.axis.TransientVirtualAxis.toRelativeTime.rst new file mode 100644 index 00000000..db4612a6 --- /dev/null +++ b/docs/source/generated/cdms2.axis.TransientVirtualAxis.toRelativeTime.rst @@ -0,0 +1,6 @@ +cdms2.axis:TransientVirtualAxis +=============================== + +.. currentmodule:: cdms2.axis + +.. automethod:: TransientVirtualAxis.toRelativeTime diff --git a/docs/source/generated/cdms2.axis.allclose.rst b/docs/source/generated/cdms2.axis.allclose.rst new file mode 100644 index 00000000..1166da7e --- /dev/null +++ b/docs/source/generated/cdms2.axis.allclose.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: allclose diff --git a/docs/source/generated/cdms2.axis.axisMatchAxis.rst b/docs/source/generated/cdms2.axis.axisMatchAxis.rst new file mode 100644 index 00000000..9cfb35d7 --- /dev/null +++ b/docs/source/generated/cdms2.axis.axisMatchAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: axisMatchAxis diff --git a/docs/source/generated/cdms2.axis.axisMatchIndex.rst b/docs/source/generated/cdms2.axis.axisMatchIndex.rst new file mode 100644 index 00000000..c1fb4827 --- /dev/null +++ b/docs/source/generated/cdms2.axis.axisMatchIndex.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: axisMatchIndex diff --git a/docs/source/generated/cdms2.axis.axisMatches.rst b/docs/source/generated/cdms2.axis.axisMatches.rst new file mode 100644 index 00000000..f114a125 --- /dev/null +++ b/docs/source/generated/cdms2.axis.axisMatches.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: axisMatches diff --git a/docs/source/generated/cdms2.axis.concatenate.rst b/docs/source/generated/cdms2.axis.concatenate.rst new file mode 100644 index 00000000..6ebbc724 --- /dev/null +++ b/docs/source/generated/cdms2.axis.concatenate.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: concatenate diff --git a/docs/source/generated/cdms2.axis.createAxis.rst b/docs/source/generated/cdms2.axis.createAxis.rst new file mode 100644 index 00000000..81548af4 --- /dev/null +++ b/docs/source/generated/cdms2.axis.createAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: createAxis diff --git a/docs/source/generated/cdms2.axis.createEqualAreaAxis.rst b/docs/source/generated/cdms2.axis.createEqualAreaAxis.rst new file mode 100644 index 00000000..aa7e7e24 --- /dev/null +++ b/docs/source/generated/cdms2.axis.createEqualAreaAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: createEqualAreaAxis diff --git a/docs/source/generated/cdms2.axis.createGaussianAxis.rst b/docs/source/generated/cdms2.axis.createGaussianAxis.rst new file mode 100644 index 00000000..f97346e3 --- /dev/null +++ b/docs/source/generated/cdms2.axis.createGaussianAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: createGaussianAxis diff --git a/docs/source/generated/cdms2.axis.createUniformLatitudeAxis.rst b/docs/source/generated/cdms2.axis.createUniformLatitudeAxis.rst new file mode 100644 index 00000000..c06926ea --- /dev/null +++ b/docs/source/generated/cdms2.axis.createUniformLatitudeAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: createUniformLatitudeAxis diff --git a/docs/source/generated/cdms2.axis.createUniformLongitudeAxis.rst b/docs/source/generated/cdms2.axis.createUniformLongitudeAxis.rst new file mode 100644 index 00000000..6516d07c --- /dev/null +++ b/docs/source/generated/cdms2.axis.createUniformLongitudeAxis.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: createUniformLongitudeAxis diff --git a/docs/source/generated/cdms2.axis.getAutoBounds.rst b/docs/source/generated/cdms2.axis.getAutoBounds.rst new file mode 100644 index 00000000..b0cb8c88 --- /dev/null +++ b/docs/source/generated/cdms2.axis.getAutoBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: getAutoBounds diff --git a/docs/source/generated/cdms2.axis.isOverlapVector.rst b/docs/source/generated/cdms2.axis.isOverlapVector.rst new file mode 100644 index 00000000..133294f9 --- /dev/null +++ b/docs/source/generated/cdms2.axis.isOverlapVector.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: isOverlapVector diff --git a/docs/source/generated/cdms2.axis.isSubsetVector.rst b/docs/source/generated/cdms2.axis.isSubsetVector.rst new file mode 100644 index 00000000..e8f97ee1 --- /dev/null +++ b/docs/source/generated/cdms2.axis.isSubsetVector.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: isSubsetVector diff --git a/docs/source/generated/cdms2.axis.lookupArray.rst b/docs/source/generated/cdms2.axis.lookupArray.rst new file mode 100644 index 00000000..45e1961d --- /dev/null +++ b/docs/source/generated/cdms2.axis.lookupArray.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: lookupArray diff --git a/docs/source/generated/cdms2.axis.mapLinearExt.rst b/docs/source/generated/cdms2.axis.mapLinearExt.rst new file mode 100644 index 00000000..002f91f1 --- /dev/null +++ b/docs/source/generated/cdms2.axis.mapLinearExt.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: mapLinearExt diff --git a/docs/source/generated/cdms2.axis.mapLinearIntersection.rst b/docs/source/generated/cdms2.axis.mapLinearIntersection.rst new file mode 100644 index 00000000..4bfbdde4 --- /dev/null +++ b/docs/source/generated/cdms2.axis.mapLinearIntersection.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: mapLinearIntersection diff --git a/docs/source/generated/cdms2.axis.reverseSlice.rst b/docs/source/generated/cdms2.axis.reverseSlice.rst new file mode 100644 index 00000000..49966dc8 --- /dev/null +++ b/docs/source/generated/cdms2.axis.reverseSlice.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: reverseSlice diff --git a/docs/source/generated/cdms2.axis.setAutoBounds.rst b/docs/source/generated/cdms2.axis.setAutoBounds.rst new file mode 100644 index 00000000..83d62f53 --- /dev/null +++ b/docs/source/generated/cdms2.axis.setAutoBounds.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: setAutoBounds diff --git a/docs/source/generated/cdms2.axis.splitSlice.rst b/docs/source/generated/cdms2.axis.splitSlice.rst new file mode 100644 index 00000000..4cc68560 --- /dev/null +++ b/docs/source/generated/cdms2.axis.splitSlice.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: splitSlice diff --git a/docs/source/generated/cdms2.axis.splitSliceExt.rst b/docs/source/generated/cdms2.axis.splitSliceExt.rst new file mode 100644 index 00000000..c418f689 --- /dev/null +++ b/docs/source/generated/cdms2.axis.splitSliceExt.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: splitSliceExt diff --git a/docs/source/generated/cdms2.axis.take.rst b/docs/source/generated/cdms2.axis.take.rst new file mode 100644 index 00000000..818a98db --- /dev/null +++ b/docs/source/generated/cdms2.axis.take.rst @@ -0,0 +1,6 @@ +cdms2.axis +========== + +.. currentmodule:: cdms2.axis + +.. autofunction:: take diff --git a/docs/source/generated/cdms2.bindex.bindexHorizontalGrid.rst b/docs/source/generated/cdms2.bindex.bindexHorizontalGrid.rst new file mode 100644 index 00000000..fdffede1 --- /dev/null +++ b/docs/source/generated/cdms2.bindex.bindexHorizontalGrid.rst @@ -0,0 +1,6 @@ +cdms2.bindex +============ + +.. currentmodule:: cdms2.bindex + +.. autofunction:: bindexHorizontalGrid diff --git a/docs/source/generated/cdms2.bindex.intersectHorizontalGrid.rst b/docs/source/generated/cdms2.bindex.intersectHorizontalGrid.rst new file mode 100644 index 00000000..8f47af05 --- /dev/null +++ b/docs/source/generated/cdms2.bindex.intersectHorizontalGrid.rst @@ -0,0 +1,6 @@ +cdms2.bindex +============ + +.. currentmodule:: cdms2.bindex + +.. autofunction:: intersectHorizontalGrid diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.__call__.rst b/docs/source/generated/cdms2.dataset.CdmsFile.__call__.rst new file mode 100644 index 00000000..290a95dd --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.__call__.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.__call__ diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.__getitem__.rst b/docs/source/generated/cdms2.dataset.CdmsFile.__getitem__.rst new file mode 100644 index 00000000..37859537 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.__getitem__ diff --git a/docs/source/generated/cdms2.dataset.CdmsFile._v.rst b/docs/source/generated/cdms2.dataset.CdmsFile._v.rst new file mode 100644 index 00000000..d48a03c6 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile._v.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile._v diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.cleardefault.rst b/docs/source/generated/cdms2.dataset.CdmsFile.cleardefault.rst new file mode 100644 index 00000000..32b2a12b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.cleardefault.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.cleardefault diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.copyAxis.rst b/docs/source/generated/cdms2.dataset.CdmsFile.copyAxis.rst new file mode 100644 index 00000000..218b8d9a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.copyAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.copyAxis diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.copyGrid.rst b/docs/source/generated/cdms2.dataset.CdmsFile.copyGrid.rst new file mode 100644 index 00000000..27136138 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.copyGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.copyGrid diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.createAxis.rst b/docs/source/generated/cdms2.dataset.CdmsFile.createAxis.rst new file mode 100644 index 00000000..72f9a037 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.createAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.createAxis diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.createRectGrid.rst b/docs/source/generated/cdms2.dataset.CdmsFile.createRectGrid.rst new file mode 100644 index 00000000..6f1e8728 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.createRectGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.createRectGrid diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.createVariable.rst b/docs/source/generated/cdms2.dataset.CdmsFile.createVariable.rst new file mode 100644 index 00000000..15375668 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.createVariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.createVariable diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.createVariableCopy.rst b/docs/source/generated/cdms2.dataset.CdmsFile.createVariableCopy.rst new file mode 100644 index 00000000..079b941a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.createVariableCopy.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.createVariableCopy diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.createVirtualAxis.rst b/docs/source/generated/cdms2.dataset.CdmsFile.createVirtualAxis.rst new file mode 100644 index 00000000..4dd12ad9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.createVirtualAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.createVirtualAxis diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.default_variable.rst b/docs/source/generated/cdms2.dataset.CdmsFile.default_variable.rst new file mode 100644 index 00000000..430e918b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.default_variable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.default_variable diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.dimensionarray.rst b/docs/source/generated/cdms2.dataset.CdmsFile.dimensionarray.rst new file mode 100644 index 00000000..5ba2ae26 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.dimensionarray.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.dimensionarray diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.dimensionobject.rst b/docs/source/generated/cdms2.dataset.CdmsFile.dimensionobject.rst new file mode 100644 index 00000000..7dcb2285 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.dimensionobject.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.dimensionobject diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.dump.rst b/docs/source/generated/cdms2.dataset.CdmsFile.dump.rst new file mode 100644 index 00000000..e4090726 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.dump.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.dump diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getAxis.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getAxis.rst new file mode 100644 index 00000000..ea7b2b51 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getAxis diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getBoundsAxis.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getBoundsAxis.rst new file mode 100644 index 00000000..077ffc2a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getBoundsAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getBoundsAxis diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getGrid.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getGrid.rst new file mode 100644 index 00000000..2e94e51c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getGrid diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getVariable.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getVariable.rst new file mode 100644 index 00000000..34a5814a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getVariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getVariable diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getVariables.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getVariables.rst new file mode 100644 index 00000000..1f019d15 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getVariables.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getVariables diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getattribute.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getattribute.rst new file mode 100644 index 00000000..c030225e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getattribute diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getdimensionunits.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getdimensionunits.rst new file mode 100644 index 00000000..740bc31c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getdimensionunits.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getdimensionunits diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getglobal.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getglobal.rst new file mode 100644 index 00000000..49b2a5ca --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getglobal diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.getslab.rst b/docs/source/generated/cdms2.dataset.CdmsFile.getslab.rst new file mode 100644 index 00000000..017c482e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.getslab.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.getslab diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listall.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listall.rst new file mode 100644 index 00000000..5db858c3 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listall.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listall diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listattribute.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listattribute.rst new file mode 100644 index 00000000..8461cfac --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listattribute diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listdimension.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listdimension.rst new file mode 100644 index 00000000..eb81dabe --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listdimension.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listdimension diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listglobal.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listglobal.rst new file mode 100644 index 00000000..1aa2fc94 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listglobal diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listvariable.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listvariable.rst new file mode 100644 index 00000000..f105678d --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listvariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listvariable diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.listvariables.rst b/docs/source/generated/cdms2.dataset.CdmsFile.listvariables.rst new file mode 100644 index 00000000..131744e0 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.listvariables.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.listvariables diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.matchPattern.rst b/docs/source/generated/cdms2.dataset.CdmsFile.matchPattern.rst new file mode 100644 index 00000000..34a5fdce --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.matchPattern diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.matchone.rst b/docs/source/generated/cdms2.dataset.CdmsFile.matchone.rst new file mode 100644 index 00000000..3f11bc79 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.matchone.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.matchone diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.readScripGrid.rst b/docs/source/generated/cdms2.dataset.CdmsFile.readScripGrid.rst new file mode 100644 index 00000000..1751d009 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.readScripGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.readScripGrid diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.searchPattern.rst b/docs/source/generated/cdms2.dataset.CdmsFile.searchPattern.rst new file mode 100644 index 00000000..434016db --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.searchPattern diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.searchPredicate.rst b/docs/source/generated/cdms2.dataset.CdmsFile.searchPredicate.rst new file mode 100644 index 00000000..19c60db9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.searchPredicate diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.searchone.rst b/docs/source/generated/cdms2.dataset.CdmsFile.searchone.rst new file mode 100644 index 00000000..e5c77092 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.searchone.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.searchone diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.showall.rst b/docs/source/generated/cdms2.dataset.CdmsFile.showall.rst new file mode 100644 index 00000000..cc1971ef --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.showall.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.showall diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.showattribute.rst b/docs/source/generated/cdms2.dataset.CdmsFile.showattribute.rst new file mode 100644 index 00000000..4c3b1a22 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.showattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.showattribute diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.showdimension.rst b/docs/source/generated/cdms2.dataset.CdmsFile.showdimension.rst new file mode 100644 index 00000000..410d114d --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.showdimension.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.showdimension diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.showglobal.rst b/docs/source/generated/cdms2.dataset.CdmsFile.showglobal.rst new file mode 100644 index 00000000..7df082a9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.showglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.showglobal diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.showvariable.rst b/docs/source/generated/cdms2.dataset.CdmsFile.showvariable.rst new file mode 100644 index 00000000..2ed76621 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.showvariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.showvariable diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.sync.rst b/docs/source/generated/cdms2.dataset.CdmsFile.sync.rst new file mode 100644 index 00000000..7d28af63 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.sync.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.sync diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.write.rst b/docs/source/generated/cdms2.dataset.CdmsFile.write.rst new file mode 100644 index 00000000..53ee71e5 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.write.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.write diff --git a/docs/source/generated/cdms2.dataset.CdmsFile.write_it_yourself.rst b/docs/source/generated/cdms2.dataset.CdmsFile.write_it_yourself.rst new file mode 100644 index 00000000..03b8246c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.CdmsFile.write_it_yourself.rst @@ -0,0 +1,6 @@ +cdms2.dataset:CdmsFile +====================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: CdmsFile.write_it_yourself diff --git a/docs/source/generated/cdms2.dataset.Dataset.__call__.rst b/docs/source/generated/cdms2.dataset.Dataset.__call__.rst new file mode 100644 index 00000000..80d455ed --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.__call__.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.__call__ diff --git a/docs/source/generated/cdms2.dataset.Dataset.__getitem__.rst b/docs/source/generated/cdms2.dataset.Dataset.__getitem__.rst new file mode 100644 index 00000000..26be9a0e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.__getitem__ diff --git a/docs/source/generated/cdms2.dataset.Dataset._v.rst b/docs/source/generated/cdms2.dataset.Dataset._v.rst new file mode 100644 index 00000000..17cd0c78 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset._v.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset._v diff --git a/docs/source/generated/cdms2.dataset.Dataset.cleardefault.rst b/docs/source/generated/cdms2.dataset.Dataset.cleardefault.rst new file mode 100644 index 00000000..a0ead48c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.cleardefault.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.cleardefault diff --git a/docs/source/generated/cdms2.dataset.Dataset.default_variable.rst b/docs/source/generated/cdms2.dataset.Dataset.default_variable.rst new file mode 100644 index 00000000..278b3dc3 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.default_variable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.default_variable diff --git a/docs/source/generated/cdms2.dataset.Dataset.dimensionarray.rst b/docs/source/generated/cdms2.dataset.Dataset.dimensionarray.rst new file mode 100644 index 00000000..ab4222dd --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.dimensionarray.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.dimensionarray diff --git a/docs/source/generated/cdms2.dataset.Dataset.dimensionobject.rst b/docs/source/generated/cdms2.dataset.Dataset.dimensionobject.rst new file mode 100644 index 00000000..5bf1283e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.dimensionobject.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.dimensionobject diff --git a/docs/source/generated/cdms2.dataset.Dataset.dump.rst b/docs/source/generated/cdms2.dataset.Dataset.dump.rst new file mode 100644 index 00000000..990b680c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.dump.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.dump diff --git a/docs/source/generated/cdms2.dataset.Dataset.getAxis.rst b/docs/source/generated/cdms2.dataset.Dataset.getAxis.rst new file mode 100644 index 00000000..57640e09 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getAxis diff --git a/docs/source/generated/cdms2.dataset.Dataset.getConvention.rst b/docs/source/generated/cdms2.dataset.Dataset.getConvention.rst new file mode 100644 index 00000000..3ce569d6 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getConvention.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getConvention diff --git a/docs/source/generated/cdms2.dataset.Dataset.getGrid.rst b/docs/source/generated/cdms2.dataset.Dataset.getGrid.rst new file mode 100644 index 00000000..02673ea0 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getGrid diff --git a/docs/source/generated/cdms2.dataset.Dataset.getLogicalCollectionDN.rst b/docs/source/generated/cdms2.dataset.Dataset.getLogicalCollectionDN.rst new file mode 100644 index 00000000..76eb0d9a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getLogicalCollectionDN.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getLogicalCollectionDN diff --git a/docs/source/generated/cdms2.dataset.Dataset.getVariable.rst b/docs/source/generated/cdms2.dataset.Dataset.getVariable.rst new file mode 100644 index 00000000..d9b414b9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getVariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getVariable diff --git a/docs/source/generated/cdms2.dataset.Dataset.getVariables.rst b/docs/source/generated/cdms2.dataset.Dataset.getVariables.rst new file mode 100644 index 00000000..ad2caf6e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getVariables.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getVariables diff --git a/docs/source/generated/cdms2.dataset.Dataset.getattribute.rst b/docs/source/generated/cdms2.dataset.Dataset.getattribute.rst new file mode 100644 index 00000000..2ef91e41 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getattribute diff --git a/docs/source/generated/cdms2.dataset.Dataset.getdimensionunits.rst b/docs/source/generated/cdms2.dataset.Dataset.getdimensionunits.rst new file mode 100644 index 00000000..c0393a75 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getdimensionunits.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getdimensionunits diff --git a/docs/source/generated/cdms2.dataset.Dataset.getglobal.rst b/docs/source/generated/cdms2.dataset.Dataset.getglobal.rst new file mode 100644 index 00000000..5c842bad --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getglobal diff --git a/docs/source/generated/cdms2.dataset.Dataset.getslab.rst b/docs/source/generated/cdms2.dataset.Dataset.getslab.rst new file mode 100644 index 00000000..554d4e61 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.getslab.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.getslab diff --git a/docs/source/generated/cdms2.dataset.Dataset.listall.rst b/docs/source/generated/cdms2.dataset.Dataset.listall.rst new file mode 100644 index 00000000..1bec6e02 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listall.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listall diff --git a/docs/source/generated/cdms2.dataset.Dataset.listattribute.rst b/docs/source/generated/cdms2.dataset.Dataset.listattribute.rst new file mode 100644 index 00000000..b211747a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listattribute diff --git a/docs/source/generated/cdms2.dataset.Dataset.listdimension.rst b/docs/source/generated/cdms2.dataset.Dataset.listdimension.rst new file mode 100644 index 00000000..38f19ccd --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listdimension.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listdimension diff --git a/docs/source/generated/cdms2.dataset.Dataset.listglobal.rst b/docs/source/generated/cdms2.dataset.Dataset.listglobal.rst new file mode 100644 index 00000000..5a4097a0 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listglobal diff --git a/docs/source/generated/cdms2.dataset.Dataset.listvariable.rst b/docs/source/generated/cdms2.dataset.Dataset.listvariable.rst new file mode 100644 index 00000000..acab1b69 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listvariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listvariable diff --git a/docs/source/generated/cdms2.dataset.Dataset.listvariables.rst b/docs/source/generated/cdms2.dataset.Dataset.listvariables.rst new file mode 100644 index 00000000..81bf6ef5 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.listvariables.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.listvariables diff --git a/docs/source/generated/cdms2.dataset.Dataset.matchone.rst b/docs/source/generated/cdms2.dataset.Dataset.matchone.rst new file mode 100644 index 00000000..4e0fec4b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.matchone.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.matchone diff --git a/docs/source/generated/cdms2.dataset.Dataset.readScripGrid.rst b/docs/source/generated/cdms2.dataset.Dataset.readScripGrid.rst new file mode 100644 index 00000000..f366bca3 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.readScripGrid.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.readScripGrid diff --git a/docs/source/generated/cdms2.dataset.Dataset.searchone.rst b/docs/source/generated/cdms2.dataset.Dataset.searchone.rst new file mode 100644 index 00000000..d38ec57a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.searchone.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.searchone diff --git a/docs/source/generated/cdms2.dataset.Dataset.showall.rst b/docs/source/generated/cdms2.dataset.Dataset.showall.rst new file mode 100644 index 00000000..2301ac75 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.showall.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.showall diff --git a/docs/source/generated/cdms2.dataset.Dataset.showattribute.rst b/docs/source/generated/cdms2.dataset.Dataset.showattribute.rst new file mode 100644 index 00000000..2000feda --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.showattribute.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.showattribute diff --git a/docs/source/generated/cdms2.dataset.Dataset.showdimension.rst b/docs/source/generated/cdms2.dataset.Dataset.showdimension.rst new file mode 100644 index 00000000..7bdf6456 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.showdimension.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.showdimension diff --git a/docs/source/generated/cdms2.dataset.Dataset.showglobal.rst b/docs/source/generated/cdms2.dataset.Dataset.showglobal.rst new file mode 100644 index 00000000..712ea3a3 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.showglobal.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.showglobal diff --git a/docs/source/generated/cdms2.dataset.Dataset.showvariable.rst b/docs/source/generated/cdms2.dataset.Dataset.showvariable.rst new file mode 100644 index 00000000..07f1c71a --- /dev/null +++ b/docs/source/generated/cdms2.dataset.Dataset.showvariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset:Dataset +===================== + +.. currentmodule:: cdms2.dataset + +.. automethod:: Dataset.showvariable diff --git a/docs/source/generated/cdms2.dataset.asVariable.rst b/docs/source/generated/cdms2.dataset.asVariable.rst new file mode 100644 index 00000000..1969efe7 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.asVariable.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: asVariable diff --git a/docs/source/generated/cdms2.dataset.createDataset.rst b/docs/source/generated/cdms2.dataset.createDataset.rst new file mode 100644 index 00000000..0d70e3f4 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.createDataset.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: createDataset diff --git a/docs/source/generated/cdms2.dataset.getMpiRank.rst b/docs/source/generated/cdms2.dataset.getMpiRank.rst new file mode 100644 index 00000000..3db00733 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getMpiRank.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getMpiRank diff --git a/docs/source/generated/cdms2.dataset.getMpiSize.rst b/docs/source/generated/cdms2.dataset.getMpiSize.rst new file mode 100644 index 00000000..0c51627d --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getMpiSize.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getMpiSize diff --git a/docs/source/generated/cdms2.dataset.getNetcdf4Flag.rst b/docs/source/generated/cdms2.dataset.getNetcdf4Flag.rst new file mode 100644 index 00000000..d42d3edc --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdf4Flag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdf4Flag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfClassicFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfClassicFlag.rst new file mode 100644 index 00000000..ead47a46 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfClassicFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfClassicFlag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfDeflateFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfDeflateFlag.rst new file mode 100644 index 00000000..149ca18b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfDeflateFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfDeflateFlag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfDeflateLevelFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfDeflateLevelFlag.rst new file mode 100644 index 00000000..1605c28c --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfDeflateLevelFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfDeflateLevelFlag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfShuffleFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfShuffleFlag.rst new file mode 100644 index 00000000..c942c8c9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfShuffleFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfShuffleFlag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfUseNCSwitchModeFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfUseNCSwitchModeFlag.rst new file mode 100644 index 00000000..2f6e2bc2 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfUseNCSwitchModeFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfUseNCSwitchModeFlag diff --git a/docs/source/generated/cdms2.dataset.getNetcdfUseParallelFlag.rst b/docs/source/generated/cdms2.dataset.getNetcdfUseParallelFlag.rst new file mode 100644 index 00000000..8f8b9303 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.getNetcdfUseParallelFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: getNetcdfUseParallelFlag diff --git a/docs/source/generated/cdms2.dataset.isOverlapVector.rst b/docs/source/generated/cdms2.dataset.isOverlapVector.rst new file mode 100644 index 00000000..a1751b71 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.isOverlapVector.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: isOverlapVector diff --git a/docs/source/generated/cdms2.dataset.load.rst b/docs/source/generated/cdms2.dataset.load.rst new file mode 100644 index 00000000..53479742 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.load.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: load diff --git a/docs/source/generated/cdms2.dataset.loadURI.rst b/docs/source/generated/cdms2.dataset.loadURI.rst new file mode 100644 index 00000000..c34080f8 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.loadURI.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: loadURI diff --git a/docs/source/generated/cdms2.dataset.openDataset.rst b/docs/source/generated/cdms2.dataset.openDataset.rst new file mode 100644 index 00000000..fadcb7df --- /dev/null +++ b/docs/source/generated/cdms2.dataset.openDataset.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: openDataset diff --git a/docs/source/generated/cdms2.dataset.parseFileMap.rst b/docs/source/generated/cdms2.dataset.parseFileMap.rst new file mode 100644 index 00000000..40e57151 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.parseFileMap.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: parseFileMap diff --git a/docs/source/generated/cdms2.dataset.parseIndexList.rst b/docs/source/generated/cdms2.dataset.parseIndexList.rst new file mode 100644 index 00000000..43aec87b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.parseIndexList.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: parseIndexList diff --git a/docs/source/generated/cdms2.dataset.parseName.rst b/docs/source/generated/cdms2.dataset.parseName.rst new file mode 100644 index 00000000..7cb5521e --- /dev/null +++ b/docs/source/generated/cdms2.dataset.parseName.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: parseName diff --git a/docs/source/generated/cdms2.dataset.parseVarMap.rst b/docs/source/generated/cdms2.dataset.parseVarMap.rst new file mode 100644 index 00000000..32c4f873 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.parseVarMap.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: parseVarMap diff --git a/docs/source/generated/cdms2.dataset.parselist.rst b/docs/source/generated/cdms2.dataset.parselist.rst new file mode 100644 index 00000000..07195951 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.parselist.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: parselist diff --git a/docs/source/generated/cdms2.dataset.setCompressionWarnings.rst b/docs/source/generated/cdms2.dataset.setCompressionWarnings.rst new file mode 100644 index 00000000..9b36e4df --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setCompressionWarnings.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setCompressionWarnings diff --git a/docs/source/generated/cdms2.dataset.setNetcdf4Flag.rst b/docs/source/generated/cdms2.dataset.setNetcdf4Flag.rst new file mode 100644 index 00000000..8702ee70 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdf4Flag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdf4Flag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfClassicFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfClassicFlag.rst new file mode 100644 index 00000000..16b0906b --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfClassicFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfClassicFlag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfDeflateFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfDeflateFlag.rst new file mode 100644 index 00000000..075bcc03 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfDeflateFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfDeflateFlag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfDeflateLevelFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfDeflateLevelFlag.rst new file mode 100644 index 00000000..52bee4b4 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfDeflateLevelFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfDeflateLevelFlag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfShuffleFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfShuffleFlag.rst new file mode 100644 index 00000000..3b98e8cd --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfShuffleFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfShuffleFlag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfUseNCSwitchModeFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfUseNCSwitchModeFlag.rst new file mode 100644 index 00000000..34071c92 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfUseNCSwitchModeFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfUseNCSwitchModeFlag diff --git a/docs/source/generated/cdms2.dataset.setNetcdfUseParallelFlag.rst b/docs/source/generated/cdms2.dataset.setNetcdfUseParallelFlag.rst new file mode 100644 index 00000000..aa6983eb --- /dev/null +++ b/docs/source/generated/cdms2.dataset.setNetcdfUseParallelFlag.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: setNetcdfUseParallelFlag diff --git a/docs/source/generated/cdms2.dataset.urlparse.rst b/docs/source/generated/cdms2.dataset.urlparse.rst new file mode 100644 index 00000000..a2b68da9 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.urlparse.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: urlparse diff --git a/docs/source/generated/cdms2.dataset.urlunparse.rst b/docs/source/generated/cdms2.dataset.urlunparse.rst new file mode 100644 index 00000000..9c3b9883 --- /dev/null +++ b/docs/source/generated/cdms2.dataset.urlunparse.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: urlunparse diff --git a/docs/source/generated/cdms2.dataset.useNetcdf3.rst b/docs/source/generated/cdms2.dataset.useNetcdf3.rst new file mode 100644 index 00000000..96d328ce --- /dev/null +++ b/docs/source/generated/cdms2.dataset.useNetcdf3.rst @@ -0,0 +1,6 @@ +cdms2.dataset +============= + +.. currentmodule:: cdms2.dataset + +.. autofunction:: useNetcdf3 diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__call__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__call__.rst new file mode 100644 index 00000000..4634b3b9 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__call__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__call__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__iadd__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__iadd__.rst new file mode 100644 index 00000000..31b80eb9 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__iadd__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__iadd__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__idiv__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__idiv__.rst new file mode 100644 index 00000000..bb3f2e33 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__idiv__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__idiv__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__imul__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__imul__.rst new file mode 100644 index 00000000..952615bd --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__imul__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__imul__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__isub__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__isub__.rst new file mode 100644 index 00000000..c6f61569 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__isub__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__isub__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.__len__.rst b/docs/source/generated/cdms2.fvariable.FileVariable.__len__.rst new file mode 100644 index 00000000..9b6c7fa8 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.__len__.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.__len__ diff --git a/docs/source/generated/cdms2.fvariable.FileVariable._decodedType.rst b/docs/source/generated/cdms2.fvariable.FileVariable._decodedType.rst new file mode 100644 index 00000000..a51eccd2 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable._decodedType.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable._decodedType diff --git a/docs/source/generated/cdms2.fvariable.FileVariable._process_specs.rst b/docs/source/generated/cdms2.fvariable.FileVariable._process_specs.rst new file mode 100644 index 00000000..07ed81d4 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable._process_specs.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable._process_specs diff --git a/docs/source/generated/cdms2.fvariable.FileVariable._single_specs.rst b/docs/source/generated/cdms2.fvariable.FileVariable._single_specs.rst new file mode 100644 index 00000000..2629ec9a --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable._single_specs.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable._single_specs diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.astype.rst b/docs/source/generated/cdms2.fvariable.FileVariable.astype.rst new file mode 100644 index 00000000..c67009ac --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.astype.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.astype diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.createattribute.rst b/docs/source/generated/cdms2.fvariable.FileVariable.createattribute.rst new file mode 100644 index 00000000..df902853 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.createattribute.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.createattribute diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.crossSectionRegrid.rst b/docs/source/generated/cdms2.fvariable.FileVariable.crossSectionRegrid.rst new file mode 100644 index 00000000..06c95d50 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.crossSectionRegrid.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.crossSectionRegrid diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.decode.rst b/docs/source/generated/cdms2.fvariable.FileVariable.decode.rst new file mode 100644 index 00000000..a337b464 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.decode.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.decode diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.deleteattribute.rst b/docs/source/generated/cdms2.fvariable.FileVariable.deleteattribute.rst new file mode 100644 index 00000000..9ed512db --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.deleteattribute.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.deleteattribute diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.dump.rst b/docs/source/generated/cdms2.fvariable.FileVariable.dump.rst new file mode 100644 index 00000000..10ea57c5 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.dump.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.dump diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.expertPaths.rst b/docs/source/generated/cdms2.fvariable.FileVariable.expertPaths.rst new file mode 100644 index 00000000..494436e3 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.expertPaths.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.expertPaths diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.genMatch.rst b/docs/source/generated/cdms2.fvariable.FileVariable.genMatch.rst new file mode 100644 index 00000000..c2694edc --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.genMatch.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.genMatch diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.generateGridkey.rst b/docs/source/generated/cdms2.fvariable.FileVariable.generateGridkey.rst new file mode 100644 index 00000000..c308acf4 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.generateGridkey.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.generateGridkey diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.generateRectGridkey.rst b/docs/source/generated/cdms2.fvariable.FileVariable.generateRectGridkey.rst new file mode 100644 index 00000000..4084a4da --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.generateRectGridkey.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.generateRectGridkey diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIds.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIds.rst new file mode 100644 index 00000000..c5c39132 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getAxisIds diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIndex.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIndex.rst new file mode 100644 index 00000000..42b5eb79 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisIndex.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getAxisIndex diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getAxisList.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisList.rst new file mode 100644 index 00000000..0773eb37 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getAxisList diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getAxisListIndex.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisListIndex.rst new file mode 100644 index 00000000..5070ad75 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getAxisListIndex.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getAxisListIndex diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getConvention.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getConvention.rst new file mode 100644 index 00000000..cae3c4b4 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getConvention.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getConvention diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getFilePath.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getFilePath.rst new file mode 100644 index 00000000..b853228b --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getFilePath.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getFilePath diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getForecastTime.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getForecastTime.rst new file mode 100644 index 00000000..431cd7cc --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getForecastTime.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getForecastTime diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getGridIndices.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getGridIndices.rst new file mode 100644 index 00000000..0f2c71aa --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getGridIndices.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getGridIndices diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getLatitude.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getLatitude.rst new file mode 100644 index 00000000..af368622 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getLatitude diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getLevel.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getLevel.rst new file mode 100644 index 00000000..4a1e5345 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getLevel.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getLevel diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getLongitude.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getLongitude.rst new file mode 100644 index 00000000..61d1b6c2 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getLongitude diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getMissing.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getMissing.rst new file mode 100644 index 00000000..698b3e14 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getMissing.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getMissing diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getOrder.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getOrder.rst new file mode 100644 index 00000000..635aa00e --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getOrder diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getPartition.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getPartition.rst new file mode 100644 index 00000000..40231222 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getPartition.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getPartition diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getRegion.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getRegion.rst new file mode 100644 index 00000000..86a650e9 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getRegion.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getRegion diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getSlice.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getSlice.rst new file mode 100644 index 00000000..a8ea67e3 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getSlice.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getSlice diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getTime.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getTime.rst new file mode 100644 index 00000000..1ee30a24 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getTime.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getTime diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getValue.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getValue.rst new file mode 100644 index 00000000..335d2094 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getValue.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getValue diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getattribute.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getattribute.rst new file mode 100644 index 00000000..06b7ead3 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getattribute diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.getdimattribute.rst b/docs/source/generated/cdms2.fvariable.FileVariable.getdimattribute.rst new file mode 100644 index 00000000..d1c5fccc --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.getdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.getdimattribute diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.hasCellData.rst b/docs/source/generated/cdms2.fvariable.FileVariable.hasCellData.rst new file mode 100644 index 00000000..aa956616 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.hasCellData.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.hasCellData diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.initDomain.rst b/docs/source/generated/cdms2.fvariable.FileVariable.initDomain.rst new file mode 100644 index 00000000..31d2456a --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.initDomain.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.initDomain diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.isEncoded.rst b/docs/source/generated/cdms2.fvariable.FileVariable.isEncoded.rst new file mode 100644 index 00000000..0ba88541 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.isEncoded.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.isEncoded diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.listall.rst b/docs/source/generated/cdms2.fvariable.FileVariable.listall.rst new file mode 100644 index 00000000..37ec32ee --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.listall.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.listall diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.listattributes.rst b/docs/source/generated/cdms2.fvariable.FileVariable.listattributes.rst new file mode 100644 index 00000000..e5e66c39 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.listattributes.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.listattributes diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.listdimattributes.rst b/docs/source/generated/cdms2.fvariable.FileVariable.listdimattributes.rst new file mode 100644 index 00000000..f00a04fe --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.listdimattributes.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.listdimattributes diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.listdimnames.rst b/docs/source/generated/cdms2.fvariable.FileVariable.listdimnames.rst new file mode 100644 index 00000000..dc567786 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.listdimnames.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.listdimnames diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.matchPattern.rst b/docs/source/generated/cdms2.fvariable.FileVariable.matchPattern.rst new file mode 100644 index 00000000..36d63850 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.matchPattern diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.matchone.rst b/docs/source/generated/cdms2.fvariable.FileVariable.matchone.rst new file mode 100644 index 00000000..26d19b2b --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.matchone.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.matchone diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.pressureRegrid.rst b/docs/source/generated/cdms2.fvariable.FileVariable.pressureRegrid.rst new file mode 100644 index 00000000..85f6b4ab --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.pressureRegrid.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.pressureRegrid diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.regrid.rst b/docs/source/generated/cdms2.fvariable.FileVariable.regrid.rst new file mode 100644 index 00000000..abd0bd35 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.regrid.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.regrid diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.reorder.rst b/docs/source/generated/cdms2.fvariable.FileVariable.reorder.rst new file mode 100644 index 00000000..b5872bae --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.reorder.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.reorder diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.searchPattern.rst b/docs/source/generated/cdms2.fvariable.FileVariable.searchPattern.rst new file mode 100644 index 00000000..a52b9352 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.searchPattern diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.searchPredicate.rst b/docs/source/generated/cdms2.fvariable.FileVariable.searchPredicate.rst new file mode 100644 index 00000000..ff9fc592 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.searchPredicate diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.searchone.rst b/docs/source/generated/cdms2.fvariable.FileVariable.searchone.rst new file mode 100644 index 00000000..51d89aaf --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.searchone.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.searchone diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.select.rst b/docs/source/generated/cdms2.fvariable.FileVariable.select.rst new file mode 100644 index 00000000..cd916117 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.select.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.select diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.setMissing.rst b/docs/source/generated/cdms2.fvariable.FileVariable.setMissing.rst new file mode 100644 index 00000000..a74260ff --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.setMissing.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.setMissing diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.setattribute.rst b/docs/source/generated/cdms2.fvariable.FileVariable.setattribute.rst new file mode 100644 index 00000000..0e8a9854 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.setattribute.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.setattribute diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.showdim.rst b/docs/source/generated/cdms2.fvariable.FileVariable.showdim.rst new file mode 100644 index 00000000..506284f3 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.showdim.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.showdim diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.size.rst b/docs/source/generated/cdms2.fvariable.FileVariable.size.rst new file mode 100644 index 00000000..7a177257 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.size.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.size diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.specs2slices.rst b/docs/source/generated/cdms2.fvariable.FileVariable.specs2slices.rst new file mode 100644 index 00000000..2443e511 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.specs2slices.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.specs2slices diff --git a/docs/source/generated/cdms2.fvariable.FileVariable.typecode.rst b/docs/source/generated/cdms2.fvariable.FileVariable.typecode.rst new file mode 100644 index 00000000..a06f8008 --- /dev/null +++ b/docs/source/generated/cdms2.fvariable.FileVariable.typecode.rst @@ -0,0 +1,6 @@ +cdms2.fvariable:FileVariable +============================ + +.. currentmodule:: cdms2.fvariable + +.. automethod:: FileVariable.typecode diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getMPIType.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getMPIType.rst new file mode 100644 index 00000000..4fa9c93f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getMPIType.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._TransientVariable__getMPIType diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getSlab.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getSlab.rst new file mode 100644 index 00000000..57a43f2d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._TransientVariable__getSlab.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._TransientVariable__getSlab diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__array_wrap__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__array_wrap__.rst new file mode 100644 index 00000000..f698ec3a --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__array_wrap__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__array_wrap__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__call__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__call__.rst new file mode 100644 index 00000000..3d3432dd --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__call__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__call__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__float__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__float__.rst new file mode 100644 index 00000000..9e7f368f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__float__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__float__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__getstate__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__getstate__.rst new file mode 100644 index 00000000..9bdaee74 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__getstate__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__getstate__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__iadd__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__iadd__.rst new file mode 100644 index 00000000..b9b940c3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__iadd__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__iadd__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__idiv__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__idiv__.rst new file mode 100644 index 00000000..22c7c601 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__idiv__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__idiv__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__ifloordiv__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__ifloordiv__.rst new file mode 100644 index 00000000..650149e4 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__ifloordiv__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__ifloordiv__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__imul__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__imul__.rst new file mode 100644 index 00000000..c68c9117 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__imul__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__imul__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__init__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__init__.rst new file mode 100644 index 00000000..17d9fd5e --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__init__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__init__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__int__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__int__.rst new file mode 100644 index 00000000..a360624c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__int__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__int__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__ipow__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__ipow__.rst new file mode 100644 index 00000000..9b797b04 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__ipow__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__ipow__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__isub__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__isub__.rst new file mode 100644 index 00000000..1d10e6af --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__isub__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__isub__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__itruediv__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__itruediv__.rst new file mode 100644 index 00000000..07611c60 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__itruediv__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__itruediv__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__len__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__len__.rst new file mode 100644 index 00000000..5ea345b4 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__len__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__len__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__long__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__long__.rst new file mode 100644 index 00000000..1be3daaf --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__long__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__long__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__new__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__new__.rst new file mode 100644 index 00000000..1734290c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__new__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: TransientVariable.__new__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__reduce__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__reduce__.rst new file mode 100644 index 00000000..39bc9a91 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__reduce__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__reduce__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__rfloordiv__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__rfloordiv__.rst new file mode 100644 index 00000000..3ff2cc55 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__rfloordiv__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__rfloordiv__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__rpow__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__rpow__.rst new file mode 100644 index 00000000..e13758ff --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__rpow__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__rpow__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__rtruediv__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__rtruediv__.rst new file mode 100644 index 00000000..1f0fe9bd --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__rtruediv__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__rtruediv__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__setitem__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__setitem__.rst new file mode 100644 index 00000000..1cedba61 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__setitem__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__setitem__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__setmask__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__setmask__.rst new file mode 100644 index 00000000..8703f142 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__setmask__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__setmask__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.__setstate__.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.__setstate__.rst new file mode 100644 index 00000000..b776615f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.__setstate__.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.__setstate__ diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._comparison.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._comparison.rst new file mode 100644 index 00000000..25f3816c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._comparison.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._comparison diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._decodedType.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._decodedType.rst new file mode 100644 index 00000000..dd84fd3b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._decodedType.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._decodedType diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._get_data.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._get_data.rst new file mode 100644 index 00000000..9535421b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._get_data.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._get_data diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._get_flat.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._get_flat.rst new file mode 100644 index 00000000..c1929fe4 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._get_flat.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._get_flat diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._get_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._get_mask.rst new file mode 100644 index 00000000..5ee5c8c8 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._get_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._get_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._get_recordmask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._get_recordmask.rst new file mode 100644 index 00000000..cab7f0e9 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._get_recordmask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._get_recordmask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._insert_masked_print.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._insert_masked_print.rst new file mode 100644 index 00000000..ce36dd4b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._insert_masked_print.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._insert_masked_print diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._process_specs.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._process_specs.rst new file mode 100644 index 00000000..6af037bb --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._process_specs.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._process_specs diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._set_flat.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._set_flat.rst new file mode 100644 index 00000000..73b4a1a0 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._set_flat.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._set_flat diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._set_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._set_mask.rst new file mode 100644 index 00000000..4a3e5c52 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._set_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._set_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._set_recordmask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._set_recordmask.rst new file mode 100644 index 00000000..e4e2bc31 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._set_recordmask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._set_recordmask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable._single_specs.rst b/docs/source/generated/cdms2.tvariable.TransientVariable._single_specs.rst new file mode 100644 index 00000000..3e12aeca --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable._single_specs.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable._single_specs diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.all.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.all.rst new file mode 100644 index 00000000..e3380172 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.all.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.all diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.anom.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.anom.rst new file mode 100644 index 00000000..31b4c1b3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.anom.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.anom diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.any.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.any.rst new file mode 100644 index 00000000..f774f340 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.any.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.any diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.argmax.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.argmax.rst new file mode 100644 index 00000000..f7f7c0e8 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.argmax.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.argmax diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.argmin.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.argmin.rst new file mode 100644 index 00000000..58cc29e7 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.argmin.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.argmin diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.argsort.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.argsort.rst new file mode 100644 index 00000000..4932c997 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.argsort.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.argsort diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.asma.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.asma.rst new file mode 100644 index 00000000..9ff57ec3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.asma.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.asma diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.astype.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.astype.rst new file mode 100644 index 00000000..dc3fcb07 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.astype.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.astype diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.clip.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.clip.rst new file mode 100644 index 00000000..ad1e6477 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.clip.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.clip diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.clone.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.clone.rst new file mode 100644 index 00000000..77e4352b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.clone.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.clone diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.compress.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.compress.rst new file mode 100644 index 00000000..74c08893 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.compress.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.compress diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.compressed.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.compressed.rst new file mode 100644 index 00000000..fcfae1d1 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.compressed.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.compressed diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.copyAxis.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.copyAxis.rst new file mode 100644 index 00000000..625243c7 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.copyAxis.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.copyAxis diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.copyDomain.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.copyDomain.rst new file mode 100644 index 00000000..3f46b546 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.copyDomain.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.copyDomain diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.copydimension.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.copydimension.rst new file mode 100644 index 00000000..eadff7a3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.copydimension.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.copydimension diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.count.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.count.rst new file mode 100644 index 00000000..f31ee372 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.count.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.count diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.createattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.createattribute.rst new file mode 100644 index 00000000..9409d40d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.createattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.createattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.crossSectionRegrid.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.crossSectionRegrid.rst new file mode 100644 index 00000000..4826aca0 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.crossSectionRegrid.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.crossSectionRegrid diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.cumprod.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.cumprod.rst new file mode 100644 index 00000000..6ba12320 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.cumprod.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.cumprod diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.cumsum.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.cumsum.rst new file mode 100644 index 00000000..d5e93937 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.cumsum.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.cumsum diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.decode.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.decode.rst new file mode 100644 index 00000000..61e7a216 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.decode.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.decode diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.deleteattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.deleteattribute.rst new file mode 100644 index 00000000..33dee90d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.deleteattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.deleteattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.diagonal.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.diagonal.rst new file mode 100644 index 00000000..4ce00898 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.diagonal.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.diagonal diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.dot.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.dot.rst new file mode 100644 index 00000000..ef01a51f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.dot.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.dot diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.dump.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.dump.rst new file mode 100644 index 00000000..48893384 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.dump.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.dump diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.dumps.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.dumps.rst new file mode 100644 index 00000000..d9c5a1bc --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.dumps.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.dumps diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.exposeHalo.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.exposeHalo.rst new file mode 100644 index 00000000..d64a64e9 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.exposeHalo.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.exposeHalo diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.fetchHaloData.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.fetchHaloData.rst new file mode 100644 index 00000000..4bec159b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.fetchHaloData.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.fetchHaloData diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.filled.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.filled.rst new file mode 100644 index 00000000..8311b9ae --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.filled.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.filled diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.flatten.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.flatten.rst new file mode 100644 index 00000000..675eb0f8 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.flatten.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.flatten diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.freeHalo.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.freeHalo.rst new file mode 100644 index 00000000..04093ca2 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.freeHalo.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.freeHalo diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.generateGridkey.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.generateGridkey.rst new file mode 100644 index 00000000..502652b8 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.generateGridkey.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.generateGridkey diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.generateRectGridkey.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.generateRectGridkey.rst new file mode 100644 index 00000000..8d2cf11b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.generateRectGridkey.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.generateRectGridkey diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIds.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIds.rst new file mode 100644 index 00000000..79c235fd --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getAxisIds diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIndex.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIndex.rst new file mode 100644 index 00000000..cd190c2f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisIndex.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getAxisIndex diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisList.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisList.rst new file mode 100644 index 00000000..4040c0df --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getAxisList diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisListIndex.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisListIndex.rst new file mode 100644 index 00000000..34fc7513 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getAxisListIndex.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getAxisListIndex diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getConvention.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getConvention.rst new file mode 100644 index 00000000..d7488d6b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getConvention.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getConvention diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getForecastTime.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getForecastTime.rst new file mode 100644 index 00000000..b4131aab --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getForecastTime.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getForecastTime diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getGridIndices.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getGridIndices.rst new file mode 100644 index 00000000..7f7a9869 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getGridIndices.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getGridIndices diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getHaloEllipsis.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getHaloEllipsis.rst new file mode 100644 index 00000000..21e1a891 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getHaloEllipsis.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getHaloEllipsis diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getLatitude.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getLatitude.rst new file mode 100644 index 00000000..5c6ef985 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getLatitude diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getLevel.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getLevel.rst new file mode 100644 index 00000000..bac9d631 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getLevel.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getLevel diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getLongitude.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getLongitude.rst new file mode 100644 index 00000000..739be9b5 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getLongitude diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getMPIRank.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getMPIRank.rst new file mode 100644 index 00000000..54d5491d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getMPIRank.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getMPIRank diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getMPISize.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getMPISize.rst new file mode 100644 index 00000000..490968de --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getMPISize.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getMPISize diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getMissing.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getMissing.rst new file mode 100644 index 00000000..41d2b5de --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getMissing.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getMissing diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getOrder.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getOrder.rst new file mode 100644 index 00000000..e106d4b6 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getOrder diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getRegion.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getRegion.rst new file mode 100644 index 00000000..8939f42c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getRegion.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getRegion diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getSlice.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getSlice.rst new file mode 100644 index 00000000..b7de2806 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getSlice.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getSlice diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getTileIndex.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getTileIndex.rst new file mode 100644 index 00000000..8237a0aa --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getTileIndex.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getTileIndex diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getTime.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getTime.rst new file mode 100644 index 00000000..141a0fa3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getTime.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getTime diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.get_fill_value.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.get_fill_value.rst new file mode 100644 index 00000000..e196a55f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.get_fill_value.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.get_fill_value diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.get_imag.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.get_imag.rst new file mode 100644 index 00000000..3c7bd9fe --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.get_imag.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.get_imag diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.get_real.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.get_real.rst new file mode 100644 index 00000000..e372621c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.get_real.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.get_real diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getattribute.rst new file mode 100644 index 00000000..f5138f43 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.getdimattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.getdimattribute.rst new file mode 100644 index 00000000..6bc3e160 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.getdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.getdimattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.harden_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.harden_mask.rst new file mode 100644 index 00000000..3282ba57 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.harden_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.harden_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.hasCellData.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.hasCellData.rst new file mode 100644 index 00000000..f8076da2 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.hasCellData.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.hasCellData diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.ids.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.ids.rst new file mode 100644 index 00000000..542d0a1f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.ids.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.ids diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.isEncoded.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.isEncoded.rst new file mode 100644 index 00000000..a485f934 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.isEncoded.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.isEncoded diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.listall.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.listall.rst new file mode 100644 index 00000000..c6a0aefb --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.listall.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.listall diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.listattributes.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.listattributes.rst new file mode 100644 index 00000000..b0c11b29 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.listattributes.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.listattributes diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.listdimattributes.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.listdimattributes.rst new file mode 100644 index 00000000..3b786cd7 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.listdimattributes.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.listdimattributes diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.listdimnames.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.listdimnames.rst new file mode 100644 index 00000000..0cd0c6f5 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.listdimnames.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.listdimnames diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.matchPattern.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.matchPattern.rst new file mode 100644 index 00000000..c847fa9a --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.matchPattern diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.matchone.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.matchone.rst new file mode 100644 index 00000000..4d76890f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.matchone.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.matchone diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.max.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.max.rst new file mode 100644 index 00000000..700f92a9 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.max.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.max diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.mean.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.mean.rst new file mode 100644 index 00000000..c5c41b04 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.mean.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.mean diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.min.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.min.rst new file mode 100644 index 00000000..2b0668e2 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.min.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.min diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.mini.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.mini.rst new file mode 100644 index 00000000..9711f601 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.mini.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.mini diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.nonzero.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.nonzero.rst new file mode 100644 index 00000000..850c46bd --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.nonzero.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.nonzero diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.pressureRegrid.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.pressureRegrid.rst new file mode 100644 index 00000000..2f4acc0f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.pressureRegrid.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.pressureRegrid diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.prod.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.prod.rst new file mode 100644 index 00000000..be2061b3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.prod.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.prod diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.product.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.product.rst new file mode 100644 index 00000000..32ba2ba5 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.product.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.product diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.ptp.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.ptp.rst new file mode 100644 index 00000000..7c1c5a9c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.ptp.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.ptp diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.put.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.put.rst new file mode 100644 index 00000000..b217e5c2 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.put.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.put diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.ravel.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.ravel.rst new file mode 100644 index 00000000..e842d40c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.ravel.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.ravel diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.regrid.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.regrid.rst new file mode 100644 index 00000000..22fbb20d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.regrid.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.regrid diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.reorder.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.reorder.rst new file mode 100644 index 00000000..5bca2c10 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.reorder.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.reorder diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.repeat.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.repeat.rst new file mode 100644 index 00000000..a09171bb --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.repeat.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.repeat diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.reshape.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.reshape.rst new file mode 100644 index 00000000..fc22d9b6 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.reshape.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.reshape diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.resize.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.resize.rst new file mode 100644 index 00000000..7664d8ad --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.resize.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.resize diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.round.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.round.rst new file mode 100644 index 00000000..6eb20e94 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.round.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.round diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.searchPattern.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.searchPattern.rst new file mode 100644 index 00000000..ed79eec3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.searchPattern diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.searchPredicate.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.searchPredicate.rst new file mode 100644 index 00000000..0a449f76 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.searchPredicate diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.searchone.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.searchone.rst new file mode 100644 index 00000000..f9e969ae --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.searchone.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.searchone diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.select.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.select.rst new file mode 100644 index 00000000..5065ef36 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.select.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.select diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setAxis.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setAxis.rst new file mode 100644 index 00000000..6a29afd9 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setAxis.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setAxis diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setAxisList.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setAxisList.rst new file mode 100644 index 00000000..db762f08 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setAxisList.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setAxisList diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setMPIComm.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setMPIComm.rst new file mode 100644 index 00000000..82af72ee --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setMPIComm.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setMPIComm diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setMaskFromGridMask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setMaskFromGridMask.rst new file mode 100644 index 00000000..d601027c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setMaskFromGridMask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setMaskFromGridMask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setMissing.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setMissing.rst new file mode 100644 index 00000000..1c63f16c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setMissing.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setMissing diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setTileIndex.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setTileIndex.rst new file mode 100644 index 00000000..b3366ac9 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setTileIndex.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setTileIndex diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.set_fill_value.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.set_fill_value.rst new file mode 100644 index 00000000..75fbc81d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.set_fill_value.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.set_fill_value diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setattribute.rst new file mode 100644 index 00000000..bf85ea7c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.setdimattribute.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.setdimattribute.rst new file mode 100644 index 00000000..d1a44366 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.setdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.setdimattribute diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.showdim.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.showdim.rst new file mode 100644 index 00000000..72b49971 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.showdim.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.showdim diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.shrink_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.shrink_mask.rst new file mode 100644 index 00000000..4bd5abf7 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.shrink_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.shrink_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.soften_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.soften_mask.rst new file mode 100644 index 00000000..289846bc --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.soften_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.soften_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.sort.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.sort.rst new file mode 100644 index 00000000..6051ab2f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.sort.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.sort diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.specs2slices.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.specs2slices.rst new file mode 100644 index 00000000..a49d3338 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.specs2slices.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.specs2slices diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.std.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.std.rst new file mode 100644 index 00000000..eafe9a2c --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.std.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.std diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.sum.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.sum.rst new file mode 100644 index 00000000..84c2efe2 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.sum.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.sum diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.swapaxes.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.swapaxes.rst new file mode 100644 index 00000000..838ff70b --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.swapaxes.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.swapaxes diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.take.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.take.rst new file mode 100644 index 00000000..dd46f7a3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.take.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.take diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.toVisit.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.toVisit.rst new file mode 100644 index 00000000..427f5f49 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.toVisit.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.toVisit diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.tobytes.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.tobytes.rst new file mode 100644 index 00000000..2334d919 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.tobytes.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.tobytes diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.tofile.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.tofile.rst new file mode 100644 index 00000000..ca15529f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.tofile.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.tofile diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.toflex.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.toflex.rst new file mode 100644 index 00000000..91f3e32d --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.toflex.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.toflex diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.tolist.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.tolist.rst new file mode 100644 index 00000000..437ba67f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.tolist.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.tolist diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.torecords.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.torecords.rst new file mode 100644 index 00000000..edafa370 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.torecords.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.torecords diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.tostring.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.tostring.rst new file mode 100644 index 00000000..c0e3f36e --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.tostring.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.tostring diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.trace.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.trace.rst new file mode 100644 index 00000000..09df67b0 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.trace.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.trace diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.transpose.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.transpose.rst new file mode 100644 index 00000000..36c49c28 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.transpose.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.transpose diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.unshare_mask.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.unshare_mask.rst new file mode 100644 index 00000000..81c58854 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.unshare_mask.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.unshare_mask diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.var.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.var.rst new file mode 100644 index 00000000..5d91475e --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.var.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.var diff --git a/docs/source/generated/cdms2.tvariable.TransientVariable.view.rst b/docs/source/generated/cdms2.tvariable.TransientVariable.view.rst new file mode 100644 index 00000000..14aa26d3 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.TransientVariable.view.rst @@ -0,0 +1,6 @@ +cdms2.tvariable:TransientVariable +================================= + +.. currentmodule:: cdms2.tvariable + +.. automethod:: TransientVariable.view diff --git a/docs/source/generated/cdms2.tvariable.asVariable.rst b/docs/source/generated/cdms2.tvariable.asVariable.rst new file mode 100644 index 00000000..e682a5cf --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.asVariable.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: asVariable diff --git a/docs/source/generated/cdms2.tvariable.createAxis.rst b/docs/source/generated/cdms2.tvariable.createAxis.rst new file mode 100644 index 00000000..00cdb42e --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.createAxis.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: createAxis diff --git a/docs/source/generated/cdms2.tvariable.createRectGrid.rst b/docs/source/generated/cdms2.tvariable.createRectGrid.rst new file mode 100644 index 00000000..e7541b8f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.createRectGrid.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: createRectGrid diff --git a/docs/source/generated/cdms2.tvariable.createVariable.rst b/docs/source/generated/cdms2.tvariable.createVariable.rst new file mode 100644 index 00000000..b385f8a7 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.createVariable.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: createVariable diff --git a/docs/source/generated/cdms2.tvariable.fromJSON.rst b/docs/source/generated/cdms2.tvariable.fromJSON.rst new file mode 100644 index 00000000..72ab8450 --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.fromJSON.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: fromJSON diff --git a/docs/source/generated/cdms2.tvariable.isVariable.rst b/docs/source/generated/cdms2.tvariable.isVariable.rst new file mode 100644 index 00000000..3e963c1a --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.isVariable.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: isVariable diff --git a/docs/source/generated/cdms2.tvariable.sctype2char.rst b/docs/source/generated/cdms2.tvariable.sctype2char.rst new file mode 100644 index 00000000..65f78b0f --- /dev/null +++ b/docs/source/generated/cdms2.tvariable.sctype2char.rst @@ -0,0 +1,6 @@ +cdms2.tvariable +=============== + +.. currentmodule:: cdms2.tvariable + +.. autofunction:: sctype2char diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__call__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__call__.rst new file mode 100644 index 00000000..9884d6c9 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__call__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__call__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__iadd__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__iadd__.rst new file mode 100644 index 00000000..1133e51c --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__iadd__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__iadd__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__idiv__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__idiv__.rst new file mode 100644 index 00000000..84fbaedb --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__idiv__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__idiv__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__imul__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__imul__.rst new file mode 100644 index 00000000..d87f64d9 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__imul__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__imul__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__init__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__init__.rst new file mode 100644 index 00000000..47ed7c19 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__init__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__init__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__isub__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__isub__.rst new file mode 100644 index 00000000..763bb25e --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__isub__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__isub__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.__len__.rst b/docs/source/generated/cdms2.variable.DatasetVariable.__len__.rst new file mode 100644 index 00000000..89562318 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.__len__.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.__len__ diff --git a/docs/source/generated/cdms2.variable.DatasetVariable._decodedType.rst b/docs/source/generated/cdms2.variable.DatasetVariable._decodedType.rst new file mode 100644 index 00000000..b9cc17d5 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable._decodedType.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable._decodedType diff --git a/docs/source/generated/cdms2.variable.DatasetVariable._process_specs.rst b/docs/source/generated/cdms2.variable.DatasetVariable._process_specs.rst new file mode 100644 index 00000000..237da6ee --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable._process_specs.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable._process_specs diff --git a/docs/source/generated/cdms2.variable.DatasetVariable._single_specs.rst b/docs/source/generated/cdms2.variable.DatasetVariable._single_specs.rst new file mode 100644 index 00000000..9be9546a --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable._single_specs.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable._single_specs diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.astype.rst b/docs/source/generated/cdms2.variable.DatasetVariable.astype.rst new file mode 100644 index 00000000..628a4dcb --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.astype.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.astype diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.createattribute.rst b/docs/source/generated/cdms2.variable.DatasetVariable.createattribute.rst new file mode 100644 index 00000000..d313455a --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.createattribute.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.createattribute diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.crossSectionRegrid.rst b/docs/source/generated/cdms2.variable.DatasetVariable.crossSectionRegrid.rst new file mode 100644 index 00000000..2cb446c6 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.crossSectionRegrid.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.crossSectionRegrid diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.decode.rst b/docs/source/generated/cdms2.variable.DatasetVariable.decode.rst new file mode 100644 index 00000000..69505154 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.decode.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.decode diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.deleteattribute.rst b/docs/source/generated/cdms2.variable.DatasetVariable.deleteattribute.rst new file mode 100644 index 00000000..53dd0d46 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.deleteattribute.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.deleteattribute diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.dump.rst b/docs/source/generated/cdms2.variable.DatasetVariable.dump.rst new file mode 100644 index 00000000..2c25ab62 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.dump.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.dump diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.expertPaths.rst b/docs/source/generated/cdms2.variable.DatasetVariable.expertPaths.rst new file mode 100644 index 00000000..9ea79d9b --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.expertPaths.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.expertPaths diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.genMatch.rst b/docs/source/generated/cdms2.variable.DatasetVariable.genMatch.rst new file mode 100644 index 00000000..45269d9f --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.genMatch.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.genMatch diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.generateGridkey.rst b/docs/source/generated/cdms2.variable.DatasetVariable.generateGridkey.rst new file mode 100644 index 00000000..b4741b7b --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.generateGridkey.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.generateGridkey diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.generateRectGridkey.rst b/docs/source/generated/cdms2.variable.DatasetVariable.generateRectGridkey.rst new file mode 100644 index 00000000..5b7c83e2 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.generateRectGridkey.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.generateRectGridkey diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIds.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIds.rst new file mode 100644 index 00000000..963da850 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getAxisIds diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIndex.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIndex.rst new file mode 100644 index 00000000..ba60a537 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisIndex.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getAxisIndex diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getAxisList.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisList.rst new file mode 100644 index 00000000..65321393 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getAxisList diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getAxisListIndex.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisListIndex.rst new file mode 100644 index 00000000..6e5d4f14 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getAxisListIndex.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getAxisListIndex diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getConvention.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getConvention.rst new file mode 100644 index 00000000..b9db59d8 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getConvention.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getConvention diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getFilePath.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getFilePath.rst new file mode 100644 index 00000000..9658fd2a --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getFilePath.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getFilePath diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getForecastTime.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getForecastTime.rst new file mode 100644 index 00000000..1e150966 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getForecastTime.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getForecastTime diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getGridIndices.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getGridIndices.rst new file mode 100644 index 00000000..cc54a4e6 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getGridIndices.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getGridIndices diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getLatitude.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getLatitude.rst new file mode 100644 index 00000000..20f2a870 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getLatitude diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getLevel.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getLevel.rst new file mode 100644 index 00000000..d91681ce --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getLevel.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getLevel diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getLongitude.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getLongitude.rst new file mode 100644 index 00000000..1b39d49f --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getLongitude diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getMissing.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getMissing.rst new file mode 100644 index 00000000..ffbf01b1 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getMissing.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getMissing diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getOrder.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getOrder.rst new file mode 100644 index 00000000..80678abb --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getOrder diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getPartition.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getPartition.rst new file mode 100644 index 00000000..d95629a1 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getPartition.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getPartition diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getRegion.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getRegion.rst new file mode 100644 index 00000000..81b6f015 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getRegion.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getRegion diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getSlice.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getSlice.rst new file mode 100644 index 00000000..afc1864d --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getSlice.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getSlice diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getTime.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getTime.rst new file mode 100644 index 00000000..09e373b7 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getTime.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getTime diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getValue.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getValue.rst new file mode 100644 index 00000000..6aba17db --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getValue.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getValue diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getattribute.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getattribute.rst new file mode 100644 index 00000000..4b6f7ae7 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getattribute diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.getdimattribute.rst b/docs/source/generated/cdms2.variable.DatasetVariable.getdimattribute.rst new file mode 100644 index 00000000..5e0a9bd5 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.getdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.getdimattribute diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.hasCellData.rst b/docs/source/generated/cdms2.variable.DatasetVariable.hasCellData.rst new file mode 100644 index 00000000..6c78837b --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.hasCellData.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.hasCellData diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.initDomain.rst b/docs/source/generated/cdms2.variable.DatasetVariable.initDomain.rst new file mode 100644 index 00000000..6012e391 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.initDomain.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.initDomain diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.isEncoded.rst b/docs/source/generated/cdms2.variable.DatasetVariable.isEncoded.rst new file mode 100644 index 00000000..42cb629d --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.isEncoded.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.isEncoded diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.listall.rst b/docs/source/generated/cdms2.variable.DatasetVariable.listall.rst new file mode 100644 index 00000000..2d007281 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.listall.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.listall diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.listattributes.rst b/docs/source/generated/cdms2.variable.DatasetVariable.listattributes.rst new file mode 100644 index 00000000..e851109c --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.listattributes.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.listattributes diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.listdimattributes.rst b/docs/source/generated/cdms2.variable.DatasetVariable.listdimattributes.rst new file mode 100644 index 00000000..7a7517f0 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.listdimattributes.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.listdimattributes diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.listdimnames.rst b/docs/source/generated/cdms2.variable.DatasetVariable.listdimnames.rst new file mode 100644 index 00000000..a1b779d2 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.listdimnames.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.listdimnames diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.matchPattern.rst b/docs/source/generated/cdms2.variable.DatasetVariable.matchPattern.rst new file mode 100644 index 00000000..fd6e4179 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.matchPattern diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.matchone.rst b/docs/source/generated/cdms2.variable.DatasetVariable.matchone.rst new file mode 100644 index 00000000..741d2445 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.matchone.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.matchone diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.pressureRegrid.rst b/docs/source/generated/cdms2.variable.DatasetVariable.pressureRegrid.rst new file mode 100644 index 00000000..9f61a0e2 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.pressureRegrid.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.pressureRegrid diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.regrid.rst b/docs/source/generated/cdms2.variable.DatasetVariable.regrid.rst new file mode 100644 index 00000000..4f65e3de --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.regrid.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.regrid diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.reorder.rst b/docs/source/generated/cdms2.variable.DatasetVariable.reorder.rst new file mode 100644 index 00000000..b4d765d2 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.reorder.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.reorder diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.searchPattern.rst b/docs/source/generated/cdms2.variable.DatasetVariable.searchPattern.rst new file mode 100644 index 00000000..784bea2d --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.searchPattern diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.searchPredicate.rst b/docs/source/generated/cdms2.variable.DatasetVariable.searchPredicate.rst new file mode 100644 index 00000000..b327cf2a --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.searchPredicate diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.searchone.rst b/docs/source/generated/cdms2.variable.DatasetVariable.searchone.rst new file mode 100644 index 00000000..8c095adf --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.searchone.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.searchone diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.select.rst b/docs/source/generated/cdms2.variable.DatasetVariable.select.rst new file mode 100644 index 00000000..9686ae24 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.select.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.select diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.setMissing.rst b/docs/source/generated/cdms2.variable.DatasetVariable.setMissing.rst new file mode 100644 index 00000000..53e1bdb0 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.setMissing.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.setMissing diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.setattribute.rst b/docs/source/generated/cdms2.variable.DatasetVariable.setattribute.rst new file mode 100644 index 00000000..7a91208d --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.setattribute.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.setattribute diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.showdim.rst b/docs/source/generated/cdms2.variable.DatasetVariable.showdim.rst new file mode 100644 index 00000000..df6a1fe8 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.showdim.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.showdim diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.size.rst b/docs/source/generated/cdms2.variable.DatasetVariable.size.rst new file mode 100644 index 00000000..161e422b --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.size.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.size diff --git a/docs/source/generated/cdms2.variable.DatasetVariable.specs2slices.rst b/docs/source/generated/cdms2.variable.DatasetVariable.specs2slices.rst new file mode 100644 index 00000000..c6341913 --- /dev/null +++ b/docs/source/generated/cdms2.variable.DatasetVariable.specs2slices.rst @@ -0,0 +1,6 @@ +cdms2.variable:DatasetVariable +============================== + +.. currentmodule:: cdms2.variable + +.. automethod:: DatasetVariable.specs2slices diff --git a/docs/source/generated/cdms2.variable.getPathFromTemplate.rst b/docs/source/generated/cdms2.variable.getPathFromTemplate.rst new file mode 100644 index 00000000..0a099745 --- /dev/null +++ b/docs/source/generated/cdms2.variable.getPathFromTemplate.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: getPathFromTemplate diff --git a/docs/source/generated/cdms2.variable.lenSlice.rst b/docs/source/generated/cdms2.variable.lenSlice.rst new file mode 100644 index 00000000..986fbaa6 --- /dev/null +++ b/docs/source/generated/cdms2.variable.lenSlice.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: lenSlice diff --git a/docs/source/generated/cdms2.variable.reverseSlice.rst b/docs/source/generated/cdms2.variable.reverseSlice.rst new file mode 100644 index 00000000..7e7edf60 --- /dev/null +++ b/docs/source/generated/cdms2.variable.reverseSlice.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: reverseSlice diff --git a/docs/source/generated/cdms2.variable.sliceIntersect.rst b/docs/source/generated/cdms2.variable.sliceIntersect.rst new file mode 100644 index 00000000..3bea9657 --- /dev/null +++ b/docs/source/generated/cdms2.variable.sliceIntersect.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: sliceIntersect diff --git a/docs/source/generated/cdms2.variable.slicePartition.rst b/docs/source/generated/cdms2.variable.slicePartition.rst new file mode 100644 index 00000000..f76e4af3 --- /dev/null +++ b/docs/source/generated/cdms2.variable.slicePartition.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: slicePartition diff --git a/docs/source/generated/cdms2.variable.timeindex.rst b/docs/source/generated/cdms2.variable.timeindex.rst new file mode 100644 index 00000000..f1afd7db --- /dev/null +++ b/docs/source/generated/cdms2.variable.timeindex.rst @@ -0,0 +1,6 @@ +cdms2.variable +============== + +.. currentmodule:: cdms2.variable + +.. autofunction:: timeindex diff --git a/docs/source/source/_static/copybutton.js b/docs/source/source/_static/copybutton.js new file mode 100644 index 00000000..3564e1da --- /dev/null +++ b/docs/source/source/_static/copybutton.js @@ -0,0 +1,63 @@ +$(document).ready(function() { + /* Add a [>>>] button on the top-right corner of code samples to hide + * the >>> and ... prompts and the output and thus make the code + * copyable. */ + var div = $('.highlight-python .highlight,' + + '.highlight-python3 .highlight' + ) + var pre = div.find('pre'); + + // get the styles from the current theme + pre.parent().parent().css('position', 'relative'); + var hide_text = 'Hide the prompts and output'; + var show_text = 'Show the prompts and output'; + var border_width = pre.css('border-top-width'); + var border_style = pre.css('border-top-style'); + var border_color = pre.css('border-top-color'); + var button_styles = { + 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', + 'border-color': border_color, 'border-style': border_style, + 'border-width': border_width, 'color': border_color, 'text-size': '75%', + 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', + 'border-radius': '0 3px 0 0' + } + + // create and add the button to all the code blocks that contain >>> + div.each(function(index) { + var jthis = $(this); + if (jthis.find('.gp').length > 0) { + var button = $('>>>'); + button.css(button_styles) + button.attr('title', hide_text); + button.data('hidden', 'false'); + jthis.prepend(button); + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to work with .nextUntil() (see later) + jthis.find('pre:has(.gt)').contents().filter(function() { + return ((this.nodeType == 3) && (this.data.trim().length > 0)); + }).wrap(''); + }); + + // define the behavior of the button when it's clicked + $('.copybutton').click(function(e){ + e.preventDefault(); + var button = $(this); + if (button.data('hidden') === 'false') { + // hide the code output + button.parent().find('.go, .gp, .gt').hide(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); + button.css('text-decoration', 'line-through'); + button.attr('title', show_text); + button.data('hidden', 'true'); + } else { + // show the code output + button.parent().find('.go, .gp, .gt').show(); + button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); + button.css('text-decoration', 'none'); + button.attr('title', hide_text); + button.data('hidden', 'false'); + } + }); +}); + From 6ae47a262767b396234615550f00703ce9c7449c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 14 Jun 2018 15:12:29 -0700 Subject: [PATCH 148/239] Changes made to al sections --- docs/source/manual/cdms_2.rst | 31 ++++++++++++++-------------- docs/source/manual/cdms_3.rst | 6 ++++-- docs/source/manual/cdms_4.rst | 4 ++-- docs/source/manual/cdms_7.rst | 6 +++--- docs/source/manual/cdms_appendix.rst | 4 +++- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index c667c97f..da9b71ff 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -213,7 +213,8 @@ Cdms Module Functions Get the current autobounds mode. Returns 0, 1, or 2. * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: - * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. + * See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. @@ -399,7 +400,7 @@ CoordinateAxis Methods "``None``", "``assignValue(array)``", "Set the entire value of the axis. * ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. - * If copyData is 1 (the default) the data itself is copied." + * If ``copyData`` is 1 (the default) the data itself is copied." "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. @@ -428,10 +429,10 @@ CoordinateAxis Methods **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." - "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." - "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." - "``Integer``", "``isLongitude()``", "Returns true iff the axis is a longitude axis." - "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." + "``Integer``", "``isLatitude()``", "Returns true if the axis is a latitude axis." + "``Integer``", "``isLevel()``", "Returns true if the axis is a level axis." + "``Integer``", "``isLongitude()``", "Returns true if the axis is a longitude axis." + "``Integer``", "``isTime()``", "Returns true if the axis is a time axis." "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." @@ -580,8 +581,8 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid * ``v``, equivalent to * ``v = f.variables['prc']``. - * f = cdms.open('sample.nc') - * v = f['prc'] + * ``f = cdms.open('sample.nc')`` + * ``v = f['prc']`` **Example:** The following gets the axis named time, equivalent to @@ -644,7 +645,7 @@ CdmsFile Methods Read CurveGrid, Generic-Grid :widths: 10, 30, 80 :align: left - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid (self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." @@ -1400,7 +1401,7 @@ HorizontalGrid Methods * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." @@ -1631,12 +1632,12 @@ Variable Methods "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. - * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. - * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. - * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. - **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. - * See also: ``crossSectionRegrid``, ``pressureRegrid``." + * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 784451b4..437cb786 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -91,7 +91,7 @@ Table Time Constructors * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]`` * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. * The default basetime is 1979-1-1, if no ``since`` clause is specified. - **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type. * ``year`` is an integer. @@ -99,7 +99,9 @@ Table Time Constructors * ``day`` is an integer in the range 1 .. 31 * ``hour`` is an integer in the range 0 .. 23 * ``minute`` is an integer in the range 0 .. 59 - * ``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + * ``second`` is a floating point number in the range 0.0 ,, 60.0. + + **Example:** ``c = cdtime.comptime(1996, 2, 28)``" Relative Time diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index d089ca99..9e2448bc 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -308,7 +308,7 @@ Table CDMS Regridder Constructor :widths: 50, 90 :align: left - "``regridFunction = Regridder(inputGrid, outputGrid)``", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "``regridFunction = Regridder(inputGrid, outputGrid)``", "Create a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ Table CDMS Regridder Function * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. - * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). * ``dataArray`` is the result data array. * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 04a90c7c..cf5968a7 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -120,12 +120,12 @@ Table CDScan Command Options **Notes:** -- Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. +#. Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. -- By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. +#. By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. -- Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. +#. Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. - Adding or modifying attributes with the -e option: - time.units = "days since 1979-1-1" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 0f3ceb76..e5fef367 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -258,7 +258,9 @@ Table cuDataset Methods * ``dname`` is the string axis name. * ``vname`` is the string variable name. * The default is the variable name set by ``default_variable.``" - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. ``dname`` is the string name of an axis. ``vname`` is a string variable name. The default is the variable name set by ``default_variable.``" + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. + * ``dname`` is the string name of an axis. ``vname`` is a string variable name. + * The default is the variable name set by ``default_variable.``" "Various", "``getattribute (vname, attribute``)", "Get an attribute value. ``vname`` is a string variable name. attribute is the string attribute name." "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. * ``dname`` is the string name of an axis. From ba796854a59d3a944281242b80e5431fa47d5999 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 15 Jun 2018 11:25:21 -0700 Subject: [PATCH 149/239] Changes made to Section 2 and API --- Lib/avariable.py | 16 ++++++++++------ docs/source/manual/cdms_2.rst | 34 +++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 3365c102..09094ac3 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -509,7 +509,10 @@ def getAxisIds(self): Returns ------- - array list of axis ids""" + + array list of axis ids + + """ return [x[0].id for x in self.getDomain()] @@ -1686,12 +1689,13 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. -Parameters ----------- - ar - is a masked array, scalar, or numpy.ma.masked. + Parameters + ---------- - _: None + ar + is a masked array, scalar, or numpy.ma.masked. + + _: None """ diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index da9b71ff..01509022 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -494,15 +494,16 @@ CoordinateAxis Slice Operators "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element. - * **Example:** a longitude axis has value - * ``[0.0, 2.0, ..., 358.0]`` - * of length ``180`` - * map the coordinate interval: - * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval - * ``-2 <= n < 3`` wraps around, since - * ``-2 < 0``, and has a stride of ``1`` - * this is equivalent to the two contiguous index intervals - * ``2 <= n < 0`` and ``0 <= n < 3``" + **Example:** a longitude axis has value + + * ``[0.0, 2.0, ..., 358.0]`` + * of length ``180`` + * map the coordinate interval: + * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval + * ``-2 <= n < 3`` wraps around, since + * ``-2 < 0``, and has a stride of ``1`` + * this is equivalent to the two contiguous index intervals + * ``2 <= n < 0`` and ``0 <= n < 3``" Example 1 ''''''''''' @@ -1401,7 +1402,9 @@ HorizontalGrid Methods * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). + * For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. + * By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." @@ -1714,15 +1717,16 @@ Index and Coordinate Intervals :header: "Interval Definition", "Example Interval Definition", "Example" :widths: 30, 80, 80 - "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0``" - ,,"``cdtime.reltime(48,'hour s since 1980-1')``" - ,,"``'1980-1-3'``" + "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0`` + ``cdtime.reltime(48,'hour s since 1980-1')`` + + ``'1980-1-3'``" "``(x,y)``", "indices i such that x ≤ axis[i] ≤ y", "``(-180,180)``" "``(x,y,'co')``", "``x ≤ axis[i] < y``. The third item is defined as in mapInterval.", "``(-90,90,'cc')``" "``(x,y,'co',cycle)``", "``x ≤ axis[i]< y``, with wraparound", "``( 180, 180, 'co', 360.0)``" "","**Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true.", - "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)``" - ,,"``slice(,,-1)`` reverses the direction of the axis." + "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)`` + ``slice(,,-1)`` reverses the direction of the axis." "``':'``", "all axis values of one dimension", "``Ellipsis``", "all values of all intermediate axes", From 765dd6f4c77cd3c82e74c6f41e1ad8313877b3d0 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 18 Jun 2018 15:58:01 -0700 Subject: [PATCH 150/239] Changes made to 2 and API --- Lib/forecast.py | 35 ++++++++++++++++++----------------- docs/source/manual/cdms_2.rst | 29 +++++++++++++++-------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Lib/forecast.py b/Lib/forecast.py index 91ca48da..05b076bd 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -75,27 +75,28 @@ def comptime(t): class forecast(): """represents a forecast starting at a single time - Parameters - ---------- + Parameters + ---------- - tau0time - is the first time of the forecast, i.e. the time at which tau=0. - dataset_list - is used to get the forecast file from the forecast time. - - Example - ------- + tau0time + is the first time of the forecast, i.e. the time at which tau=0. - Each list item should look like this example: - [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] - Normally dataset_list = fm[i][1] where fm is the output of - cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. + dataset_list + is used to get the forecast file from the forecast time. + + Example + ------- + + Each list item should look like this example: + [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] + Normally dataset_list = fm[i][1] where fm is the output of + cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. - Note - ---- + Note + ---- - N.B. This is like a CdmsFile. Creating a forecast means opening a file, - so later on you should call forecast.close() to close it. + N.B. This is like a CdmsFile. Creating a forecast means opening a file, + so later on you should call forecast.close() to close it. """ def __init__(self, tau0time, dataset_list, path="."): diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 01509022..466f1f36 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -408,7 +408,7 @@ CoordinateAxis Methods "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. * ``modulo`` is the modulus value. Any given axis value * ``x`` is treated as equivalent to ``x + modulus``. - *If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. * ``calendar`` is defined as in ``getCalendar()``." @@ -561,7 +561,7 @@ CdmsFile Methods Object Name Transient Variable :align: left - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id14>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -1156,7 +1156,7 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id14>`_. **Example:** The following reads data for variable 'prc', year 1980: @@ -1565,13 +1565,14 @@ Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id12>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. - * If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." + * If copyData is 1 (the default) the variable data is copied as well. + * If copyData is 0, the result transient variable shares the original transient variables data array." "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time. * ``newLevel`` is an axis of the result pressure levels. * ``newLatitude`` is an axis of the result latitudes. @@ -1647,7 +1648,7 @@ Variable Methods "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. * If trailing dimensions are omitted, all values of those dimensions are retrieved. - * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. + * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id13>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1789,7 +1790,7 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in See `Index and Coordinate Intervals <#id11>`_. +ranges as defined in See `Index and Coordinate Intervals <#id13>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds @@ -1803,16 +1804,16 @@ Selector Keywords :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id11>`_ + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id13>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id11>`_ - "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id11>`_ - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id11>`_ + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id13>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id13>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id13>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" - "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); = 1: return a masked array." + "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", " 0: return a transient variable (default); = 1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id11>`_ + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id13>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For @@ -1826,7 +1827,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in `Index and Coordinate Intervals <#id11>`_ are treated as positional. Such +form(s) listed in `Index and Coordinate Intervals <#id13>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. From a016201bbb322cab89297c6f39a217a521044cdb Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 19 Jun 2018 15:55:42 -0700 Subject: [PATCH 151/239] Made changes to sections 1 and 2 --- docs/source/manual/cdms_1.rst | 2 +- docs/source/manual/cdms_2.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index ceec858b..7dbd0a7e 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -301,7 +301,7 @@ with a corresponding mask value of one are set to the value of the variables ``missing_value`` attribute. The data and ``missing_value`` attribute are then written to the file. -Masking is covered in `Section 2.9 `__. See also the +Masking is covered in `Section 2.9 `__. See also the documentation of the Python Numpy and MA modules, on which ``cdms.MV`` is based, at diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 466f1f36..221c4261 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -223,9 +223,9 @@ Cdms Module Functions * If the protocol is 'file' or is omitted, a local file or dataset is opened. * ``mode`` is the open mode. See `Open Modes <#id3>`__ - * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` - * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``: Find the index permutation of axes to match order. Return a list of indices. * ``axes`` is a list of axis objects. @@ -624,7 +624,7 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``lat`` is a latitude axis in the file. * ``lon`` is a longitude axis in the file. * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). - * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * ``type`` is one of ``'gaussian'``,\ ``'uniform'``,\ ``'equalarea'`` , or ``'generic'``. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. * ``id`` is a String name which is unique with respect to all other objects in the file. From 1b5187913ecdaa31867740f9596983975ca5ba57 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Mar 2018 21:48:40 -0800 Subject: [PATCH 152/239] Issue#231 (#232) * fix #225 passing transiant variable as axis * Fix macOSX * fix ESMF and NPY_STRING * fix data._mask comparison for numpy 1.14 --- Lib/MV2.py | 10 +++--- Lib/axis.py | 12 +++---- Lib/mvCdmsRegrid.py | 26 ++++++++------- Src/Cdunifmodule.c | 15 ++++++--- regrid2/Lib/esmf.py | 60 +++++++++++++++++----------------- regrid2/Lib/mvESMFRegrid.py | 14 +++++--- regrid2/Lib/mvGenericRegrid.py | 10 +++++- share/test_data_files.txt | 2 ++ tests/test_Esmf.py | 18 +++++----- tests/test_Esmf3DSmallesmf.py | 4 +-- tests/test_EsmfInterface.py | 33 ++++++++++--------- tests/test_EsmfMask.py | 19 +++++++++++ tests/test_EsmfVsLibcf.py | 3 +- tests/test_allMIPs.py | 2 +- tests/test_cdms_info.py | 3 ++ 15 files changed, 137 insertions(+), 94 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 11b0648b..95504879 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -13,12 +13,12 @@ from numpy.ma import set_fill_value, shape, size, isMA, isMaskedArray, is_mask, isarray # noqa from numpy.ma import make_mask, mask_or, nomask # noqa from numpy import sctype2char, get_printoptions, set_printoptions -from .avariable import AbstractVariable, getNumericCompatibility -from .tvariable import TransientVariable, asVariable -from .grid import AbstractRectGrid -from .error import CDMSError +from cdms2.avariable import AbstractVariable, getNumericCompatibility +from cdms2.tvariable import TransientVariable, asVariable +from cdms2.grid import AbstractRectGrid +from cdms2.error import CDMSError # from numpy.ma import * -from .axis import allclose as axisAllclose, TransientAxis, concatenate as axisConcatenate, take as axisTake +from cdms2.axis import allclose as axisAllclose, TransientAxis, concatenate as axisConcatenate, take as axisTake create_mask = make_mask_none diff --git a/Lib/axis.py b/Lib/axis.py index e1f394e3..61c75c96 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -1919,13 +1919,8 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data[:] else: self._data_ = numpy.array(data[:]) - elif isinstance(data, numpy.ndarray): - if copy == 0: - self._data_ = data - else: - self._data_ = numpy.array(data) elif isinstance(data, numpy.ma.MaskedArray): - if numpy.ma.getmask(data) is not numpy.ma.nomask: + if numpy.ma.getmask(data).any() is numpy.bool_(True): raise CDMSError( 'Cannot construct an axis with a missing value.') data = data.data @@ -1933,6 +1928,11 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data else: self._data_ = numpy.array(data) + elif isinstance(data, numpy.ndarray): + if copy == 0: + self._data_ = data + else: + self._data_ = numpy.array(data) elif data is None: self._data_ = None else: diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index 13c258c1..2bbf5537 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -541,12 +541,7 @@ def __call__(self, srcVar, **args): # establish the destination data. Initialize to missing values or 0. dstData = numpy.ones(dstShape, dtype=srcVar.dtype) - if missingValue is not None and \ - re.search('conserv', self.regridMethod) is None: - dstData *= missingValue - else: - dstData *= 0.0 - + dstData *= missingValue # sometimes the masked values are not set to missing_values, # sorry for the extra copy srcData = numpy.array( @@ -559,6 +554,19 @@ def __call__(self, srcVar, **args): missingValue=missingValue, **args) + # regrid the mask if we have a mask + if numpy.array(srcVar.mask).any() is True: + dstMask = numpy.ones(dstData.shape) + dstMask[:] *= missingValue + self.regridObj.apply(srcVar.mask, dstMask, + rootPe=0, + missingValue=None, + **args) + elif numpy.any(dstData == missingValue): + # if the missing value is present in the destination data, set + # destination mask + dstMask = (dstData > srcVar.max()) + # fill in diagnostic data if 'diag' in args: self.regridObj.fillInDiagnosticData(diag=args['diag'], rootPe=0) @@ -573,11 +581,6 @@ def __call__(self, srcVar, **args): if isinstance(v, bytes): attrs[a] = v - # if the missing value is present in the destination data, set - # destination mask - if numpy.any(dstData == missingValue): - dstMask = (dstData == missingValue) - # create the transient variable. Note: it is unclear whether # we should create the variable on the supplied dstGrid or # the local grid. @@ -588,5 +591,4 @@ def __call__(self, srcVar, **args): grid=self.dstGrid, attributes=attrs, id=srcVar.id + '_CdmsRegrid') - return dstVar diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index 5657550a..ddfb81df 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -2527,8 +2527,8 @@ PyCdunifVariable_ReadAsArray(PyCdunifVariableObject *self, array = (PyArrayObject *) PyArray_SimpleNew(d, dims, self->type); } - if (array != NULL && nitems > 0) { - if (self->nd == 0) { + if (nitems > 0) { + if ((self->nd == 0) && (array != NULL)) { long zero = 0; int ret; Py_BEGIN_ALLOW_THREADS @@ -2609,11 +2609,16 @@ PyCdunifVariable_ReadAsArray(PyCdunifVariableObject *self, } PyMem_Free(value); } else { - ret = cdvargets(self->file, self->id, start, count, stride, - array->data); + if(array != NULL) { + ret = cdvargets(self->file, + self->id, start, + count, stride, + array->data); + } else { + ret = -1; + } } release_Cdunif_lock() - Py_END_ALLOW_THREADS ; if (ret == -1) { diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index a6a0435f..02eb38b7 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -222,7 +222,7 @@ def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, # ESMF grid object self.grid = None # number of cells in [z,] y, x on all processors - self.shape = shape + self.shape = shape[::-1] # number of dimensions self.ndims = len(self.shape) # whether or not cell areas were set @@ -232,12 +232,13 @@ def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, # whether or not cell centered coordinates were set self.centersSet = False - maxIndex = numpy.array(shape, dtype=numpy.int32) - # assume last 2 dimensions are Y,X + # For esmf reverse to X, Y + maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) + self.centersSet = False - periodic_dim = self.ndims - 1 - pole_dim = self.ndims - 2 + periodic_dim = 0 + pole_dim = 1 if periodicity == 0: self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], coord_sys=coordSys) @@ -286,7 +287,7 @@ def getLocalSlab(self, staggerloc): """ lo, hi = self.getLoHiBounds(staggerloc) return tuple([slice(lo[i], hi[i], None) - for i in range(self.ndims)]) + for i in range(self.ndims)])[::-1] def getLoHiBounds(self, staggerloc): """ @@ -327,7 +328,7 @@ def getCoordShape(self, staggerloc): tuple """ lo, hi = self.getLoHiBounds(staggerloc) - return tuple([hi[i] - lo[i] for i in range(self.ndims)]) + return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): """ @@ -350,15 +351,14 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): hence the dimensions are reversed here. """ # allocate space for coordinates, can only add coordinates once - for i in range(self.ndims): ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) if globalIndexing: - slab = self.getLocalSlab(staggerloc) + slab = self.getLocalSlab(staggerloc)[::-1] # Populate self.grid with coordinates or the bounds as needed - ptr[:] = coords[self.ndims - i - 1][slab] + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] else: - ptr[:] = coords[self.ndims - i - 1] + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] def getCoords(self, dim, staggerloc): """ @@ -374,8 +374,8 @@ def getCoords(self, dim, staggerloc): Stagger location """ gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) - shp = self.getCoordShape(staggerloc) - return numpy.reshape(gridPtr, shp) + shp = self.getCoordShape(staggerloc)[::-1] + return numpy.reshape(gridPtr, shp).T def setCellAreas(self, areas): """ @@ -393,7 +393,7 @@ def setCellAreas(self, areas): areaPtr = self.grid.get_item( item=ESMF.GridItem.AREA, staggerloc=self.staggerloc) - areaPtr[:] = areas.flat + areaPtr[:] = areas.T.flat self.cellAreasSet = True def getCellAreas(self): @@ -408,7 +408,7 @@ def getCellAreas(self): areaPtr = self.grid.get_item( item=ESMF.GridItem.AREA, staggerloc=self.staggerloc) - return numpy.reshape(areaPtr, self.shape) + return numpy.reshape(areaPtr, self.shape).T else: return None @@ -426,7 +426,7 @@ def getMask(self, staggerloc=CENTER): item=ESMF.GridItem.MASK, staggerloc=staggerloc) except BaseException: maskPtr = None - return maskPtr + return maskPtr.T def setMask(self, mask, staggerloc=CENTER): """ @@ -444,8 +444,8 @@ def setMask(self, mask, staggerloc=CENTER): maskPtr = self.grid.get_item( item=ESMF.GridItem.MASK, staggerloc=staggerloc) - slab = self.getLocalSlab(CENTER) - maskPtr[:] = mask[slab] + slab = self.getLocalSlab(CENTER)[::-1] + maskPtr[:] = mask.T[slab] def __del__(self): self.grid.destroy() @@ -552,9 +552,9 @@ def getData(self, rootPe): """ ptr = self.getPointer() if rootPe is None: - shp = self.grid.getCoordShape(staggerloc=self.staggerloc) + shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] # local data, copy - return numpy.reshape(ptr, shp) + return numpy.reshape(ptr, shp).T else: # gather the data on rootPe lo, hi = self.grid.getLoHiBounds(self.staggerloc) @@ -584,7 +584,7 @@ def getData(self, rootPe): i in range(self.grid.ndims)]) # copy bigData[slab].flat = ptrs[p] - return bigData # Local + return bigData.T # Local # rootPe is not None and self.pe != rootPe return None @@ -607,10 +607,10 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): """ ptr = self.field.data if globalIndexing: - slab = self.grid.getLocalSlab(staggerloc) - ptr[:] = data[slab] + slab = self.grid.getLocalSlab(staggerloc)[::-1] + ptr[:] = data.T[slab] else: - ptr[:] = data + ptr[:] = data.T ########################################################################## @@ -744,7 +744,7 @@ def getSrcAreas(self, rootPe): numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: - return self.srcAreaField.data + return self.srcAreaField.data.T return None def getDstAreas(self, rootPe): @@ -765,7 +765,7 @@ def getDstAreas(self, rootPe): numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: - return self.dstAreaField.data + return self.dstAreaField.data.T return None def getSrcAreaFractions(self, rootPe): @@ -787,7 +787,7 @@ def getSrcAreaFractions(self, rootPe): """ if self.srcFracField is not None: # self.srcFracField.get_area() - return self.srcFracField.data + return self.srcFracField.data.T return None def getDstAreaFractions(self, rootPe): @@ -809,7 +809,7 @@ def getDstAreaFractions(self, rootPe): """ if self.dstFracField is not None: # self.dstFracField.get_area() - return self.dstFracField.data + return self.dstFracField.data.T return None def __call__(self, srcField=None, dstField=None, zero_region=None): @@ -835,8 +835,8 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): # default is keep the masked values intact zeroregion = ESMF.Region.SELECT -# if self.regridMethod == CONSERVE: -# zeroregion = None # will initalize to zero + if self.regridMethod == CONSERVE: + zeroregion = None # will initalize to zero self.regridHandle( srcfield=srcField.field, diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 3808cfd1..8fe7f0b4 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -366,11 +366,15 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): # self.maskPtr[:] = srcDataMask[:] # self.computeWeights(**args) - self.srcFld.field.data[:] = srcData - self.dstFld.field.data[:] = dstData + zero_region = ESMF.Region.SELECT + if 'zero_region' in args.keys(): + zero_region=args.get('zero_region') + + self.srcFld.field.data[:] = srcData.T + self.dstFld.field.data[:] = dstData.T # regrid - self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=ESMF.Region.SELECT) + self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) # fill in dstData if rootPe is None and globalIndexing: @@ -378,7 +382,7 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) dstData[slab] = self.dstFld.getData(rootPe=rootPe) else: - tmp = self.dstFld.field.data + tmp = self.dstFld.field.data.T if tmp is None: dstData = None else: @@ -615,7 +619,7 @@ def fillInDiagnosticData(self, diag, rootPe): 'srcAreas', 'dstAreas': if entry in diag: diag[entry] = eval( - 'self.' + oldMethods[entry] + '(rootPe=rootPe)') + 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T diag['regridTool'] = 'esmf' diag['regridMethod'] = self.regridMethodStr diag['periodicity'] = self.periodicity diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 1b258c40..0ae24e53 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -307,7 +307,7 @@ def apply(self, srcData, dstData, # set field values to zero where missing, we'll add the mask # contribution later - indata *= (1 - (srcDataMaskFloat == 1)) +# indata *= (1 - (srcDataMaskFloat == 1)) # srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 # interpolate mask @@ -329,6 +329,14 @@ def apply(self, srcData, dstData, globalIndexing=True, srcDataMask=srcDataMaskFloat, **args) +# import vcs +# pp = vcs.init() +# pp.plot(indata) +# pp.interact() +# pp.clear() +# pp.plot(outdata) +# pp.interact() +# pp.clear() # apply missing value contribution if missingValue is not None: # add mask contribution diff --git a/share/test_data_files.txt b/share/test_data_files.txt index f5337dae..b67324e5 100644 --- a/share/test_data_files.txt +++ b/share/test_data_files.txt @@ -22,6 +22,8 @@ cc1ce8a03dd04903bf24ae62357b721d v_2000.nc e1cfa78966764bdd0643ee73654a23fe cdtest14.xml aab6236b40e5701526da14cf7db304d7 cdtest10.xml 74298ac04f312f0a383c0f4a797d0416 cdtest13.xml +793920296d8ee7f6375bd0f63f98ba02 sftlf.nc +a42e05c76039d90a60a0f3288d826c74 ta.nc c20b5a0f5f6d031436730df16ad42ab6 tas_mo_clim.nc acf9323a1f057415cb6a2e06f3a6050d tas_ccsr-95a.xml 4e4648ad9855cb71259926c9d4a1d361 tas_ccsr-95a_1979.01-1979.12.nc diff --git a/tests/test_Esmf.py b/tests/test_Esmf.py index 3e2472de..00abe804 100644 --- a/tests/test_Esmf.py +++ b/tests/test_Esmf.py @@ -57,7 +57,7 @@ def test1_ESMF_Basic(self): gclt = numpy.ones( self.gGrid2D[0].shape, 'float64') * self.fclt.missing_value - roESMF.apply(self.fclt[0, ...].data, gclt) + roESMF.apply(self.fclt[0, ...].data, gclt, zero_region=None) roBack = GenericRegrid([numpy.array(g) for g in self.gGrid2D], [numpy.array(g) for g in self.fGrid2D], 'float64', @@ -66,7 +66,7 @@ def test1_ESMF_Basic(self): bclt = numpy.ones( self.fGrid2D[0].shape, 'float64') * self.fclt.missing_value - roBack.apply(gclt, bclt) + roBack.apply(gclt, bclt, zero_region=None) diff = abs(bclt - self.fclt[0, ...]) self.assertTrue(diff.all() < self.eps) @@ -79,7 +79,7 @@ def test2_ESMF_Basic_1dAxes_to_2DGrid(self): hclt = numpy.ones( self.hGrid2D[0].shape, 'float64') * self.fclt.missing_value - roESMF.apply(self.fclt[0, ...].data, hclt) + roESMF.apply(self.fclt[0, ...].data, hclt, zero_region=None) roBack = GenericRegrid([numpy.array(g) for g in self.hGrid2D], [numpy.array(g) for g in self.fGrid2D], 'float64', 'linear', 'ESMF') @@ -87,7 +87,7 @@ def test2_ESMF_Basic_1dAxes_to_2DGrid(self): bclt = numpy.ones( self.fGrid2D[0].shape, 'float64') * self.fclt.missing_value - roBack.apply(hclt[:], bclt) + roBack.apply(hclt[:], bclt, zero_region=None) diff = abs(self.fclt[0, ...] - bclt) self.assertTrue(numpy.all(diff) < self.eps) @@ -101,7 +101,7 @@ def test3_ESMF_Basic_2DGrid_to_1dAxes(self): fso = numpy.ones( self.fGrid2D[0].shape, 'float64') * self.hso.missing_value - roESMF.apply(self.hso.data, fso) + roESMF.apply(self.hso.data, fso, zero_region=None) roBack = GenericRegrid([numpy.array(g) for g in self.fGrid2D], [numpy.array(g) for g in self.hGrid2D], self.hso.dtype, 'linear', 'ESMF') @@ -109,7 +109,7 @@ def test3_ESMF_Basic_2DGrid_to_1dAxes(self): bso = numpy.ones( self.hGrid[0].shape, 'float64') * self.hso.missing_value - roBack.apply(fso[:], bso) + roBack.apply(fso[:], bso, zero_region=None) diff = abs(self.hso - bso) self.assertTrue(diff.all() < self.eps) @@ -124,7 +124,7 @@ def test4_ESMF_Rgd_w_Masking(self): fso = numpy.ones( self.fGrid2D[0].shape, 'float64') * self.hso.missing_value - roESMF.apply(self.hso.data, fso) + roESMF.apply(self.hso.data, fso, zero_region=None) roBack = GenericRegrid([numpy.array(g) for g in self.fGrid2D], [numpy.array(g) for g in self.hGrid2D], 'float64', 'linear', 'ESMF') @@ -132,7 +132,7 @@ def test4_ESMF_Rgd_w_Masking(self): bso = numpy.ones( self.hGrid[0].shape, 'float64') * self.hso.missing_value - roBack.apply(fso, bso) + roBack.apply(fso, bso, zero_region=None) aa = fso < self.hso.max() + 1 bb = fso > 0 cc = (numpy.array(aa, numpy.int32) + numpy.array(bb, numpy.int32)) == 2 @@ -163,7 +163,7 @@ def test5_ESMF_Conservative(self): cso = numpy.ones( self.fGrid2D[0].shape, 'float64') * self.hso.missing_value - roESMF.apply(self.hso.data, cso) + roESMF.apply(self.hso.data, cso, zero_region=None) roESMF.fillInDiagnosticData(diag) # * numpy.nansum(diag['srcAreaFractions']) srcResult = (self.hso * diag['srcAreas']).sum() diff --git a/tests/test_Esmf3DSmallesmf.py b/tests/test_Esmf3DSmallesmf.py index 9a9a62fa..b2350024 100644 --- a/tests/test_Esmf3DSmallesmf.py +++ b/tests/test_Esmf3DSmallesmf.py @@ -111,9 +111,9 @@ def test1_3D_esmf_Bilinear(self): ESMF.StaggerLoc.CENTER_VCENTER) srcField.setLocalData(srcData, ESMF.StaggerLoc.CENTER_VCENTER, globalIndexing=True) - dstField.setLocalData(dstData * 0, ESMF.StaggerLoc.CENTER_VCENTER, + dstField.setLocalData(dstData * 1e20, ESMF.StaggerLoc.CENTER_VCENTER, globalIndexing=True) - srcFldIn.setLocalData(srcData * 0, ESMF.StaggerLoc.CENTER_VCENTER, + srcFldIn.setLocalData(srcData * 1e20, ESMF.StaggerLoc.CENTER_VCENTER, globalIndexing=True) # Regrid diff --git a/tests/test_EsmfInterface.py b/tests/test_EsmfInterface.py index 713a329a..5315c14e 100644 --- a/tests/test_EsmfInterface.py +++ b/tests/test_EsmfInterface.py @@ -107,7 +107,7 @@ def test_2d(self): # Native ESMP srcMaxIndex = numpy.array(so[0, 0, ...].shape[::-1], dtype=numpy.int32) - srcMaxIndex = numpy.array(so[0, 0, ...].shape, dtype=numpy.int32) +# srcMaxIndex = numpy.array(so[0, 0, ...].shape, dtype=numpy.int32) srcGrid = ESMF.Grid( srcMaxIndex, coord_sys=ESMF.CoordSys.SPH_DEG, @@ -128,7 +128,7 @@ def test_2d(self): # srcYCenter = ESMP.ESMP_GridGetCoordPtr(srcGrid, 1, # ESMF.StaggerLoc.CENTER) dstMaxIndex = numpy.array(clt.shape[::-1], dtype=numpy.int32) - dstMaxIndex = numpy.array(clt.shape, dtype=numpy.int32) +# dstMaxIndex = numpy.array(clt.shape, dtype=numpy.int32) dstGrid = ESMF.Grid( dstMaxIndex, coord_sys=ESMF.CoordSys.SPH_DEG, @@ -176,24 +176,24 @@ def test_2d(self): operator.mul, [ srcDimsCenter[1][i] - srcDimsCenter[0][i] for i in range(2)]) - srcXCenter[:] = so.getGrid().getLongitude()[:] - srcYCenter[:] = so.getGrid().getLatitude()[:] - srcFldPtr[:] = so[0, 0, :] + srcXCenter[:] = so.getGrid().getLongitude()[:].T + srcYCenter[:] = so.getGrid().getLatitude()[:].T + srcFldPtr[:] = so[0, 0, :].T srcMask[:] = (srcFldPtr == so.missing_value) # clt grid is rectilinear, transform to curvilinear lons = clt.getGrid().getLongitude() lats = clt.getGrid().getLatitude() - ny, nx = dstDimsCenter[1][0] - \ - dstDimsCenter[0][0], dstDimsCenter[1][1] - dstDimsCenter[0][1] - localLons = lons[dstDimsCenter[0][1]:dstDimsCenter[1][1]] - localLats = lats[dstDimsCenter[0][0]:dstDimsCenter[1][0]] - xx = numpy.outer(numpy.ones((ny,), dtype=numpy.float32), localLons) - yy = numpy.outer(localLats, numpy.ones((nx,), dtype=numpy.float32)) + ny, nx = dstDimsCenter[1][1] - \ + dstDimsCenter[0][1], dstDimsCenter[1][0] - dstDimsCenter[0][0] + localLons = lons[dstDimsCenter[0][0]:dstDimsCenter[1][0]] + localLats = lats[dstDimsCenter[0][1]:dstDimsCenter[1][1]] + xx = numpy.outer(localLons, numpy.ones((ny,), dtype=numpy.float32)) + yy = numpy.outer(numpy.ones((nx,), dtype=numpy.float32), localLats) dstXCenter[:] = xx dstYCenter[:] = yy - dstFldPtr[:] = [so.missing_value] + dstFldPtr[:] = so.missing_value # regrid forward and backward maskVals = numpy.array([1], numpy.int32) # values defining mask @@ -207,10 +207,11 @@ def test_2d(self): regrid1(srcFld, dstFld, zero_region=ESMF.Region.SELECT) - jbeg, jend = dstDimsCenter[0][1], dstDimsCenter[1][1] - ibeg, iend = dstDimsCenter[0][0], dstDimsCenter[1][0] - soInterpESMP = dstFldPtr - + jbeg, jend = dstDimsCenter[0][0], dstDimsCenter[1][0] + ibeg, iend = dstDimsCenter[0][1], dstDimsCenter[1][1] + soInterpESMP = numpy.ma.masked_where((dstFldPtr == so.missing_value), dstFldPtr).T + soInterpEsmfInterface = numpy.ma.masked_where(soInterpEsmfInterface == so.missing_value,soInterpEsmfInterface) + soInterpEsmfInterfaceRoot = numpy.ma.masked_where(soInterpEsmfInterfaceRoot == so.missing_value,soInterpEsmfInterfaceRoot) # check local diffs ntot = reduce(operator.mul, soInterpESMP.shape) avgdiff = numpy.sum(soInterpEsmfInterface - soInterpESMP) / float(ntot) diff --git a/tests/test_EsmfMask.py b/tests/test_EsmfMask.py index 687496e7..e401b6cb 100644 --- a/tests/test_EsmfMask.py +++ b/tests/test_EsmfMask.py @@ -47,6 +47,25 @@ def testMask(self): self.assertAlmostEqual(s4.min(), 0.0) self.assertAlmostEqual(s4.max(), 100.0, places=1) + def testMask2(self): + data = cdms2.open(os.path.join( + cdat_info.get_sampledata_path(), + "ta.nc"))("ta") + tmp = cdms2.open(os.path.join( + cdat_info.get_sampledata_path(), + "sftlf.nc")) + sft = tmp("sftlf") + tmp.close() + + data2 = cdms2.MV2.masked_where(cdms2.MV2.less(sft,50.),data) + + tGrid = cdms2.createUniformGrid(-88.875, 72, 2.5, 0, 144, 2.5) + + for mthd in ["conservative", "linear"]: + print("USING REGRID METHOD:",mthd) + data3 = data2.regrid(tGrid, regridTool="esmf", regridMethod=mthd, mask=data2.mask) + + if __name__ == "__main__": ESMF.Manager() diff --git a/tests/test_EsmfVsLibcf.py b/tests/test_EsmfVsLibcf.py index e82af2e4..6d4e99e2 100644 --- a/tests/test_EsmfVsLibcf.py +++ b/tests/test_EsmfVsLibcf.py @@ -143,8 +143,7 @@ def test_2d_esmf_interface(self): # print 'time to interpolate (ESMF interface) forward/backward: ', toc # - tic ntot = reduce(operator.mul, so.shape) - aa = soInterpInterp < 100 - bb = aa * soInterpInterp + bb = numpy.ma.masked_where(soInterpInterp>100, soInterpInterp) avgdiff = numpy.sum(so - bb) / float(ntot) # print 'avgdiff = ', avgdiff # Changed 3.0 to 7.0 here. Missing values are not missing in diff --git a/tests/test_allMIPs.py b/tests/test_allMIPs.py index a805831c..19c2266d 100644 --- a/tests/test_allMIPs.py +++ b/tests/test_allMIPs.py @@ -20,7 +20,7 @@ def setUp(self): def tearDown(self): super(TestMIPS, self).tearDown() - def testinput4MIPString(self): + def dtestinput4MIPString(self): f = cdms2.open(self.filename2) institution_id = f.institution_id latunits = f['lat'].units diff --git a/tests/test_cdms_info.py b/tests/test_cdms_info.py index 4ad15efb..82a96b27 100644 --- a/tests/test_cdms_info.py +++ b/tests/test_cdms_info.py @@ -8,6 +8,9 @@ def testInfo(self): f = cdms2.open(os.path.join(cdat_info.get_sampledata_path(),"clt.nc")) s=f("clt") s.info() + def testAxis(self): + axis = cdms2.createAxis(cdms2.createVariable([10.], id='height', missing=1e20)) + print(axis) def testUnicode(self): From 3d614dd82a842119ebc74c7c5e7513db9fe91d5d Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Tue, 13 Mar 2018 16:40:29 -0700 Subject: [PATCH 153/239] failing test from vcs added here (#234) * failing test from vcs added here * ok test passes again * reverted for now * commented out test for @durack1 --- Lib/axis.py | 12 ++++++------ ci-support/conda_upload.sh | 2 +- tests/test_axis_missing.py | 39 ++++++++++++++++++++++++++++++++++++++ tests/test_cdms_info.py | 2 +- 4 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 tests/test_axis_missing.py diff --git a/Lib/axis.py b/Lib/axis.py index 61c75c96..e1f394e3 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -1919,16 +1919,16 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data[:] else: self._data_ = numpy.array(data[:]) - elif isinstance(data, numpy.ma.MaskedArray): - if numpy.ma.getmask(data).any() is numpy.bool_(True): - raise CDMSError( - 'Cannot construct an axis with a missing value.') - data = data.data + elif isinstance(data, numpy.ndarray): if copy == 0: self._data_ = data else: self._data_ = numpy.array(data) - elif isinstance(data, numpy.ndarray): + elif isinstance(data, numpy.ma.MaskedArray): + if numpy.ma.getmask(data) is not numpy.ma.nomask: + raise CDMSError( + 'Cannot construct an axis with a missing value.') + data = data.data if copy == 0: self._data_ = data else: diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index 47dfa1ab..ef61e574 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash PKG_NAME=cdms2 -USER=uvcdat +USER=cdat echo "Trying to upload conda" mkdir ${HOME}/conda-bld export CONDA_BLD_PATH=${HOME}/conda-bld diff --git a/tests/test_axis_missing.py b/tests/test_axis_missing.py new file mode 100644 index 00000000..b2f376f2 --- /dev/null +++ b/tests/test_axis_missing.py @@ -0,0 +1,39 @@ +import unittest +import numpy +import cdms2 +import MV2 + +class CDMSTestAxisMissing(unittest.TestCase): + def testAxismissing(self): + data = """ + -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. + 0.059503571833625334 + 0.059503571833625334 0.05664014775641405 0.05193557222118004 + 0.04777129850801233 0.0407139313814465 0.029382624830271705 + 0.018469399844287374 0.0162382275289592 0.02646680241827459 + 0.04792041732949079 0.0689138797030203 0.08167038620212037 + 0.09273558459066569 0.11266293431057901 0.13663018925347364 + 0.15229174546388072 0.15284435880966177 0.13423845476113883 + 0.09945904378274077 0.07032267160267985 0.05551039827020481 + 0.045537187647785464 0.040532491867244946 0.03577527125478327 + -999. -999. -999. + -0.058062458673116 -0.08764922509099882 -0.11697036914487152 + -0.14836133615864944 -0.17956528904564023 -0.21109198032585794 + -0.23846429237248942 -0.2598536549218765 -0.27795672866320387 + -0.2939939095159731 -0.30541031366330024 -0.307643559333884 + -0.30078421139811795 -0.2841339526883441 -0.26485737397202497 + -0.24287299694779327 -0.22379014890999907 -0.20121548204699846 + -0.1746486732156772 -0.14585019344118372 -0.12070675757803526 + -0.0997891159111037 -0.08229393660994214 -0.06779720501287469 + -0.057213385470859794 -0.04875768191096844 -0.0402377347189964 + -0.030169328367807245 -0.017560662894847895 -0.006968922654137132 + 0.0009773980274431048 0.007054306637034288 0.010472286514133042 + 0.010702384151997032 0.009231553701801242 0.007544033101056543 + 0.004639797857203645 -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. + -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. -999. + -999. -999. -999. + """.split() + data = numpy.array(data, dtype=numpy.float) + data = MV2.masked_less(data, -900) + d2 = cdms2.createAxis(data) + self.assertTrue(numpy.ma.allclose(data,d2[:])) diff --git a/tests/test_cdms_info.py b/tests/test_cdms_info.py index 82a96b27..5a618097 100644 --- a/tests/test_cdms_info.py +++ b/tests/test_cdms_info.py @@ -8,7 +8,7 @@ def testInfo(self): f = cdms2.open(os.path.join(cdat_info.get_sampledata_path(),"clt.nc")) s=f("clt") s.info() - def testAxis(self): + def tstAxis(self): axis = cdms2.createAxis(cdms2.createVariable([10.], id='height', missing=1e20)) print(axis) From e2a12a8750eeb7f17c6c6846b95b4f0b9870dff5 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 29 Mar 2018 16:16:08 -0700 Subject: [PATCH 154/239] Cdmsdocsmerge (#223) * First cdms2 documentation revamp * latest changes * add new files and work on avariable documentations * fix index order * revamp documentation * Fixing cdms documentation (docstrings) * update documentation * continue to work on docs * sphinx doctest in manual.rst * chapter 1 continu * add requirments.txt for read-the-doc * move requirements.txt into docs dir * add requirements * Chapter 2 * add chapter 3 * finish chapter 3 started chapter 4 * flake8 python files * chapter 4 regridding * cdms_4 doctest * add other chapters * finish chapter 4 * add chapter 5 * add chapter 6 * cdms chapter 6 * fix TOC * add chapter 7 and appendix * merge docs * add requirements.txt * remove cdat_info * remote cdat_info * fix latex_logo png * pin pyopenssl to 17.2.0 due to myproxyclient failure in py3 * update TOC * work on tables and setup * try to force jquery 3.1 * just copy js script in _static * add highlight python * add sample dataset page * add sample dataset page * work on tables for cdms_2.rst * continue cdms2 documentations * update cdms2 tables * update sections * update table * finish chapter 2 * fix litteral error * unlink .dodsrc for cdscan * First changes from Tanya * some change in chapter 1 and 2 * some changes in Chapter 2 * fix tables * Some changes to Chapter 2 * Some Changes to Chapter 2 * Some changes made to Chapters 1, 2 and 4 * Some changes to Chapter 2 * Some Changes made to Chapter 2 * Some changes to Chapters 2, 3 and 4 * Some changes made to 1 through Appendix * Some Changes made to Chapter 2 * Some Changes to Chapters 1, 2, 3, 6 and Appendix * Some changes made to Chapters 1 thru 7 and appendix * Some changes to Chpaters 1, 2 and 3 * Changes made to Chapters 1, 4, 5 and Appendix * Some changes to Chapter 2 and 4 * Some Changes to Images, Chapter 3 and Appendix * update logo * add my logo * fix chapter 1 test --- docs/source/conf.py | 2 +- docs/source/manual/images/cdms_logo2_nocube.png | Bin 0 -> 17386 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/source/manual/images/cdms_logo2_nocube.png diff --git a/docs/source/conf.py b/docs/source/conf.py index a178ee54..f6eed9f5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -211,7 +211,7 @@ def side_effect(*args, **kwargs): # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = 'manual/images/uvcdat.png' +html_logo = 'manual/images/cdms_logo2_nocube.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 diff --git a/docs/source/manual/images/cdms_logo2_nocube.png b/docs/source/manual/images/cdms_logo2_nocube.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba6a2a2dd3c2893154b04919c66443c22a147b4 GIT binary patch literal 17386 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 Date: Tue, 1 May 2018 09:49:51 -0700 Subject: [PATCH 155/239] Fix python3 slice issue(setitem) and flake8 (#243) --- Src/Cdunifmodule.c | 8 +++++++- regrid2/Lib/esmf.py | 2 +- regrid2/Lib/mvESMFRegrid.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index ddfb81df..400ba4f9 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -3089,7 +3089,9 @@ static int PyCdunifVariableObject_ass_subscript(PyCdunifVariableObject *self, if (PySlice_Check(index)) { Py_ssize_t slicelen; int length; - if( self->dimensions[0] == self->file->recdim ){ + length = INT_MAX; + if( self->dimids[0]== self->file->recdim && + self->dimensions[0] == 0){ length = INT_MAX; } else { length = self->dimensions[0]; @@ -3097,6 +3099,10 @@ static int PyCdunifVariableObject_ass_subscript(PyCdunifVariableObject *self, PySlice_GetIndicesEx((PySliceObject *) index, length, &indices->start, &indices->stop, &indices->stride, &slicelen); + + if(indices->stop == indices->start){ + indices->stop = indices->start + indices->stride; + } return PyCdunifVariable_WriteArray(self, indices, value); } if (PyTuple_Check(index)) { diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 02eb38b7..39b8044f 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -836,7 +836,7 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): # default is keep the masked values intact zeroregion = ESMF.Region.SELECT if self.regridMethod == CONSERVE: - zeroregion = None # will initalize to zero + zeroregion = None # will initalize to zero self.regridHandle( srcfield=srcField.field, diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 8fe7f0b4..908034e2 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -368,7 +368,7 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): zero_region = ESMF.Region.SELECT if 'zero_region' in args.keys(): - zero_region=args.get('zero_region') + zero_region = args.get('zero_region') self.srcFld.field.data[:] = srcData.T self.dstFld.field.data[:] = dstData.T From 7ced34c037789d2af4670702648b6cf6d9156b38 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 1 May 2018 19:09:37 -0700 Subject: [PATCH 156/239] fix python 3 aggregation issue and flake8 (#244) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 --- Src/Cdunifmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index 400ba4f9..f5f3ba83 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -535,7 +535,9 @@ static int cdopen(const char* controlpath, int ncmode, CuFileType *filetype) { /* Take care for mode flag */ if ((cdms_classic == 0) || (cdms_shuffle != 0) || (cdms_deflate != 0) || (cdms_netcdf4 == 1)) { - ncmode = ncmode | NC_NETCDF4; + if(strstr(controlpath, "http") == NULL){ + ncmode = ncmode | NC_NETCDF4; + } } #ifdef PARALLEL /* ok we can only use MPIIO if not using shuffle or deflate for reason From 9d5b7d21c2566a5c5142d0f3d3a39f9690df75a0 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 5 Jun 2018 18:14:24 -0700 Subject: [PATCH 157/239] Netcdf46 (#249) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env --- .circleci/config.yml | 147 +++++++++++++++++++++++++ .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 --- ci-support/circleci_mac_dep.sh | 102 ----------------- ci-support/circleci_mac_machine_pre.sh | 8 -- ci-support/conda_upload.sh | 83 +++----------- circle.yml | 35 ------ tests/dodsrccircleci | 8 +- tests/test_cdscan.py | 1 + 9 files changed, 171 insertions(+), 232 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 ci-support/circleci_mac.sh delete mode 100644 ci-support/circleci_mac_dep.sh delete mode 100644 ci-support/circleci_mac_machine_pre.sh delete mode 100644 circle.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..8a582e3b --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,147 @@ +version: 2 + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +aliases: + + - &setup_miniconda + name: setup_miniconda + command: | + mkdir -p workspace + git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat + ls workspace/cdat + # following will install miniconda3 under $WORKDIR/miniconda/bin + python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' + + - &create_conda_env + name: create_conda_env + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + conda config --set always_yes yes --set changeps1 no + conda update -y -q conda + conda config --set anaconda_upload no + conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" + conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" + if [ $(uname) == "Linux" ]; then + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + else + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + fi + + - &setup_cdms + name: setup_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + source activate py3 + mkdir $HOME/.esg + echo "Get ESGF certificates" + echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert + cp tests/dodsrccircleci $HOME/.dodsrc + echo "Create .dods_cookies" + curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + source activate py2 + rm -rf build + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + + - &run_cdms_tests + name: run_cdms_tests + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + set -e + source activate py2 + python run_tests.py -v2 + PY2_RESULT=$? + echo "*** py2 test result: "${PY2_RESULT} + source activate py3 + python run_tests.py -v2 + PY3_RESULT=$? + echo "*** py3 test result: "${PY3_RESULT} + echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt + echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt + + - &upload_cdms + name: upload_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export LABEL="nightly"; + # Retrieve results + PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) + PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) + echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} + echo "*** PY2_RESULT: "${PY2_RESULT} + echo "*** PY3_RESULT: "${PY3_RESULT} + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + #if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then + if [ $CIRCLE_BRANCH != "master" ]; then + export LABEL="unstable"; + echo "NOTE: upload LABEL="${LABEL} + conda install -n root conda-build anaconda-client; + bash ./ci-support/conda_upload.sh; + fi + +jobs: + macos_cdms: + macos: + xcode: "9.2.0" + environment: + WORKDIR: "workspace/test_macos_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + linux_cdms: + machine: + image: circleci/classic:latest + environment: + WORKDIR: "workspace/test_linux_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + +workflows: + version: 2 + cdms_test: + jobs: + - macos_cdms + - linux_cdms + + diff --git a/.travis.yml b/.travis.yml index 26d87cc8..0bb331b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh deleted file mode 100644 index 66e14816..00000000 --- a/ci-support/circleci_mac.sh +++ /dev/null @@ -1,15 +0,0 @@ -export UVCDAT_ANONYMOUS_LOG=False -export PATH=${HOME}/miniconda/bin:${PATH} -echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH -echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS -echo "CI_PULL_REQUEST"$CI_PULL_REQUEST -source activate py2 -python run_tests.py -v2 -s -RESULT=$? -source activate py3 -python run_tests.py -v2 -s -RESULT=$(( $RESULT + $? )) -echo "RESULT:"${RESULT} -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi -exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh deleted file mode 100644 index 385aef61..00000000 --- a/ci-support/circleci_mac_dep.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -cmd="ls" -echo $cmd -$cmd - -cmd="pwd" -echo $cmd -$cmd - -cmd="export PATH=${HOME}/miniconda/bin:${PATH}" -echo $cmd -$cmd - -# Create Python 3 environment -cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py3 pyopenssl" -echo $cmd -$cmd - - -cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# Create Python 2 environment -cmd="conda create -n py2 python=2.7" -echo $cmd -$cmd - -# Activate python 2 environment -cmd="source activate py2" -echo $cmd -$cmd - -cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py2 pyopenssl" -echo $cmd -$cmd -: - -# add relative path to ncdump -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" -#echo $cmd -#$cmd - -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" -#echo $cmd -#$cmd - -cmd="export UVCDAT_ANONYMOUS_LOG=False" -echo $cmd -$cmd - -# Retrieve certificates from ESGF -cmd="mkdir /Users/distiller/.esg" -echo $cmd -$cmd - -cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " -eval $cmd - -echo "Create .dods_cookies" -cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" -echo $cmd -$cmd - -#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" -#$cmd - -#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" -#echo $cmd -#$cmd - -#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" -#echo $cmd -#$cmd - -#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" -#echo $cmd -#$cmd - -# compile cdms on py2 and py3 environemt. - -cmd="python setup.py install" -echo $cmd -$cmd - -cmd="source activate py3" -echo $cmd -$cmd - -cmd="python setup.py install" -echo $cmd -$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh deleted file mode 100644 index 386629ec..00000000 --- a/ci-support/circleci_mac_machine_pre.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh -bash miniconda.sh -b -p $HOME/miniconda -export PATH=${HOME}/miniconda/bin:${PATH} -conda config --set always_yes yes --set changeps1 no -conda update -y -q conda -conda config --set anaconda_upload no -#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ef61e574..ebde3a90 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,83 +1,34 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -echo "Trying to upload conda" -mkdir ${HOME}/conda-bld -export CONDA_BLD_PATH=${HOME}/conda-bld -export VERSION="2.12" +export VERSION="3.0" +echo "Trying to upload to conda" +echo "" +echo "Activating base env" +source activate base +echo "Making sure conda-build is installed" +conda install "conda-build<3.10" +echo "Updating conda" +conda update -y -q conda if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" - yum install -y wget git gcc - # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null - wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null - bash miniconda2.sh -b -p ${HOME}/miniconda - export SYSPATH=$PATH - export PATH=${HOME}/miniconda/bin:${SYSPATH} - echo $PATH - conda config --set always_yes yes --set changeps1 no - conda config --set anaconda_upload false --set ssl_verify false - conda install -n root -q anaconda-client "conda-build<3.3" - conda install -n root gcc future - which python - export UVCDAT_ANONYMOUS_LOG=False - BRANCH=${TRAVIS_BRANCH} -# echo "Creating python 3 env" -# conda create -n py3 python=3.6 -# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy -# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy -# echo "Creating certificate" -# source activate py3 -# mkdir ${HOME}/.esg -# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert -# ls ${HOME}/.esg -# cd travis_home -# ls -# cp tests/dodsrc ${HOME}.dodsrc -# source deactivate else echo "Mac OS" OS=osx-64 - BRANCH=${CIRCLE_BRANCH} fi -which python -if [ `uname` == "Linux" ]; then - conda install -n root -q anaconda-client "conda-build<3.3" -else - conda install -n root -q anaconda-client conda-build -fi -# pin conda so that conda-build does not update it -#if [ `uname` == "Darwin" ]; then -# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 -#fi +mkdir ~/conda-bld conda config --set anaconda_upload no +export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -cd ${HOME} -git clone git://github.com/UV-CDAT/conda-recipes +git clone git://github.com/CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -python ./prep_for_build.py -b ${BRANCH} -echo "Building now" -echo "use nesii/label/dev-esmf for esmf" -conda build -V -conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat -# -# binstar config set 'false' instead of false (not quote) I have to do it manually -# this is true for OSX. -# binstar is changing verify_ssl to ssl_verify, but the later is not always working -# -# binstar config --set verify_ssl false -# binstar config --set ssl_verify false -# -mkdir -p ~/.continuum/anaconda-client/ -echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml -echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml -if [ `uname` == "Darwin" ]; then - # fix conda and anaconda-client conflict - conda install conda==4.2.16 -fi -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force - +export BRANCH=${CIRCLE_BRANCH} +python ./prep_for_build.py -b ${BRANCH} +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 5d2059a9..00000000 --- a/circle.yml +++ /dev/null @@ -1,35 +0,0 @@ -general: - #branches: - # ignore: - # We only want to build pull requests for testing. If something is merged, - # then we are prepping for release an there is no need to build it again. - # - master -# artifacts: -# - tests_html -# - tests_png - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -#machine: -machine: -# xcode: -# version: 7.2 - pre: - - sudo -H pip install --upgrade virtualenv - - ls - - pwd - - bash cdms/ci-support/circleci_mac_machine_pre.sh - #services: - # - docker - -dependencies: - override: - - bash ./ci-support/circleci_mac_dep.sh - # - docker pull cdat/conda:conda-forge-cdms2 - -test: - override: - - bash ./ci-support/circleci_mac.sh - # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b9b0608f..b2d0bbe8 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert -HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert -HTTP.SSL.CAPATH=/Users/distiller/.esg/ +HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert +HTTP.SSL.KEY=$HOME/.esg/esgf.cert +HTTP.SSL.CAPATH=$HOME/.esg/ diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index e53bdcba..97104482 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -58,6 +58,7 @@ def testopenFile(self): pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() + os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From f18e8aa4501f93c64aa951052429fa258cacedf5 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 5 Jun 2018 18:15:04 -0700 Subject: [PATCH 158/239] Revert "Netcdf46 (#249)" (#250) This reverts commit a9e29eaaecd1158071660d4ce26ccafb56820639. --- .circleci/config.yml | 147 ------------------------- .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 +++ ci-support/circleci_mac_dep.sh | 102 +++++++++++++++++ ci-support/circleci_mac_machine_pre.sh | 8 ++ ci-support/conda_upload.sh | 83 +++++++++++--- circle.yml | 35 ++++++ tests/dodsrccircleci | 8 +- tests/test_cdscan.py | 1 - 9 files changed, 232 insertions(+), 171 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 ci-support/circleci_mac.sh create mode 100644 ci-support/circleci_mac_dep.sh create mode 100644 ci-support/circleci_mac_machine_pre.sh create mode 100644 circle.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8a582e3b..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,147 +0,0 @@ -version: 2 - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -aliases: - - - &setup_miniconda - name: setup_miniconda - command: | - mkdir -p workspace - git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat - ls workspace/cdat - # following will install miniconda3 under $WORKDIR/miniconda/bin - python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' - - - &create_conda_env - name: create_conda_env - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - conda config --set always_yes yes --set changeps1 no - conda update -y -q conda - conda config --set anaconda_upload no - conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" - conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" - if [ $(uname) == "Linux" ]; then - conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 - conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 - else - conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc - conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc - fi - - - &setup_cdms - name: setup_cdms - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export UVCDAT_ANONYMOUS_LOG=False - source activate py3 - mkdir $HOME/.esg - echo "Get ESGF certificates" - echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert - cp tests/dodsrccircleci $HOME/.dodsrc - echo "Create .dods_cookies" - curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" - if [ $(uname) == "Linux" ];then - export LDSHARED="$CC -shared -pthread" - LDSHARED="$CC -shared -pthread" python setup.py install - else - python setup.py install - fi - source activate py2 - rm -rf build - if [ $(uname) == "Linux" ];then - export LDSHARED="$CC -shared -pthread" - LDSHARED="$CC -shared -pthread" python setup.py install - else - python setup.py install - fi - - - &run_cdms_tests - name: run_cdms_tests - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export UVCDAT_ANONYMOUS_LOG=False - set -e - source activate py2 - python run_tests.py -v2 - PY2_RESULT=$? - echo "*** py2 test result: "${PY2_RESULT} - source activate py3 - python run_tests.py -v2 - PY3_RESULT=$? - echo "*** py3 test result: "${PY3_RESULT} - echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt - echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt - - - &upload_cdms - name: upload_cdms - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export LABEL="nightly"; - # Retrieve results - PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) - PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) - echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} - echo "*** PY2_RESULT: "${PY2_RESULT} - echo "*** PY3_RESULT: "${PY3_RESULT} - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi - #if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then - if [ $CIRCLE_BRANCH != "master" ]; then - export LABEL="unstable"; - echo "NOTE: upload LABEL="${LABEL} - conda install -n root conda-build anaconda-client; - bash ./ci-support/conda_upload.sh; - fi - -jobs: - macos_cdms: - macos: - xcode: "9.2.0" - environment: - WORKDIR: "workspace/test_macos_cdms" - steps: - - checkout - - run: *setup_miniconda - - run: *create_conda_env - - run: *setup_cdms - - run: *run_cdms_tests - - run: *upload_cdms - - store_artifacts: - path: tests_html - destination: tests_html - - store_artifacts: - path: tests_png - destination: tests_png - - linux_cdms: - machine: - image: circleci/classic:latest - environment: - WORKDIR: "workspace/test_linux_cdms" - steps: - - checkout - - run: *setup_miniconda - - run: *create_conda_env - - run: *setup_cdms - - run: *run_cdms_tests - - run: *upload_cdms - - store_artifacts: - path: tests_html - destination: tests_html - - store_artifacts: - path: tests_png - destination: tests_png - - -workflows: - version: 2 - cdms_test: - jobs: - - macos_cdms - - linux_cdms - - diff --git a/.travis.yml b/.travis.yml index 0bb331b0..26d87cc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh new file mode 100644 index 00000000..66e14816 --- /dev/null +++ b/ci-support/circleci_mac.sh @@ -0,0 +1,15 @@ +export UVCDAT_ANONYMOUS_LOG=False +export PATH=${HOME}/miniconda/bin:${PATH} +echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH +echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS +echo "CI_PULL_REQUEST"$CI_PULL_REQUEST +source activate py2 +python run_tests.py -v2 -s +RESULT=$? +source activate py3 +python run_tests.py -v2 -s +RESULT=$(( $RESULT + $? )) +echo "RESULT:"${RESULT} +if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi +if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi +exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh new file mode 100644 index 00000000..385aef61 --- /dev/null +++ b/ci-support/circleci_mac_dep.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +cmd="ls" +echo $cmd +$cmd + +cmd="pwd" +echo $cmd +$cmd + +cmd="export PATH=${HOME}/miniconda/bin:${PATH}" +echo $cmd +$cmd + +# Create Python 3 environment +cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# update openssl for myproxyclient +cmd="conda install -n py3 pyopenssl" +echo $cmd +$cmd + + +cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# Create Python 2 environment +cmd="conda create -n py2 python=2.7" +echo $cmd +$cmd + +# Activate python 2 environment +cmd="source activate py2" +echo $cmd +$cmd + +cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# update openssl for myproxyclient +cmd="conda install -n py2 pyopenssl" +echo $cmd +$cmd +: + +# add relative path to ncdump +#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" +#echo $cmd +#$cmd + +#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" +#echo $cmd +#$cmd + +cmd="export UVCDAT_ANONYMOUS_LOG=False" +echo $cmd +$cmd + +# Retrieve certificates from ESGF +cmd="mkdir /Users/distiller/.esg" +echo $cmd +$cmd + +cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " +eval $cmd + +echo "Create .dods_cookies" +cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" +echo $cmd +$cmd + +#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" +#$cmd + +#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" +#echo $cmd +#$cmd + +#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" +#echo $cmd +#$cmd + +#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" +#echo $cmd +#$cmd + +# compile cdms on py2 and py3 environemt. + +cmd="python setup.py install" +echo $cmd +$cmd + +cmd="source activate py3" +echo $cmd +$cmd + +cmd="python setup.py install" +echo $cmd +$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh new file mode 100644 index 00000000..386629ec --- /dev/null +++ b/ci-support/circleci_mac_machine_pre.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh +bash miniconda.sh -b -p $HOME/miniconda +export PATH=${HOME}/miniconda/bin:${PATH} +conda config --set always_yes yes --set changeps1 no +conda update -y -q conda +conda config --set anaconda_upload no +#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ebde3a90..ef61e574 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,34 +1,83 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -export VERSION="3.0" -echo "Trying to upload to conda" -echo "" -echo "Activating base env" -source activate base -echo "Making sure conda-build is installed" -conda install "conda-build<3.10" -echo "Updating conda" -conda update -y -q conda +echo "Trying to upload conda" +mkdir ${HOME}/conda-bld +export CONDA_BLD_PATH=${HOME}/conda-bld +export VERSION="2.12" if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" + yum install -y wget git gcc + # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null + wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null + bash miniconda2.sh -b -p ${HOME}/miniconda + export SYSPATH=$PATH + export PATH=${HOME}/miniconda/bin:${SYSPATH} + echo $PATH + conda config --set always_yes yes --set changeps1 no + conda config --set anaconda_upload false --set ssl_verify false + conda install -n root -q anaconda-client "conda-build<3.3" + conda install -n root gcc future + which python + export UVCDAT_ANONYMOUS_LOG=False + BRANCH=${TRAVIS_BRANCH} +# echo "Creating python 3 env" +# conda create -n py3 python=3.6 +# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy +# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy +# echo "Creating certificate" +# source activate py3 +# mkdir ${HOME}/.esg +# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert +# ls ${HOME}/.esg +# cd travis_home +# ls +# cp tests/dodsrc ${HOME}.dodsrc +# source deactivate else echo "Mac OS" OS=osx-64 + BRANCH=${CIRCLE_BRANCH} fi -mkdir ~/conda-bld +which python +if [ `uname` == "Linux" ]; then + conda install -n root -q anaconda-client "conda-build<3.3" +else + conda install -n root -q anaconda-client conda-build +fi +# pin conda so that conda-build does not update it +#if [ `uname` == "Darwin" ]; then +# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 +#fi conda config --set anaconda_upload no -export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -git clone git://github.com/CDAT/conda-recipes +cd ${HOME} +git clone git://github.com/UV-CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -export BRANCH=${CIRCLE_BRANCH} -python ./prep_for_build.py -b ${BRANCH} +python ./prep_for_build.py -b ${BRANCH} +echo "Building now" +echo "use nesii/label/dev-esmf for esmf" +conda build -V +conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat +# +# binstar config set 'false' instead of false (not quote) I have to do it manually +# this is true for OSX. +# binstar is changing verify_ssl to ssl_verify, but the later is not always working +# +# binstar config --set verify_ssl false +# binstar config --set ssl_verify false +# +mkdir -p ~/.continuum/anaconda-client/ +echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml +echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml +if [ `uname` == "Darwin" ]; then + # fix conda and anaconda-client conflict + conda install conda==4.2.16 +fi +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force + -conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 -conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml new file mode 100644 index 00000000..5d2059a9 --- /dev/null +++ b/circle.yml @@ -0,0 +1,35 @@ +general: + #branches: + # ignore: + # We only want to build pull requests for testing. If something is merged, + # then we are prepping for release an there is no need to build it again. + # - master +# artifacts: +# - tests_html +# - tests_png + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +#machine: +machine: +# xcode: +# version: 7.2 + pre: + - sudo -H pip install --upgrade virtualenv + - ls + - pwd + - bash cdms/ci-support/circleci_mac_machine_pre.sh + #services: + # - docker + +dependencies: + override: + - bash ./ci-support/circleci_mac_dep.sh + # - docker pull cdat/conda:conda-forge-cdms2 + +test: + override: + - bash ./ci-support/circleci_mac.sh + # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b2d0bbe8..b9b0608f 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert -HTTP.SSL.KEY=$HOME/.esg/esgf.cert -HTTP.SSL.CAPATH=$HOME/.esg/ +HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert +HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert +HTTP.SSL.CAPATH=/Users/distiller/.esg/ diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index 97104482..e53bdcba 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -58,7 +58,6 @@ def testopenFile(self): pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() - os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From 074b412136f378231dee0e5cca9e91b23567e95f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 12 Jun 2018 15:24:36 -0700 Subject: [PATCH 159/239] Netcdf46 (#251) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env * inverse dodsrc and curl commands * move unlink above cdscan test * fix ESGF test * add new dodsrc files * create dodsrc on-demand * put back tests for unstable --- .circleci/config.yml | 147 +++++++++++++++++++++++++ .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 --- ci-support/circleci_mac_dep.sh | 102 ----------------- ci-support/circleci_mac_machine_pre.sh | 8 -- ci-support/conda_upload.sh | 83 +++----------- circle.yml | 35 ------ tests/dodsrccircleci | 8 +- tests/dodsrccircleciDarwin | 6 + tests/dodsrccircleciLinux | 6 + tests/test_all_formats.py | 17 ++- tests/test_cdscan.py | 11 +- 12 files changed, 203 insertions(+), 239 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 ci-support/circleci_mac.sh delete mode 100644 ci-support/circleci_mac_dep.sh delete mode 100644 ci-support/circleci_mac_machine_pre.sh delete mode 100644 circle.yml create mode 100644 tests/dodsrccircleciDarwin create mode 100644 tests/dodsrccircleciLinux diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..6988a468 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,147 @@ +version: 2 + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +aliases: + + - &setup_miniconda + name: setup_miniconda + command: | + mkdir -p workspace + git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat + ls workspace/cdat + # following will install miniconda3 under $WORKDIR/miniconda/bin + python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' + + - &create_conda_env + name: create_conda_env + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + conda config --set always_yes yes --set changeps1 no + conda update -y -q conda + conda config --set anaconda_upload no + conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" + conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" + if [ $(uname) == "Linux" ]; then + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + else + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + fi + + - &setup_cdms + name: setup_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + source activate py3 + mkdir $HOME/.esg + echo "Get ESGF certificates" + echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert + echo "Create .dods_cookies" + curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" + if [ $(uname) == "Linux" ];then + cp tests/dodsrccircleciLinux $HOME/.dodsrc + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + cp tests/dodsrccircleciDarwin $HOME/.dodsrc + python setup.py install + fi + source activate py2 + rm -rf build + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + + - &run_cdms_tests + name: run_cdms_tests + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + set -e + source activate py2 + python run_tests.py -v2 + PY2_RESULT=$? + echo "*** py2 test result: "${PY2_RESULT} + source activate py3 + python run_tests.py -v2 + PY3_RESULT=$? + echo "*** py3 test result: "${PY3_RESULT} + echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt + echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt + + - &upload_cdms + name: upload_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export LABEL="nightly"; + # Retrieve results + PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) + PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) + echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} + echo "*** PY2_RESULT: "${PY2_RESULT} + echo "*** PY3_RESULT: "${PY3_RESULT} + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then + export LABEL="unstable"; + echo "NOTE: upload LABEL="${LABEL} + conda install -n root conda-build anaconda-client; + bash ./ci-support/conda_upload.sh; + fi + +jobs: + macos_cdms: + macos: + xcode: "9.2.0" + environment: + WORKDIR: "workspace/test_macos_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + linux_cdms: + machine: + image: circleci/classic:latest + environment: + WORKDIR: "workspace/test_linux_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + +workflows: + version: 2 + cdms_test: + jobs: + - macos_cdms + - linux_cdms + + diff --git a/.travis.yml b/.travis.yml index 26d87cc8..0bb331b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh deleted file mode 100644 index 66e14816..00000000 --- a/ci-support/circleci_mac.sh +++ /dev/null @@ -1,15 +0,0 @@ -export UVCDAT_ANONYMOUS_LOG=False -export PATH=${HOME}/miniconda/bin:${PATH} -echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH -echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS -echo "CI_PULL_REQUEST"$CI_PULL_REQUEST -source activate py2 -python run_tests.py -v2 -s -RESULT=$? -source activate py3 -python run_tests.py -v2 -s -RESULT=$(( $RESULT + $? )) -echo "RESULT:"${RESULT} -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi -exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh deleted file mode 100644 index 385aef61..00000000 --- a/ci-support/circleci_mac_dep.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -cmd="ls" -echo $cmd -$cmd - -cmd="pwd" -echo $cmd -$cmd - -cmd="export PATH=${HOME}/miniconda/bin:${PATH}" -echo $cmd -$cmd - -# Create Python 3 environment -cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py3 pyopenssl" -echo $cmd -$cmd - - -cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# Create Python 2 environment -cmd="conda create -n py2 python=2.7" -echo $cmd -$cmd - -# Activate python 2 environment -cmd="source activate py2" -echo $cmd -$cmd - -cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py2 pyopenssl" -echo $cmd -$cmd -: - -# add relative path to ncdump -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" -#echo $cmd -#$cmd - -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" -#echo $cmd -#$cmd - -cmd="export UVCDAT_ANONYMOUS_LOG=False" -echo $cmd -$cmd - -# Retrieve certificates from ESGF -cmd="mkdir /Users/distiller/.esg" -echo $cmd -$cmd - -cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " -eval $cmd - -echo "Create .dods_cookies" -cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" -echo $cmd -$cmd - -#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" -#$cmd - -#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" -#echo $cmd -#$cmd - -#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" -#echo $cmd -#$cmd - -#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" -#echo $cmd -#$cmd - -# compile cdms on py2 and py3 environemt. - -cmd="python setup.py install" -echo $cmd -$cmd - -cmd="source activate py3" -echo $cmd -$cmd - -cmd="python setup.py install" -echo $cmd -$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh deleted file mode 100644 index 386629ec..00000000 --- a/ci-support/circleci_mac_machine_pre.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh -bash miniconda.sh -b -p $HOME/miniconda -export PATH=${HOME}/miniconda/bin:${PATH} -conda config --set always_yes yes --set changeps1 no -conda update -y -q conda -conda config --set anaconda_upload no -#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ef61e574..ebde3a90 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,83 +1,34 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -echo "Trying to upload conda" -mkdir ${HOME}/conda-bld -export CONDA_BLD_PATH=${HOME}/conda-bld -export VERSION="2.12" +export VERSION="3.0" +echo "Trying to upload to conda" +echo "" +echo "Activating base env" +source activate base +echo "Making sure conda-build is installed" +conda install "conda-build<3.10" +echo "Updating conda" +conda update -y -q conda if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" - yum install -y wget git gcc - # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null - wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null - bash miniconda2.sh -b -p ${HOME}/miniconda - export SYSPATH=$PATH - export PATH=${HOME}/miniconda/bin:${SYSPATH} - echo $PATH - conda config --set always_yes yes --set changeps1 no - conda config --set anaconda_upload false --set ssl_verify false - conda install -n root -q anaconda-client "conda-build<3.3" - conda install -n root gcc future - which python - export UVCDAT_ANONYMOUS_LOG=False - BRANCH=${TRAVIS_BRANCH} -# echo "Creating python 3 env" -# conda create -n py3 python=3.6 -# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy -# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy -# echo "Creating certificate" -# source activate py3 -# mkdir ${HOME}/.esg -# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert -# ls ${HOME}/.esg -# cd travis_home -# ls -# cp tests/dodsrc ${HOME}.dodsrc -# source deactivate else echo "Mac OS" OS=osx-64 - BRANCH=${CIRCLE_BRANCH} fi -which python -if [ `uname` == "Linux" ]; then - conda install -n root -q anaconda-client "conda-build<3.3" -else - conda install -n root -q anaconda-client conda-build -fi -# pin conda so that conda-build does not update it -#if [ `uname` == "Darwin" ]; then -# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 -#fi +mkdir ~/conda-bld conda config --set anaconda_upload no +export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -cd ${HOME} -git clone git://github.com/UV-CDAT/conda-recipes +git clone git://github.com/CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -python ./prep_for_build.py -b ${BRANCH} -echo "Building now" -echo "use nesii/label/dev-esmf for esmf" -conda build -V -conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat -# -# binstar config set 'false' instead of false (not quote) I have to do it manually -# this is true for OSX. -# binstar is changing verify_ssl to ssl_verify, but the later is not always working -# -# binstar config --set verify_ssl false -# binstar config --set ssl_verify false -# -mkdir -p ~/.continuum/anaconda-client/ -echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml -echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml -if [ `uname` == "Darwin" ]; then - # fix conda and anaconda-client conflict - conda install conda==4.2.16 -fi -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force - +export BRANCH=${CIRCLE_BRANCH} +python ./prep_for_build.py -b ${BRANCH} +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 5d2059a9..00000000 --- a/circle.yml +++ /dev/null @@ -1,35 +0,0 @@ -general: - #branches: - # ignore: - # We only want to build pull requests for testing. If something is merged, - # then we are prepping for release an there is no need to build it again. - # - master -# artifacts: -# - tests_html -# - tests_png - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -#machine: -machine: -# xcode: -# version: 7.2 - pre: - - sudo -H pip install --upgrade virtualenv - - ls - - pwd - - bash cdms/ci-support/circleci_mac_machine_pre.sh - #services: - # - docker - -dependencies: - override: - - bash ./ci-support/circleci_mac_dep.sh - # - docker pull cdat/conda:conda-forge-cdms2 - -test: - override: - - bash ./ci-support/circleci_mac.sh - # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b9b0608f..b2d0bbe8 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert -HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert -HTTP.SSL.CAPATH=/Users/distiller/.esg/ +HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert +HTTP.SSL.KEY=$HOME/.esg/esgf.cert +HTTP.SSL.CAPATH=$HOME/.esg/ diff --git a/tests/dodsrccircleciDarwin b/tests/dodsrccircleciDarwin new file mode 100644 index 00000000..b9b0608f --- /dev/null +++ b/tests/dodsrccircleciDarwin @@ -0,0 +1,6 @@ +HTTP.VERBOSE=0 +HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert +HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert +HTTP.SSL.CAPATH=/Users/distiller/.esg/ + diff --git a/tests/dodsrccircleciLinux b/tests/dodsrccircleciLinux new file mode 100644 index 00000000..2269387e --- /dev/null +++ b/tests/dodsrccircleciLinux @@ -0,0 +1,6 @@ +HTTP.VERBOSE=0 +HTTP.COOKIEJAR=/home/circleci/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/home/circleci/.esg/esgf.cert +HTTP.SSL.KEY=/home/circleci/.esg/esgf.cert +HTTP.SSL.CAPATH=/home/circleci/.esg/ + diff --git a/tests/test_all_formats.py b/tests/test_all_formats.py index 8a6cc387..bee09221 100644 --- a/tests/test_all_formats.py +++ b/tests/test_all_formats.py @@ -3,6 +3,8 @@ import sys import cdat_info import basetest +import platform +from shutil import copyfile class TestFormats(basetest.CDMSBaseTest): @@ -20,7 +22,11 @@ def testDRS(self): data = f['a'] self.assertEqual(data.missing_value, 1e20) - def testDAP(self): + def dtestDAP(self): + try: + os.unlink(os.environ['HOME']+'/.dodsrc') + except: + pass f = cdms2.open('http://test.opendap.org/opendap/hyrax/data/nc/coads_climatology.nc') data=f['SST'] self.assertEqual(data.missing_value, -1e34) @@ -32,7 +38,14 @@ def testGRIB2(self): self.assertEqual(data.missing_value, 9.999e20) # test disabled due to OSX issue - def dtestESGF(self): + def testESGF(self): + file = open(os.environ['HOME']+'/.dodsrc','w') + file.write("HTTP.VERBOSE=0\n") + file.write("HTTP.COOKIEJAR="+os.environ['HOME']+"/.esg/.dods_cookies\n") + file.write("HTTP.SSL.CERTIFICATE="+os.environ['HOME']+"/.esg/esgf.cert\n") + file.write("HTTP.SSL.KEY="+os.environ['HOME']+"/.esg/esgf.cert\n") + file.write("HTTP.SSL.CAPATH="+os.environ['HOME']+"/.esg/\n") + file.close() f = cdms2.open("https://aims3.llnl.gov/thredds/dodsC/cmip5_css01_data/cmip5/output1/BCC/bcc-csm1-1-m/1pctCO2/day/ocean/day/r1i1p1/v20120910/tos/tos_day_bcc-csm1-1-m_1pctCO2_r1i1p1_02800101-02891231.nc") self.assertIn('tos', f.listvariables()) data=f['tos'] diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index e53bdcba..9bb24173 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -1,5 +1,9 @@ - import basetest +import os +try: + os.unlink(os.environ['HOME']+'/.dodsrc') +except: + pass import cdms2 from cdms2.cdscan import main as cdscan import os @@ -52,12 +56,9 @@ def testopenFile(self): ''' retrieve value from cdscan ''' - try: - os.unlink(os.environ['HOME']+'/.dodsrc') - except: - pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() + os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From c9dd25e651da37204548af78d353dcfb8cf524f5 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 12 Jun 2018 16:29:12 -0700 Subject: [PATCH 160/239] Netcdf46 (#252) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env * inverse dodsrc and curl commands * move unlink above cdscan test * fix ESGF test * add new dodsrc files * create dodsrc on-demand * put back tests for unstable * instal anaconda-client before calling conda-upload --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6988a468..6e1432ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -88,8 +88,9 @@ aliases: echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} echo "*** PY2_RESULT: "${PY2_RESULT} echo "*** PY3_RESULT: "${PY3_RESULT} - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then export LABEL="unstable"; echo "NOTE: upload LABEL="${LABEL} From a378f3198c758aa3b0b7626fb5b43a816bb65707 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 23 May 2018 15:16:36 -0700 Subject: [PATCH 161/239] Changes made to API --- Lib/avariable.py | 23 +++++++------- Lib/coord.py | 69 +++++++++++++++++++++++++++-------------- Lib/cudsinterface.py | 2 +- Lib/database.py | 4 +-- Lib/variable.py | 38 ++++++++++++----------- regrid2/Lib/gsRegrid.py | 8 ++--- 6 files changed, 85 insertions(+), 59 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index ba38c886..35762f0e 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -133,10 +133,10 @@ class AbstractVariable(CdmsObj, Slab): Parameters ---------- - variableNode - is the variable tree node, if any. - parent - is the containing dataset instance. + variableNode + is the variable tree node, if any. + parent + is the containing dataset instance. """ def info(self, flag=None, device=None): Slab.info(self, flag, device) @@ -1437,8 +1437,8 @@ def crossSectionRegrid(self, newLevel, newLatitude, method : Optional either "log" to interpolate in the log of pressure (default), or "linear" for linear interpolation. - missing and order: - are as for regrid.CrossSectionRegridder. + missing-and-order: + are as for regrid.CrossSectionRegridder. """ from regrid2 import CrossSectionRegridder @@ -1689,12 +1689,13 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. - Parameter - --------- - ar - is a masked array, scalar, or numpy.ma.masked. + +Parameters +---------- + ar + is a masked array, scalar, or numpy.ma.masked. - _: None + _: None """ diff --git a/Lib/coord.py b/Lib/coord.py index ef731cec..cb5aa229 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -62,7 +62,20 @@ def createCoordinateAxis(data, bounds=None, id=None, copy=0): class AbstractCoordinateAxis(CdmsObj): + """ + Parameters + ---------- + clone + (self, copyData=1) + + _:None + + Returns + ------- + a copy of self as a transient axis. If copyData is 1, make a separate copy of the data. + + """ axis_count = 0 # Transient axis count def __init__(self, parent=None, variableNode=None, bounds=None): @@ -73,9 +86,9 @@ def isAbstractCoordinate(self): return 1 def clone(self, copyData=1): - """clone (self, copyData=1) - Return a copy of self as a transient axis. - If copyData is 1, make a separate copy of the data.""" + """ + + """ raise CDMSError(MethodNotImplemented) # Designate axis as a latitude axis. @@ -275,21 +288,31 @@ def writeToFile(self, file): class AbstractAxis2D(AbstractCoordinateAxis): + """ + Parameters + ---------- + + clone + (self, copyData=1) + _:None + + + Returns + ------- + a copy of self as a transient axis. + + Note + ---- + If copyData is 1, make a separate copy of the data. + """ def __init__(self, parent=None, variableNode=None, bounds=None): AbstractCoordinateAxis.__init__( self, parent, variableNode, bounds=bounds) def clone(self, copyData=1): - """clone (self, copyData=1) - - Returns - ------- - a copy of self as a transient axis. - - Note - ---- - If copyData is 1, make a separate copy of the data.""" + """ + """ result = TransientAxis2D( self[:], copy=copyData, @@ -369,22 +392,22 @@ def __repr__(self): class TransientAxis2D(AbstractAxis2D, TransientVariable): + """ + Create a transient 2D axis. + All arguments are as for TransientVariable. + + Parameters + ---------- + bounds: + is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and + nvert: + is the max number of vertices per cell. + """ def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): """ - Create a transient 2D axis. - - All arguments are as for TransientVariable. - Parameters - ---------- - - 'bounds' - is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and - - nvert - is the max number of vertices per cell. """ AbstractAxis2D.__init__(self, None, None, bounds=bounds) TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index e91ce10b..99c02bb7 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -125,7 +125,7 @@ def listdimension(self, vname=None): Returns ------- - a list of the dimension names associated with a variable. + a list of the dimension names associated with a variable. If no argument, return the file.axes.keys() diff --git a/Lib/database.py b/Lib/database.py index b69ee49e..0cba0284 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -45,7 +45,7 @@ def connect(uri=None, user="", password=""): Description: Open a CDMS database connection. Arguments - --------- + uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. user: user id password: password @@ -465,7 +465,7 @@ def searchPredicate(self, predicate, tag=None): class LDAPSearchResult(AbstractSearchResult): - + def __init__(self, db, LDAPresult): self.db = db self.result = LDAPresult diff --git a/Lib/variable.py b/Lib/variable.py index 887ef32a..b09a0dec 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -39,9 +39,7 @@ def timeindex(value, units, basetime, delta, delunits, calendar): class DatasetVariable(AbstractVariable): - - def __init__(self, parent, id, variableNode=None): - """Variable (parent, variableNode=None) + """Variable (parent, variableNode=None) Parameters ---------- @@ -50,6 +48,10 @@ def __init__(self, parent, id, variableNode=None): parent is the containing dataset instance. + + """ + def __init__(self, parent, id, variableNode=None): + """ """ AbstractVariable.__init__(self, parent, variableNode) val = self.__cdms_internals__ + ['domain', 'name_in_file'] @@ -322,30 +324,30 @@ def expertPaths(self, slist): a 3-tuple (npart, dimensionlist, partitionSlices) - Where: + Where: - npart - is the number of partitioned dimensions: 0, 1, or 2; + npart + is the number of partitioned dimensions: 0, 1, or 2; - dimensionlist - is a tuple of length npart, having the dimension numbers of the partitioned dimensions; + dimensionlist + is a tuple of length npart, having the dimension numbers of the partitioned dimensions; - partitionSlices - is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. + partitionSlices + is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. - The exact form of partitionSlices depends on the value of npart: + The exact form of partitionSlices depends on the value of npart: - npart partitionSlices + npart partitionSlices - 0 (filename,slicelist) + 0 (filename,slicelist) - 1 [(filename,slicelist),...,(filename,slicelist)] + 1 [(filename,slicelist),...,(filename,slicelist)] - 2 [[(filename,slicelist),...,(filename,slicelist)] - [(filename,slicelist),...,(filename,slicelist)] - ... - [(filename,slicelist),...,(filename,slicelist)]] + 2 [[(filename,slicelist),...,(filename,slicelist)] + [(filename,slicelist),...,(filename,slicelist)] + ... + [(filename,slicelist),...,(filename,slicelist)]] Note: - A filename of None indicates that no file was found with data corresponding to the slicelist. diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 2d915b1e..3c949192 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer and Dave Kindig, Tech-X (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Regridding of curvilinear structured grids -Alex Pletzer and Dave Kindig, Tech-X (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ # standard python includes # from re import search, sub From 5ffe9de10336caa876b2b88cebb90e7e0d20a266 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 24 May 2018 15:28:00 -0700 Subject: [PATCH 162/239] Made some changes to API --- Lib/MV2.py | 1 + Lib/grid.py | 2 +- Lib/mvCdmsRegrid.py | 7 +++---- Lib/selectors.py | 13 +++++++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index a5ffac43..d3feb738 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -770,6 +770,7 @@ def transpose(a, axes=None): class _minimum_operation: + "Object to calculate minima" def __init__(self): diff --git a/Lib/grid.py b/Lib/grid.py index 9ab1c9e8..a777ed0c 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -941,7 +941,7 @@ def isGrid(grid): Parameters ---------- - grid cdms2: + grid-cdms2: contruct to be examined _: None diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index 3b9daced..63e77bd9 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -379,11 +379,10 @@ class CdmsRegrid: regridder. If a multidimensional variable is passed in, the apply step loops over the axes above the Lat (Y) -- Lon (X) coordinates - Establish which regridding method to use, handle CDMS variables before - handing off to regridder. See specific tool for more information. + Establish which regridding method to use, handle CDMS variables before handing off to regridder. See specific tool for more information. - Parameters - ---------- +Parameters +---------- srcGrid CDMS source grid diff --git a/Lib/selectors.py b/Lib/selectors.py index d4403135..947a4e37 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -16,14 +16,14 @@ def __init__(self, args): class Selector: - """Selector class""" + """Selector class + + Positional args are SelectorComponents or Selectors Keyword args and their value are passed to kwselect to create selectors. All the selector components are put into the components list of this Selector, along with all the componentsof any Selector arguments. + + """ def __init__(self, *args, **kwargs): - """Positional args are SelectorComponents or Selectors - Keyword args and their value are passed to kwselect to create - selectors. All the selector components are put into the - components list of this Selector, along with all the components - of any Selector arguments. + """ """ self.__components = [] self.refine(*args, **kwargs) @@ -96,6 +96,7 @@ def select(self, variable, *args, **kwargs): Options modify the result of the selection. The options and their default values are: -- raw = 0: if 1, return an numpy.ma only + -- squeeze = 0: If 1, eliminate any dimensions of length 1 from the result. -- order = None: If given, is a string such as From 6442448c4e11b32684cafec5824bacfc7ca700b0 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 29 May 2018 15:40:37 -0700 Subject: [PATCH 163/239] Changes made to API --- Lib/cache.py | 47 ++++++---- Lib/mvVTKSGWriter.py | 18 ++-- Lib/mvVTKUGWriter.py | 15 ++-- Lib/mvVsWriter.py | 20 +++-- regrid2/Lib/gsRegrid.py | 193 ++++++++++++++++++++-------------------- 5 files changed, 159 insertions(+), 134 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index 899b909c..324bf30f 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -181,8 +181,14 @@ def copyFile(fromURL, toURL, callback=None, For request manager transfers, is the logical collection distinguished name, - - is the string user ID, is true if the request manager should search the replica catalog for the actual file to transfer. + Parameters + ---------- + + + is the string user ID, + + + is true if the request manager should search the replica catalog for the actual file to transfer. """ if callback is None: if _useWindow: @@ -349,15 +355,17 @@ def copyFile(self, fromURL, filekey, lcpath=None, """ Copy the file into the cache. Return the result path. - For request manager transfers, lcpath is the logical collection path, + For request manager transfers, lcpath is the logical collection path, +Parameters +---------- - - is the string user ID, + + is the string user ID, - - is true iff the request manager should search the replica catalog for the actual file to transfer. + + is true iff the request manager should search the replica catalog for the actual file to transfer. """ # Put a notification into the cache, that this file is being read. @@ -397,32 +405,35 @@ def getFile(self, fromURL, filekey, naptime=5, maxtries=60, """ Get the file with . - If the file is in the cache, read it. + If the file is in the cache, read it. - If another process is transferring it into the cache, wait for the + If another process is transferring it into the cache, wait for the transfer to complete. + + Parameters + --------- - is the number of seconds between retries, + is the number of seconds between retries, - is the maximum number of retries. Otherwise, copy it from the remote file. + is the maximum number of retries. Otherwise, copy it from the remote file. - is the cache index key. A good choice is (datasetDN, filename) + is the cache index key. A good choice is (datasetDN, filename) where datasetDN is the distinguished name of the dataset, and filename is the name of the file within the dataset. For request manager transfers, - - is the logical collection path, + + is the logical collection path, - - is the user string ID, + + is the user string ID, - - is true iff the request manager should search the replica catalog for the actual file to transfer. + + is true iff the request manager should search the replica catalog for the actual file to transfer. Returns the path of a file in the cache. diff --git a/Lib/mvVTKSGWriter.py b/Lib/mvVTKSGWriter.py index b857e541..ce12f582 100644 --- a/Lib/mvVTKSGWriter.py +++ b/Lib/mvVTKSGWriter.py @@ -14,16 +14,20 @@ class VTKSGWriter(mvBaseWriter.BaseWriter): + """ + Write file - def write(self, filename): - """ - Write file + Parameters + ---------- - Parameters - ---------- + filename + file name - filename - file name + _: None + """ + def write(self, filename): + """ + """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVTKUGWriter.py b/Lib/mvVTKUGWriter.py index 120f1549..9fd0dbfe 100644 --- a/Lib/mvVTKUGWriter.py +++ b/Lib/mvVTKUGWriter.py @@ -14,18 +14,21 @@ class VTKUGWriter(mvBaseWriter.BaseWriter): + """ + Write file - def write(self, filename): - """ - Write file - - Parameters - ---------- + Parameters + ---------- filename file name _:None + + """ + def write(self, filename): + """ + """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVsWriter.py b/Lib/mvVsWriter.py index 1aff8dec..d9681495 100644 --- a/Lib/mvVsWriter.py +++ b/Lib/mvVsWriter.py @@ -13,16 +13,20 @@ class VsWriter(mvBaseWriter.BaseWriter): - - def write(self, filename): - """ - Write file + """ + Write file + + Parameters + ---------- - Parameters - ---------- + filename + file name - filename - file name + _: None + """ + def write(self, filename): + """ + """ try: import tables diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 3c949192..738a264d 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -48,19 +48,19 @@ def getTensorProduct(axis, dim, dims): Parameters ---------- - axis - 1D array of coordinates + axis + 1D array of coordinates - dim - dimensional index of the above coordinate + dim + dimensional index of the above coordinate - dims - sizes of all coordinates + dims + sizes of all coordinates Returns ------- - coordinate values obtained by tensor product + coordinate values obtained by tensor product """ return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) @@ -74,14 +74,14 @@ def makeCurvilinear(coords): Parameters ---------- - coords - list of coordinates - _: None + coords + list of coordinates + _: None Returns ------- - new list of coordinates and associated dimensions + new list of coordinates and associated dimensions """ rank = len(coords) @@ -126,16 +126,16 @@ def makeCoordsCyclic(coords, dims): Parameters ---------- - coords - input coordinates + coords + input coordinates - dims - input dimensions + dims + input dimensions Returns ------- - new, extended coordinates such that the longitudes cover the sphere and new dimensions + new, extended coordinates such that the longitudes cover the sphere and new dimensions """ # assume lon is the last coordinate!! @@ -192,17 +192,17 @@ def checkForCoordCut(coords, dims): Parameters ---------- - coords - input coordinates + coords + input coordinates - dims - input dimensions + dims + input dimensions Returns ------- - True for cut found - False for no cut + True for cut found + False for no cut """ # Assume latitude is next to last coordinate and longitude is last @@ -300,19 +300,19 @@ def handleCoordsCut(coords, dims, bounds): Parameters ---------- - coords - input coordinates list of rank + coords + input coordinates list of rank - dims - input dimensions + dims + input dimensions - bounds - boundaries for each coordinate + bounds + boundaries for each coordinate Returns ------- - extended coordinates such that there is an extra row containing connectivity information across the cut + extended coordinates such that there is an extra row containing connectivity information across the cut """ # Assume latitude is next to last coordinate and longitude is @@ -329,19 +329,19 @@ def getIndices(array, nlon, newI): Parameters ---------- - array - Array of booleans + array + Array of booleans - nlon - number of longitudes + nlon + number of longitudes - newI - index row with connectivity to be updated + newI + index row with connectivity to be updated Returns ------- - new coordinates, new dimensions, index row + new coordinates, new dimensions, index row """ for i in range(len(array)): # An edge @@ -371,32 +371,35 @@ def getIndices(array, nlon, newI): class Regrid: - def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, - handleCut=False, verbose=False): - """ - Constructor + """ + Constructor - Parameters - ---------- + Parameters + ---------- + src_grid + source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient - src_grid - source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient + dst_grid + destination grid, a list of [x, y, ...] coordinates - dst_grid - destination grid, a list of [x, y, ...] coordinates + src_bounds + list of cell bounding coordinates (to be used when handling a cut in coordinates) - src_bounds - list of cell bounding coordinates (to be used when handling a cut in coordinates) + mkCyclic + Add a column to the right side of the grid to complete a cyclic grid - mkCyclic - Add a column to the right side of the grid to complete a cyclic grid + handleCut + Add a row to the top of grid to handle a cut for grids such as the tri-polar grid verbose print diagnostic messages - handleCut - Add a row to the top of grid to handle a cut for grids such as the tri-polar grid - verbose print diagnostic messages + Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. + """ + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, + handleCut=False, verbose=False): + """ + Constructor - Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. + """ self.regridid = c_int(-1) self.src_gridid = c_int(-1) @@ -568,7 +571,7 @@ def getPeriodicities(self): Returns ------- - numpy array, values inf indicate no periodicity + numpy array, values inf indicate no periodicity """ coord_periodicity = numpy.zeros((self.rank,), numpy.float64) status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, @@ -612,11 +615,11 @@ def setValidMask(self, inMask): Parameters ---------- - inMask - flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. - 0 - invalid, 1 - valid data + inMask + flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. + 0 - invalid, 1 - valid data - _: None + _: None Note: This must be invoked before computing the weights, the mask is a property of the grid (not the data). """ @@ -641,11 +644,12 @@ def setMask(self, inDataOrMask): Parameters ---------- - inDataOrMask cdms2 array or flat mask array, - 0 - valid data - 1 - invalid data + inDataOrMask + cdms2 array or flat mask array, + 0 - valid data + 1 - invalid data - _: None + _: None Note: this definition is compatible with the numpy masked arrays @@ -672,12 +676,11 @@ def computeWeights(self, nitermax=100, tolpos=1.e-2): Parameters ---------- - nitermax - max number of iterations + nitermax + max number of iterations - tolpos - max tolerance when locating destination positions in - index space + tolpos + max tolerance when locating destination positions in index space """ status = self.lib.nccf_compute_regrid_weights(self.regridid, nitermax, @@ -692,14 +695,14 @@ def apply(self, src_data_in, dst_data, missingValue=None): Parameters ---------- - src_data - data on source grid + src_data + data on source grid - dst_data - data on destination grid + dst_data + data on destination grid - missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ if not self.weightsComputed: raise RegridError('Weights must be set before applying the regrid') @@ -813,14 +816,14 @@ def __call__(self, src_data, dst_data, missingValue=None): Parameters ---------- - src_data - data on source grid + src_data + data on source grid - dst_data - data on destination grid + dst_data + data on destination grid - missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ self.apply(src_data, dst_data, missingValue) @@ -886,15 +889,15 @@ def getIndicesAndWeights(self, dst_indices): Parameters ---------- - dst_indices - index set on the target grid + dst_indices + index set on the target grid - _: None + _: None Returns ------- - [index sets on original grid, weights] + [index sets on original grid, weights] """ dinds = numpy.array(dst_indices) sinds = (c_int * 2**self.rank)() @@ -924,10 +927,10 @@ def _extend(self, src_data): Parameters ---------- - src_data - input source data + src_data + input source data - _: None + _: None Returns ------- @@ -969,17 +972,17 @@ def _findIndices(self, targetPos, nitermax, tolpos, Parameters ---------- - targetPos - numpy array of target positions + targetPos + numpy array of target positions - nitermax - max number of iterations + nitermax + max number of iterations - tolpos - max toelrance in positions + tolpos + max toelrance in positions - dindicesGuess - guess for the floating point indices + dindicesGuess + guess for the floating point indices Returns ------- From 93b206e70e30afa77b37161168f29f2f811ee8cb Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 30 May 2018 15:07:48 -0700 Subject: [PATCH 164/239] Changes made to API --- Lib/MV2.py | 3 ++- Lib/gengrid.py | 2 +- Lib/mvBaseWriter.py | 15 +++++++++++- Lib/mvCdmsRegrid.py | 57 ++++++++++++++++++++++++--------------------- Lib/tvariable.py | 1 + regrid2/Lib/esmf.py | 18 +++++++------- 6 files changed, 58 insertions(+), 38 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index d3feb738..95504879 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -949,7 +949,8 @@ def ones(myshape, typecode=float, savespace=0, axes=None, def outerproduct(a, b): - """outerproduct(a,b) = {a[i]*b[j]}, has shape (len(a),len(b))""" + """outerproduct(a,b) = {a[i]*b[j]}, has shape (len(a),len(b)) + """ ta = asVariable(a, writeable=1) tb = asVariable(b, writeable=1) maresult = numpy.ma.outerproduct(ta, tb) diff --git a/Lib/gengrid.py b/Lib/gengrid.py index 23c4c70c..aea1197f 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -396,7 +396,7 @@ def __repr__(self): class TransientGenericGrid(AbstractGenericGrid): - + grid_count = 0 def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None): diff --git a/Lib/mvBaseWriter.py b/Lib/mvBaseWriter.py index 38f76d46..0421f46a 100644 --- a/Lib/mvBaseWriter.py +++ b/Lib/mvBaseWriter.py @@ -12,9 +12,22 @@ class BaseWriter: + """ + Constructor + Parameters + ---------- - def __init__(self, var, sphereRadius=1.0, maxElev=0.1): + var + a cdms2 variable + + sphereRadius + radius of the sphere upon which the grid will be projected + + maxElev + max elevation/depth normalized to the sphere radius + """ + def __init__(self, var, sphereRadius=1.0, maxElev=0.1): """ Constructor diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index 63e77bd9..2bbf5537 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -22,9 +22,11 @@ def _areCellsOk(cornerCoords, mask=None): Parameters ---------- - cornerCoords + cornerCoords - mask checks will not be performed where mask is 1 (True) + mask checks will not be performed where mask is 1 (True) + + _: None Returns ------- @@ -56,7 +58,8 @@ def projectToSphere(the, lam): Returns ------- - x, y, z coordinates in Cartesian space""" + x, y, z coordinates in Cartesian space + """ ct = numpy.cos(the) return ct * numpy.cos(lam), ct * numpy.sin(lam), numpy.sin(the) @@ -181,13 +184,15 @@ def _buildBounds(bounds): Parameters ---------- - bounds - CdmsVar.getBounds() + bounds + CdmsVar.getBounds() + + _:None Returns ------- - ndarrray of corners + ndarrray of corners """ bndShape = [s + 1 for s in bounds.shape[:-1]] @@ -212,22 +217,22 @@ def getBoundList(coordList, mask=None, Parameters ---------- - coordList - coordinate list, should have getBounds() + coordList + coordinate list, should have getBounds() - mask - avoid checking areas where mask is one + mask + avoid checking areas where mask is one - removeBadCells - set to True if you want to the code to remove bad cells, ie zero cells, butterfly cells, ... + removeBadCells + set to True if you want to the code to remove bad cells, ie zero cells, butterfly cells, ... - maskCellIndices - list of bad cell indices to mask out (output) + maskCellIndices + list of bad cell indices to mask out (output) Returns ------- - [latBounds, lonBounds] + [latBounds, lonBounds] """ cornerCoords = [] for c in coordList: @@ -262,7 +267,7 @@ def _getCoordList(grid): Returns ------- - lats, lons + lats, lons """ lats = grid.getLatitude() @@ -288,16 +293,16 @@ def _getDstDataShape(srcVar, dstGrid): Parameters ---------- - srcVar - the variable from which all axes other than lat/lon will be taken from + srcVar + the variable from which all axes other than lat/lon will be taken from - dstGrid - target, horizontal grid + dstGrid + target, horizontal grid Returns ------- - list + list """ shp = srcVar.shape @@ -334,16 +339,16 @@ def _getAxisList(srcVar, dstGrid): Parameters ---------- - srcVar - the variable from which all axes other than lat/lon will be taken from + srcVar + the variable from which all axes other than lat/lon will be taken from - dstGrid - target, horizontal grid + dstGrid + target, horizontal grid Returns ------- - variable with non-horizontal axes from srcVar and horizontal axes from dstGrid + variable with non-horizontal axes from srcVar and horizontal axes from dstGrid """ shp = srcVar.shape diff --git a/Lib/tvariable.py b/Lib/tvariable.py index 54d6206b..b68a6ed3 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -1,3 +1,4 @@ + # Automatically adapted for numpy.oldnumeric Aug 01, 2007 by # Further modified to be pure new numpy June 24th 2008 diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index e81cfa6f..02eb38b7 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -37,7 +37,7 @@ class EsmfUnstructGrid: """ - + Constructor Parameters ---------- @@ -50,7 +50,7 @@ class EsmfUnstructGrid: """ def __init__(self, numTopoDims, numSpaceDims): - """Constructor + """ """ @@ -92,7 +92,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- .. figure:: /images/ESMF.jpg - :scale: 95% + :scale: 55% :alt: 3 4-------------3 /\ | | @@ -819,14 +819,14 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): Parameters ---------- - srcField - source field (or None if src field passed to constructor is to be used) + srcField + source field (or None if src field passed to constructor is to be used) - dstField - destination field (or None if dst field passed to constructor is to be used) + dstField + destination field (or None if dst field passed to constructor is to be used) - zero_region - specify which region of the field indices will be zeroed (or None default to TOTAL Region) + zero_region + specify which region of the field indices will be zeroed (or None default to TOTAL Region) """ if srcField is None: srcField = self.srcField From c390ee62c53322670289065f7f245b11fc489e6b Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 31 May 2018 15:52:04 -0700 Subject: [PATCH 165/239] Changes made to API --- Lib/avariable.py | 5 ++- Lib/grid.py | 94 +++++++++++++++++++++++++++++++++++++++++++++ Lib/mvBaseWriter.py | 2 +- 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 35762f0e..ccd2c92d 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -867,8 +867,9 @@ def getSlice(self, *specs, **keys): #. an instance of the slice class #. a tuple, which will be used as arguments to create a slice #. `None` or `:`, which means a slice covering that entire dimension - #. Ellipsis (...), which means to fill the slice list with `:` - leaving only enough room at the end for the remaining positional arguments + #. Ellipsis (...), which means to fill the slice list with `:` + + leaving only enough room at the end for the remaining positional arguments There can be keyword arguments of the form key = value, where key can be one of the names `time`, `level`, `latitude`, or diff --git a/Lib/grid.py b/Lib/grid.py index a777ed0c..ebb50bc2 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -24,6 +24,9 @@ def setClassifyGrids(mode): + """ + Not documented + """ global _classifyGrids if mode == 'on': _classifyGrids = 1 @@ -34,6 +37,10 @@ def setClassifyGrids(mode): def createRectGrid(lat, lon, order="yx", type="generic", mask=None): + """ + Not documented + """ + return TransientRectGrid(lat, lon, order, type, mask) # Generate a uniform rectilinear grid @@ -41,6 +48,10 @@ def createRectGrid(lat, lon, order="yx", type="generic", mask=None): def createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order="yx", mask=None): + """ + Not documented + """ + lat = createUniformLatitudeAxis(startLat, nlat, deltaLat) lon = createUniformLongitudeAxis(startLon, nlon, deltaLon) return createRectGrid(lat, lon, order, "uniform", mask) @@ -50,6 +61,9 @@ def createUniformGrid(startLat, nlat, deltaLat, startLon, def createGlobalMeanGrid(grid): + """ + Not documented + """ inlat = grid.getLatitude() inlatBounds, inlonBounds = grid.getBounds() outlatArray = numpy.array([(inlat[0] + inlat[-1]) / 2.0]) @@ -70,6 +84,9 @@ def createGlobalMeanGrid(grid): def createZonalGrid(grid): + """ + Not documented + """ inlat = grid.getLatitude() outlatBounds, inlonBounds = grid.getBounds() outlat = createAxis(inlat[:], outlatBounds) @@ -88,6 +105,9 @@ def createZonalGrid(grid): def createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order="yx", mask=None): + """ + Not documented + """ lat = createAxis(latArray, latBounds) lat.units = "degrees_north" lon = createAxis(lonArray, lonBounds) @@ -205,6 +225,7 @@ def setRegionSpecs(grid, coordSpec, coordType, resultSpec): class AbstractGrid (CdmsObj): def __init__(self, node): + CdmsObj.__init__(self, node) self.id = '' # String identifier if node is not None and hasattr(node, 'id'): @@ -329,6 +350,7 @@ def listall(self, all=None): return result def _getshape(self): + if self._order_ == "yx": return (len(self._lataxis_), len(self._lonaxis_)) else: @@ -336,6 +358,9 @@ def _getshape(self): # Get the n-th axis. naxis is 0 or 1. def getAxis(self, naxis): + """ + Not documented + """ ind = self._order_[naxis] if ind == 'x': axis = self.getLongitude() @@ -344,6 +369,9 @@ def getAxis(self, naxis): return axis def getBounds(self): + """ + Not documented + """ latbnds, lonbnds = (self._lataxis_.getExplicitBounds(), self._lonaxis_.getExplicitBounds()) if (latbnds is None or lonbnds is None) and getAutoBounds() in [1, 2]: @@ -356,24 +384,45 @@ def getBounds(self): return (latbnds, lonbnds) def getLatitude(self): + """ + Not documented + """ return self._lataxis_ def getLongitude(self): + """ + Not documented + """ return self._lonaxis_ def getMask(self): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def setMask(self, mask, permanent=0): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def getOrder(self): + """ + Not documented + """ return self._order_ def getType(self): + """ + Not documented + """ return self._gridtype_ def setType(self, gridtype): + """ + Not documented + """ if gridtype == 'linear': gridtype = 'uniform' if gridtype == 'unknown': @@ -387,6 +436,9 @@ def setType(self, gridtype): # lonWeights[i] = abs(lonBnds[i+1] - lonBnds[i])/360.0 # Assumes that both axes are represented in degrees. def getWeights(self): + """ + Not documented + """ latBounds, lonBounds = self.getBounds() latBounds = (numpy.pi / 180.0) * latBounds @@ -401,6 +453,9 @@ def getWeights(self): # Create a transient grid for the index (tuple) intervals. def subGrid(self, latinterval, loninterval): + """ + Not documented + """ if latinterval is None: latinterval = (0, len(self._lataxis_)) if loninterval is None: @@ -424,12 +479,18 @@ def subGrid(self, latinterval, loninterval): # Same as subGrid, for coordinates def subGridRegion(self, latRegion, lonRegion): + """ + Not documented + """ latInterval = self._lataxis_.mapInterval(latRegion) lonInterval = self._lonaxis_.mapInterval(lonRegion) return self.subGrid(latInterval, lonInterval) # Return a transient grid which is the transpose of this grid def transpose(self): + """ + Not documented + """ if self._order_ == "yx": neworder = "xy" else: @@ -453,6 +514,9 @@ def transpose(self): # isoffset is true iff this is a BOUNDARY grid, hence the bounds # are the points wrt nlat, plus the poles. def classify(self): + """ + Not documented + """ import regrid2._regrid CLOSE_ENOUGH = 1.e-3 @@ -539,6 +603,9 @@ def classify(self): # basegrid is the full grid, if this is regional, or None # latindex is index into basegrid latitude, or None def classifyInFamily(self, gridlist): + """ + Not documented + """ gridtype, nlats, isoffset = self.classify() coverage = 'global' basegrid = None @@ -567,6 +634,9 @@ def classifyInFamily(self, gridlist): # Generate default bounds def genBounds(self): + """ + Not documented + """ import regrid2._regrid if hasattr(self, "parent") and self.parent is not None: @@ -784,6 +854,9 @@ def toCurveGrid(self, gridid=None): return grid def toGenericGrid(self, gridid=None): + """ + Not documented + """ curvegrid = self.toCurveGrid() gengrid = curvegrid.toGenericGrid(gridid=gridid) return gengrid @@ -808,6 +881,9 @@ def __init__(self, parent, rectgridNode=None): # Set pointers to related structural elements: lon, lat axes, order, mask def initDomain(self, axisdict, vardict): + """ + Not documented + """ if self.latitude not in axisdict: raise CDMSError('No such latitude: %s' % repr(self.latitude)) if self.longitude not in axisdict: @@ -824,6 +900,9 @@ def initDomain(self, axisdict, vardict): self._maskVar_ = None def getMask(self): + """ + Not documented + """ if self._maskVar_ is None: # return numpy.ones(self.shape) return None @@ -831,6 +910,9 @@ def getMask(self): return self._maskVar_[:] def getMaskVar(self): + """ + Not documented + """ return self._maskVar_ # internattr.add_internal_attribute(RectGrid) @@ -856,11 +938,17 @@ def __init__(self, parent, gridname, latobj, lonobj, # Set bounds. If persistent==1, write to file, else just shadow any file # boundaries. def setBounds(self, latBounds, lonBounds, persistent=0): + """ + Not documented + """ self._lataxis_.setBounds(latBounds, persistent) self._lonaxis_.setBounds(lonBounds, persistent) # Return the mask array (NOT the mask variable). def getMask(self): + """ + Not documented + """ if self._tempMask_ is not None: return self._tempMask_ elif self._maskVar_ is None: @@ -872,6 +960,9 @@ def getMask(self): # Set the mask to array 'mask'. If persistent == 1, modify permanently # in the file, else set as a temporary mask. def setMask(self, mask, persistent=0): + """ + Not documented + """ if persistent != 0: raise CDMSError(MethodNotImplemented) if mask is None: @@ -884,6 +975,9 @@ def setMask(self, mask, persistent=0): self._tempMask_ = copy.copy(mask) def getMaskVar(self): + """ + Not documented + """ return self._maskVar_ # internattr.add_internal_attribute(FileRectGrid) diff --git a/Lib/mvBaseWriter.py b/Lib/mvBaseWriter.py index 0421f46a..0159791d 100644 --- a/Lib/mvBaseWriter.py +++ b/Lib/mvBaseWriter.py @@ -27,7 +27,7 @@ class BaseWriter: maxElev max elevation/depth normalized to the sphere radius """ - def __init__(self, var, sphereRadius=1.0, maxElev=0.1): + def __init__(self, var, sphereRadius=1.0, maxElev=0.1): """ Constructor From 1b5ad8a1a38518113e9dff14a2a2e32ee3367488 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 1 Jun 2018 14:51:15 -0700 Subject: [PATCH 166/239] Changes made to Section 2 and API --- Lib/grid.py | 15 +++ Lib/hgrid.py | 15 +++ docs/source/manual/cdms_2.rst | 230 +++++++++++++++++++++------------- 3 files changed, 172 insertions(+), 88 deletions(-) diff --git a/Lib/grid.py b/Lib/grid.py index ebb50bc2..e08bcc39 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -268,6 +268,9 @@ def hasCoordType(self, coordType): return 0 def getAxisList(self): + """ + Not documented + """ axes = [] for i in range(len(self._order_)): axes.append(self.getAxis(i)) @@ -690,6 +693,9 @@ def genBounds(self): return (latbnds, lonbnds) def writeToFile(self, file): + """ + Not documented + """ return None def getMesh(self): @@ -1005,6 +1011,9 @@ def __init__(self, latobj, lonobj, order, gridtype, maskarray=None): self.setMask(maskarray) # numpy mask array def getMask(self): + """ + Not documented + """ if self._maskArray_ is None: # return numpy.ones(self.shape) return None @@ -1014,6 +1023,9 @@ def getMask(self): # Set the mask. The persistent argument is provided for compatibility # with persistent versions, is ignored. def setMask(self, mask, persistent=0): + """ + Not documented + """ if mask is not None: if not isinstance(mask, numpy.ndarray): raise CDMSError('Mask must be a numpy array') @@ -1022,6 +1034,9 @@ def setMask(self, mask, persistent=0): self._maskArray_ = copy.copy(mask) def setBounds(self, latBounds, lonBounds): + """ + Not documented + """ self._lataxis_.setBounds(latBounds) self._lonaxis_.setBounds(lonBounds) diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 310df3f0..a2d5bc08 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -48,10 +48,16 @@ def __init__(self, latAxis, lonAxis, id=None, # Generate default bounds def genBounds(self): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) # Get the n-th axis. naxis is 0 or 1. def getAxis(self, naxis): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def getBounds(self): @@ -99,14 +105,23 @@ def getWeightsArray(self): raise CDMSError(MethodNotImplemented) def listall(self, all=None): + """ + Not documented + """ result = [] result.append('Grid has Python id %s.' % hex(id(self))) return result def setMask(self, mask, permanent=0): + """ + Not documented + """ self._maskVar_ = mask def subGridRegion(self, latRegion, lonRegion): + """ + Not documented + """ raise CDMSError(MethodNotImplemented) def hasCoordType(self, coordType): diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 16e5c1bf..311c4ec1 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -46,8 +46,8 @@ the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: -Table PythonTypes used in CDMS -------------------------------- +PythonTypes used in CDMS +------------------------ .. csv-table:: :header: "Type", "Description" :widths: 10, 80 @@ -134,8 +134,8 @@ Rather, they are called as module functions, e.g., -Table Cdms Module Functions ---------------------------- +Cdms Module Functions +--------------------- .. csv-table:: :header: "Type", "Definition" @@ -223,8 +223,8 @@ Table Cdms Module Functions -Table Class Tags --------------------- +Class Tags +---------- .. csv-table:: :header: "Tag", "Class" :widths: 20, 20 @@ -258,8 +258,8 @@ external attributes are written, but not the internal attributes. >>> extatts = obj.attributes.keys() -Table Attributes Common to All CDMS Objects -------------------------------------------- +Attributes Common to All CDMS Objects +------------------------------------- .. csv-table:: Attributes common to all CDMS objects :header: "Type", "Name", "Definition" @@ -268,8 +268,8 @@ Table Attributes Common to All CDMS Objects "Dictionary", "attributes", "External attribute dictionary for this object." -Table Getting and Setting Attributes ------------------------------------- +Getting and Setting Attributes +------------------------------ .. csv-table:: :header: "Type", "Definition" :widths: 20, 80 @@ -296,8 +296,8 @@ documents methods that are common to all CoordinateAxis types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D Axis objects. -Table CoordinateAxis Types --------------------------- +CoordinateAxis Types +-------------------- .. csv-table:: :header: "Type", "Definition" @@ -308,8 +308,8 @@ Table CoordinateAxis Types "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." -Table CoordinateAxis Internal Attributes ----------------------------------------- +CoordinateAxis Internal Attributes +---------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -320,8 +320,8 @@ Table CoordinateAxis Internal Attributes "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." -Table Axis Constructors ------------------------ +CoordinateAxis Constructors +--------------------------- .. csv-table:: :header: "Constructor", "Description" @@ -342,8 +342,8 @@ Table Axis Constructors , "* See `A First Example`_ ." -Table CoordinateAxis Methods ----------------------------- +CoordinateAxis Methods +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -381,8 +381,8 @@ Table CoordinateAxis Methods "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." -Table Axis Methods, Additional to CoordinateAxis ------------------------------------------------- +CoordinateAxis Methods, Additional to CoordinateAxis +---------------------------------------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -419,8 +419,8 @@ Table Axis Methods, Additional to CoordinateAxis ,,"* see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." -Table Axis Slice Operators --------------------------- +CoordinateAxis Slice Operators +------------------------------ .. csv-table:: :header: "Slice", "Definition" @@ -463,9 +463,8 @@ formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only. As of CDMS V3, the legacy cuDataset interface is also supported by Cdms-Files. See “cu Module”. - -Table CdmsFile Internal Attributes ----------------------------------- +CdmsFile Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -477,8 +476,8 @@ Table CdmsFile Internal Attributes "``String``", "``id``", "File pathname." "``Dictionary``", "``variables``", "Variables contained in the file." -Table CdmsFile Constructors ---------------------------- +CdmsFile Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -489,8 +488,8 @@ Table CdmsFile Constructors "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." -Table CdmsFile Methods ----------------------- +CdmsFile Methods Object Name Transient Variable +------------------------------------------------ .. csv-table:: :header: "Type", "Method", "Definition" @@ -503,6 +502,15 @@ Table CdmsFile Methods ,, " **Example:** The following reads data for variable 'prc', year 1980:" ,, " * >>> f = cdms.open('test.nc')" ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" + +CdmsFile Methods Object Identifier Variable, Axis or Grid +--------------------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." ,, " **Example:** The following gets the persistent variable" ,, " * ``v``, equivalent to" @@ -513,16 +521,55 @@ Table CdmsFile Methods ,, " * ``t = f.axes['time']``." ,, " * ``t = f['time']``" "``None``", "``close()``", "Close the file." + +CdmsFile Methods Copy Axis, Grid +-------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + +CdmsFile Methods Create Axis, RectGrid and Variable +---------------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + + +CdmsFile Methods Read CurveGrid, Generic-Grid +--------------------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." + + +CdmsFile Methods Write Variable +------------------------------- + +.. csv-table:: + :header: "Type", "Method", "Definition" + :widths: 10, 30, 80 + :align: left + + + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." ,,"* ``var`` is a Variable, masked array, or Numpy array." ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." @@ -535,8 +582,8 @@ Table CdmsFile Methods ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." -Table CDMS Datatypes --------------------- +CDMS Datatypes +-------------- .. csv-table:: :header: "CDMS Datatype", "Definition" @@ -627,8 +674,8 @@ To access a database: ``db.close()`` -Table Database Internal Attributes ----------------------------------- +Database Internal Attributes +---------------------------- .. csv-table:: @@ -642,8 +689,8 @@ Table Database Internal Attributes "``String``", "``uri``", "Uniform Resource Identifier" -Table Database Constructors ---------------------------- +Database Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -655,8 +702,8 @@ Table Database Constructors ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" -Table Database Methods ----------------------- +Database Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -807,8 +854,8 @@ variables defined on a 94x192 grid: -Table SearchResult Methods --------------------------- +SearchResult Methods +-------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -828,8 +875,8 @@ information defined for the associated CDMS object, which is retrieved with the ``getObject`` method. -Table ResultEntry Attributes ----------------------------- +ResultEntry Attributes +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -839,8 +886,8 @@ Table ResultEntry Attributes "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" -Table ResultEntry Methods -------------------------- +ResultEntry Methods +------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -851,7 +898,7 @@ Table ResultEntry Methods Accessing data --------------------- +-------------- To access data via CDMS: @@ -870,7 +917,7 @@ In the next example, a portion of variable ‘ua’ is read from dataset Examples of Database Searches ------------------------------------ +----------------------------- In the following examples, db is the database opened with: @@ -956,8 +1003,8 @@ As of CDMS V3, the legacy cuDataset interface is supported by Datasets. See “cu Module". -Table Dataset Internal Attributes ---------------------------------- +Dataset Internal Attributes +--------------------------- .. csv-table:: :header: "Type", "Name", "Description" @@ -973,8 +1020,8 @@ Table Dataset Internal Attributes "Dictionary", "``variables``", "Variables contained in the dataset." "Dictionary", "``xlinks``", "External links contained in the dataset." -Table Dataset Constructors --------------------------- +Dataset Constructors +-------------------- .. csv-table:: :header: "Constructor", "Description" @@ -984,12 +1031,12 @@ Table Dataset Constructors "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" -Table Open Modes ----------------- +Open Modes +---------- .. csv-table:: :header: "Mode", "Definition" - :widths: 50, 70 + :widths: 10, 70 :align: left "‘r’", "read-only" @@ -998,8 +1045,8 @@ Table Open Modes "‘w’", "Create a new file, read-write" -Table Dataset Methods ---------------------- +Dataset Methods +--------------- .. csv-table:: :header: "Type", "Definition", "Description" @@ -1009,13 +1056,20 @@ Table Dataset Methods ,, "**Example:** The following reads data for variable 'prc', year 1980:" ,, " * f = cdms.open('test. xml')" ,, " * x = f('prc', time=('1980-1','1981-1'))" - "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found." - ,, "**Example:**" - ,, " * f = cdms.open('sampl e.xml')" - ,, " * v = f['prc']" - ,, " * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``." - ,, "**Example:**" - ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. + + **Example:** + + * f = cdms.open('sampl e.xml') + * v = f['prc'] + + * gets the persistent variable v equivalent to ``v=f.variables['prc']``. + + **Example:** + + * t = f['time'] + + * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." ,,"``lat`` is a latitude axis in the dataset." @@ -1095,8 +1149,8 @@ https://numpy.sourceforge.net for a description of these functions. -Table Variable Constructors in Module MV ------------------------------------------ +Variable Constructors in Module MV +----------------------------------- .. tabularcolumns:: |l|r| @@ -1121,8 +1175,8 @@ The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. -Table MV Functions ------------------- +MV Functions +------------ .. csv-table:: :header: "Function", "Description" :widths: 50, 80 @@ -1172,8 +1226,8 @@ cells. Specifically, a HorizontalGrid: CDMS supports several types of HorizontalGrids: -Table Grids ------------ +Grids +----- .. csv-table:: :header: "Grid Type", "Definition" @@ -1184,8 +1238,8 @@ Table Grids "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" -Table HorizontalGrid Internal Attribute ---------------------------------------- +HorizontalGrid Internal Attribute +--------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1199,8 +1253,8 @@ Table HorizontalGrid Internal Attribute -Table RectGrid Constructors ---------------------------- +RectGrid Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1220,8 +1274,8 @@ Table RectGrid Constructors -Table HorizontalGrid Methods ----------------------------- +HorizontalGrid Methods +---------------------- .. csv-table:: @@ -1260,8 +1314,8 @@ Table HorizontalGrid Methods ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." -Table RectGrid Methods, Additional to HorizontalGrid Methods ------------------------------------------------------------- +RectGrid Methods, Additional to HorizontalGrid Methods +------------------------------------------------------ .. csv-table:: :header: "Type", "Method", "Description" @@ -1319,8 +1373,8 @@ advantage of the attribute, domain, and mask information in a transient variable. -Table Variable Internal Attributes ----------------------------------- +Variable Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1333,8 +1387,8 @@ Table Variable Internal Attributes "Tuple", "``shape``", "The length of each axis of the variable" -Table Variable Constructors ---------------------------- +Variable Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1349,8 +1403,8 @@ Table Variable Constructors -Table Variable Methods ----------------------- +Variable Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1471,8 +1525,8 @@ Read all data for March, 1980: -Table Variable Slice Operators ------------------------------- +Variable Slice Operators +------------------------ .. csv-table:: :header: "Operator", "Description" @@ -1490,8 +1544,8 @@ Table Variable Slice Operators -Table Index and Coordinate Intervals ------------------------------------- +Index and Coordinate Intervals +------------------------------ .. csv-table:: :header: "Interval Definition", "Example Interval Definition", "Example" @@ -1575,8 +1629,8 @@ components is the positional form, where the component order corresponds to the axis order of a variable. For example: -Table Selector Keywords ------------------------ +Selector Keywords +----------------- .. csv-table:: :header: "Keyword", "Description", "Value" From e9792fb91869f291258519a4fbabd00f7b8f2cb8 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 4 Jun 2018 15:49:48 -0700 Subject: [PATCH 167/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 585 ++++++++++++++++++---------------- 1 file changed, 310 insertions(+), 275 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 311c4ec1..52acb9ae 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -145,10 +145,10 @@ Cdms Module Functions "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" - , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." - , " * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." - , " * See ``setAutoBounds``." - , " * Also see: ``CdmsFile.createAxis``" + , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. + * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * See ``setAutoBounds``. + * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" @@ -156,63 +156,61 @@ Cdms Module Functions "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values." - , " * ``lonArray`` is a NumPy array of longitude values. " - , " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. " - , " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. " - , " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." - , " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values. + * ``lonArray`` is a NumPy array of longitude values. + * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. + * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. + * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. + * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" - , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation." - , " * ``lat`` is a latitude axis, created by ``cdms.createAxis``." - , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." - , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - + , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + * ``lat`` is a latitude axis, created by ``cdms.createAxis``. + * ``lon`` is a longitude axis, created by ``cdms.createAxis``. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" - , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``." - , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." - , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. + * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``. + * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" - , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes." - , " * ``deltaLat`` is the increment between latitudes." + , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. + * ``deltaLat`` is the increment between latitudes." "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" - , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis." - , " * ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes." - , " * ``deltaLon`` is the increment between longitudes." + , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + * ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes + * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." , " * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: " , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" - , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" - , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:" - - , " * Letters t, x, y, z meaning time, longitude, latitude, level" - , " * Numbers 0-9 representing position in axes" - , " * Dash (-) meaning insert the next available axis here." - , " * The ellipsis ... meaning fill these positions with any remaining axes." - , " * (name) meaning an axis whose id is name" + , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * Dash (-) meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``:" , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" @@ -326,20 +324,18 @@ CoordinateAxis Constructors .. csv-table:: :header: "Constructor", "Description" :widths: 20, 80 + :align: left "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" - , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" - , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited``" - , "``cdms.createEqualAreaAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createGaussianAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" - , "* See `A First Example`_ ." + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: + * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or + * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` + + * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. + * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. + * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. + * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." CoordinateAxis Methods @@ -359,19 +355,22 @@ CoordinateAxis Methods "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." - "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis:" - ,,"* ``Axis``: ``(n,2)``" - ,,"* ``Axis2D``: ``(i,j,4)``" - ,,"* ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell." - ,,"If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." - "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are:" - ,,"* ``cdtime.GregorianCalendar``: the standard Gregorian calendar" - ,,"* ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar" - ,,"* ``cdtime.JulianCalendar``: years divisible by 4 are leap years" - ,,"* ``cdtime.NoLeapCalendar``: a year is 365 days" - ,,"* ``cdtime.Calendar360``: a year is 360 days" - ,,"* ``None``: no calendar can be identified" - ,," **Note** If the axis is not a time axis, the global, file-related calendar is returned." + "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: + + * ``Axis``: ``(n,2)`` + * ``Axis2D``: ``(i,j,4)`` + * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. + * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: + + * ``cdtime.GregorianCalendar``: the standard Gregorian calendar + * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar + * ``cdtime.JulianCalendar``: years divisible by 4 are leap years + * ``cdtime.NoLeapCalendar``: a year is 365 days + * ``cdtime.Calendar360``: a year is 360 days + * ``None``: no calendar can be identified + + * **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." @@ -393,30 +392,32 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if:" - ,," * ``axis.topology == 'circular'``, or" - ,," * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: + + * ``axis.topology == 'circular'``, or + * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." - "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None or ':'``" - ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:" - ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" - ,,"* ``'n'`` - select node values which are contained in the interval" - ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" - ,,"* ``'e'`` - same as n, but include an extra node on either side" - ,,"* ``'s'`` - select axis elements for which the cell boundary is a subset of the interval" - ,,"* The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected." - ,,"* If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``." - ,,"* An interval of ``None`` or ``':'`` returns the full index interval of the axis." - ,,"* The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty." - ,,"* for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``" - ,,"* if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint." - ,,"* otherwise the interval wraps around the axis endpoint." - ,,"* see also: ``mapinterval``, ``variable.subregion()``" + "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: + + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None or ':'`` + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: + * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi + * ``'n'`` - select node values which are contained in the interva + * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval + * ``'e'`` - same as n, but include an extra node on either sid + * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval + * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * An interval of ``None`` or ``':'`` returns the full index interval of the axis. + * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. + * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` + * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. + * otherwise the interval wraps around the axis endpoint." + * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." CoordinateAxis Slice Operators @@ -432,16 +433,17 @@ CoordinateAxis Slice Operators "``[:j]``", "the beginning element through, but not including, element ``j``" "``[:]``", "the entire array" "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" - "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." - , " **Example:** a longitude axis has value" - , " * ``[0.0, 2.0, ..., 358.0]``" - , " * of length ``180``" - , " * map the coordinate interval:" - , " * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval" - , " * ``-2 <= n < 3`` wraps around, since" - , " * ``-2 < 0``, and has a stride of ``1``" - , " * this is equivalent to the two contiguous index intervals" - , " * ``2 <= n < 0`` and ``0 <= n < 3``" + "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element. + + * **Example:** a longitude axis has value + * ``[0.0, 2.0, ..., 358.0]`` + * of length ``180`` + * map the coordinate interval: + * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval + * ``-2 <= n < 3`` wraps around, since + * ``-2 < 0``, and has a stride of ``1`` + * this is equivalent to the two contiguous index intervals + * ``2 <= n < 0`` and ``0 <= n < 3``" Example 1 ''''''''''' @@ -498,10 +500,12 @@ CdmsFile Methods Object Name Transient Variable "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, " **Example:** The following reads data for variable 'prc', year 1980:" - ,, " * >>> f = cdms.open('test.nc')" - ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" + ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + + **Example:** The following reads data for variable 'prc', year 1980: + + * >>> f = cdms.open('test.nc') + * >>> x = f('prc', time=('1980-1','1981-1'))" CdmsFile Methods Object Identifier Variable, Axis or Grid --------------------------------------------------------- @@ -511,15 +515,19 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid :widths: 10, 30, 80 :align: left - "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." - ,, " **Example:** The following gets the persistent variable" - ,, " * ``v``, equivalent to" - ,, " * ``v = f.variables['prc']``." - ,, " * f = cdms.open('sample.nc')" - ,, " * v = f['prc']" - ,, " **Example:** The following gets the axis named time, equivalent to" - ,, " * ``t = f.axes['time']``." - ,, " * ``t = f['time']``" + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. + + **Example:** The following gets the persistent variable + + * ``v``, equivalent to + * ``v = f.variables['prc']``. + * f = cdms.open('sample.nc') + * v = f['prc'] + + **Example:** The following gets the axis named time, equivalent to + + * ``t = f.axes['time']``. + * ``t = f['time']``" "``None``", "``close()``", "Close the file." CdmsFile Methods Copy Axis, Grid @@ -544,8 +552,9 @@ CdmsFile Methods Create Axis, RectGrid and Variable "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." - ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + + **Note:** Unlike copyAxis, the actual data is not copied to the new variable." CdmsFile Methods Read CurveGrid, Generic-Grid @@ -570,17 +579,18 @@ CdmsFile Methods Write Variable "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." - ,,"* ``var`` is a Variable, masked array, or Numpy array." - ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." - ,,"* ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``." - ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." - ,,"* ``id`` is the variable name in the file. Default is ``var.id``." - ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." - ,,"* The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." - ,,"* ``fill_value`` is the missing value flag." - ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." - ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." + ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. + + * ``var`` is a Variable, masked array, or Numpy array. + * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``. + * ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``. + * ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``. + * ``id`` is the variable name in the file. Default is ``var.id``. + * ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable. + * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour. + * ``fill_value`` is the missing value flag. + * ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. + **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." CDMS Datatypes -------------- @@ -711,33 +721,37 @@ Database Methods "None", "``close()``", "Close a database" "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." - "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." - , "* ``dsetid``","is the string dataset identifier" - , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." - , "* ``openDataset``", "is a synonym for ``open``." + "Dataset", "``open(dsetid, mode='r')``", "Open a dataset. + + * ``dsetid``, is the string dataset identifier + + * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + + * ``openDataset``, is a synonym for ``open``." "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." - ,, - ,," **Example:**" - ,," * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'." - ,," - A formal definition of search filters is provided in the following section." - ,," - ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." - ,," - ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." - ,, - ,," **Example:**" - ,," * To search only dataset 'ncep_reanalysis_mo', specify:" - ,," - ``relbase='dataset=ncep_reanalysis_mo'``" - ,," * To search only variable 'ua' in 'ncep_reanalysis_mo', use:" - ,," - ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``" - ,, - ,,"If no base is specified, the entire database is searched. See the ``scope`` argument also." - ,,"``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**)." - ,," * **Subtree** searches the base object and its descendants." - ,," * **Onelevel** searches the base object and its immediate descendants." - ,," * **Base**\ searches the base object alone." - ,," * The default is **Subtree**." - ,,"``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." - ,,"``timeout``: integer number of seconds before timeout. The default is no timeout." + ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + **Example:** + + * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. + * A formal definition of search filters is provided in the following section. + * ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid'). + * ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy. + + **Example:** + + * To search only dataset 'ncep_reanalysis_mo', specify: + * ``relbase='dataset=ncep_reanalysis_mo'`` + * To search only variable 'ua' in 'ncep_reanalysis_mo', use: + * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'`` + If no base is specified, the entire database is searched. See the ``scope`` argument also. + + * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**). + * **Subtree** searches the base object and its descendants. + * **Onelevel** searches the base object and its immediate descendants. + * **Base**\ searches the base object alone. + * The default is **Subtree**. + * ``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list. + * ``timeout``: integer number of seconds before timeout. The default is no timeout." ------------ @@ -1052,10 +1066,14 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, "**Example:** The following reads data for variable 'prc', year 1980:" - ,, " * f = cdms.open('test. xml')" - ,, " * x = f('prc', time=('1980-1','1981-1'))" + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + + **Example:** The following reads data for variable 'prc', year 1980: + + * f = cdms.open('test. xml') + + * x = f('prc', time=('1980-1','1981-1'))" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. **Example:** @@ -1071,22 +1089,24 @@ Dataset Methods * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." - ,,"``lat`` is a latitude axis in the dataset." - ,,"``lon`` is a longitude axis in the dataset." - ,,"``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" - ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." - ,,"``id`` is the string axis identifier." - "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset." - ,,"``id`` is the string grid identifier." + "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the dataset. + * ``lon`` is a longitude axis in the dataset. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic' + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset. + * ``id`` is the string axis identifier." + "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset. + * ``id`` is the string grid identifier." "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." - "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." - ,,"``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." - ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``." - ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset. + * ``id`` is the string variable identifier." + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile. + + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1285,33 +1305,37 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" - ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." - ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." - ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." - ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``)." - ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + + * for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." - "Axis", "``getLongitude()``", " Get the latitude axis of this grid." + "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." - "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.``" - ,,"``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively." - ,,"Each interval is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None``" - ,,"where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" - ,,"``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." - ,,"If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0." - ,,"An interval of ``None`` returns the full index interval of the axis." - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." - ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` + + * ``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively. + * Each interval is a tuple having one of the forms: + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None`` + + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: + + * ``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co'). + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. + * An interval of ``None`` returns the full index interval of the axis. + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. + **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." RectGrid Methods, Additional to HorizontalGrid Methods @@ -1321,28 +1345,36 @@ RectGrid Methods, Additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." - ,,"The latitude weights are defined as:" - ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" - ,," The longitude weights are defined as:" - ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" - ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" - ,,"**Example:**" - ,,"Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``." - ,,"* from cdms import MV" - ,,"* latwts, lonwts = gri d.getWeights()" - ,,"* weights = MV.outerproduct(latwts, lonwts)" - ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees. + + * The latitude weights are defined as: + * ``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`` + + * The longitude weights are defined as: + * ``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0`` + + * For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0 + + **Example:** + + * Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``. + * from cdms import MV + * latwts, lonwts = gri d.getWeights() + * weights = MV.outerproduct(latwts, lonwts) + * Also see the function ``area_weights`` in module ``pcmdi.weighting``." ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." - ,,"**Example:**" - ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." - ,,"``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))``" - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges." - ,,"**Note:** The result grid is not associated with any file or dataset." - "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed." - ,,"**Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + + **Example:** + + * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. + * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + + **Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1397,8 +1429,9 @@ Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." - "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." - ,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. + + * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1417,54 +1450,56 @@ Variable Methods "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." - "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." - ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." - "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time." - ,,"* ``newLevel`` is an axis of the result pressure levels." - ,,"* ``newLatitude`` is an axis of the result latitudes." - ,,"* ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,,"* ``missing`` is a missing data value. The default is ``var.getMissing()``" - ,,"* ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``." - ,,"*See also:* ``regrid``, ``pressureRegrid``." - "Axis", "``getAxis(n)``", "Get the n-th axis." - ,,"``n`` is an integer." + "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. + * If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." + "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``newLatitude`` is an axis of the result latitudes. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``. + * See also:* ``regrid``, ``pressureRegrid``." + "Axis", "``getAxis(n)``", "Get the n-th axis. + * ``n`` is an integer." "List", "``getAxisIds()``", "Get a list of axis identifiers." - "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." - ,,"``axis_spec`` is a specification as defined for getAxisList" - "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable." - ,,"If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." - ,,"If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." - ,,"``order`` is an optional string determining the output order." - ,,"Specifications for the axes or omit keywords are a list, each element having one of the following forms:" - ,,"* an integer dimension index, starting at 0." - ,,"* a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'." - ,,"* a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches." - ,,"* an axis object; will match if it is the same object as axis." - ,,"``order`` can be a string containing the characters t,x,y,z, or * ." - ,,"If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." + "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match. + * ``axis_spec`` is a specification as defined for getAxisList" + "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable. + * If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given. + * If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below. + * ``order`` is an optional string determining the output order. + * Specifications for the axes or omit keywords are a list, each element having one of the following forms: + * an integer dimension index, starting at 0. + * a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'. + * a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches. + * an axis object; will match if it is the same object as axis. + * ``order`` can be a string containing the characters t,x,y,z, or * . + * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." - "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found." - ,, "String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" - ,, "* 't': time" - ,, "* 'z': vertical level" - ,, "* 'y': latitude" - ,, "* 'x': longitude" - ,, "* '-': the axis is not spatio-temporal." - ,, "**Example:**" - ,, "A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." - ,, "**Note:** The order string is of the form required for the order argument of a regridder function." - ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." - ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." - ,, "**Note:** This function is not defined for transient variables." + "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found. + String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of: + * 't': time + * 'z': vertical level + * 'y': latitude + * 'x': longitude + * '-': the axis is not spatio-temporal. + **Example:** + A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude). + + **Note:** The order string is of the form required for the order argument of a regridder function. + * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned. + + * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. + **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." - "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." - ,,"**Note:** ``size()`` returns the total number of elements." + "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. + **Note:** ``size()`` returns the total number of elements." "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." ,, "``newLevel`` is an axis of the result pressure levels." ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." @@ -1472,32 +1507,32 @@ Variable Methods ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" ,, "See also: ``regrid``, ``crossSectionRegrid``." "Integer", "``rank()``", "The number of dimensions of the variable." - "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid." - ,, "``missing`` is a Float specifying the missing data value. The default is 1.0e20." - ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." - ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." - ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." + "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." - "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." - ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." - ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." - ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." - ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" - ,,"* a single integer n, meaning ``slice(n, n+1)``" - ,,"* an instance of the slice class" - ,,"* a tuple, which will be used as arguments to create a slice" - ,,"* ':', which means a slice covering that entire dimension" - ,,"* Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments" - ,,"* a Python slice object, of the form ``slice(i,j,k)``" - ,,"If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read." - ,,"The keyword arguments are defined as in subRegion." - ,,"There must be no conflict between the positional arguments and the keywords." - ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." - ,,"String ``typecode()`` The Numpy datatype identifier." + "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``. + * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. + * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. + * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." + "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off. + * ``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form: + * a single integer n, meaning ``slice(n, n+1)`` + * an instance of the slice class + * a tuple, which will be used as arguments to create a slice + * ':', which means a slice covering that entire dimension + * Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments + * a Python slice object, of the form ``slice(i,j,k)`` + * If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read. + * The keyword arguments are defined as in subRegion. + * There must be no conflict between the positional arguments and the keywords. + * In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing. + * String ``typecode()`` The Numpy datatype identifier." Example Get a Region of Data. ----------------------------- From 01ba90a83818f3b4f3f6f42bba76e9983236816b Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 5 Jun 2018 14:52:22 -0700 Subject: [PATCH 168/239] Changes made to Chapter 2 --- docs/source/manual/cdms_2.rst | 89 +++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 52acb9ae..3c6bde95 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -161,11 +161,9 @@ Cdms Module Functions * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. - * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." - + * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. @@ -186,7 +184,8 @@ Cdms Module Functions * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." - "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." + "``RectGrid``","``createZonalGrid(grid)``:" + ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. @@ -200,7 +199,9 @@ Cdms Module Functions "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." @@ -212,11 +213,20 @@ Cdms Module Functions * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: + * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. + * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." + , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. + * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. + * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." + , "Write a grid to a SCRIP grid file. + * ``path`` is a string, the path of the SCRIP file to be created. + * ``grid`` is a CDMS grid object. It may be rectangular. + * ``gridTitle`` is a string ID for the grid." +: @@ -487,7 +497,9 @@ CdmsFile Constructors :align: left - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. + * ``path`` is the file pathname, a string. + * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." CdmsFile Methods Object Name Transient Variable @@ -538,8 +550,14 @@ CdmsFile Methods Copy Axis, Grid :widths: 10, 30, 80 :align: left - "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." - "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. + * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. + * ``axis`` is the axis object to be copied. + * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. + * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. + * ``grid`` is the grid object to be copied. + * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." CdmsFile Methods Create Axis, RectGrid and Variable ---------------------------------------------------- @@ -549,10 +567,23 @@ CdmsFile Methods Create Axis, RectGrid and Variable :widths: 10, 30, 80 :align: left - "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. + * ``id`` is an alphanumeric string identifier, containing no blanks. + * ``ar`` is the one-dimensional axis array. + * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. + * ``lon`` is a longitude axis in the file. + * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). + * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. + * ``id`` is a String name which is unique with respect to all other objects in the file. + * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. + * ``axes`` is a list of Axis and/or Grid objects. + * ``fill_value`` is the missing value (optional)." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." @@ -565,7 +596,10 @@ CdmsFile Methods Read CurveGrid, Generic-Grid :widths: 10, 30, 80 :align: left - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." @@ -578,8 +612,9 @@ CdmsFile Methods Write Variable :align: left - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable. + * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. + * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. * ``var`` is a Variable, masked array, or Numpy array. * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``. @@ -708,9 +743,11 @@ Database Constructors :align: left - "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." - ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." - ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database. + * For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. + * For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. + * If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. + * If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" Database Methods ---------------- @@ -728,8 +765,8 @@ Database Methods * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. * ``openDataset``, is a synonym for ``open``." - "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database. + * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. **Example:** * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. @@ -877,8 +914,10 @@ SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." - "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." - ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. + * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. + * ``tag`` restricts the search to objects of the class denoted by the tag. + **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -1270,6 +1309,8 @@ HorizontalGrid Internal Attribute "String", "``id``", "The grid identifier." "Dataset or CdmsFile", "``parent``", "The dataset or file which contains the grid." "Tuple", "``shape``", "The shape of the grid, a 2-tuple" +:: + From 691b1107344b213303e2c2baa110f4aa675db9de Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 6 Jun 2018 15:43:33 -0700 Subject: [PATCH 169/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 105 +++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 3c6bde95..a4c914e2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -143,27 +143,39 @@ Cdms Module Functions :align: left - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." + "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. + * ``s`` is a masked array, Numpy array, or Variable. + * If ``s`` is already a transient variable, ``s`` is returned. + * See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``:" , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. - * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * ``data`` is a one-dimensional, monotonic Numpy array. + * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, + * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. + * If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + * ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" + , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + * ``nlats`` is the number of latitudes. + * ``xorigin`` is the origin of the longitude axis. + * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values. + , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." + , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. @@ -185,7 +197,8 @@ Cdms Module Functions * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``:" - ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." + ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. @@ -196,15 +209,20 @@ Cdms Module Functions , " * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: " , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. - * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + "``Dataset``", "``open(url,mode='r')``:" + , "Open or create a ``Dataset`` or ``CdmsFile``. + * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. + * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. + * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." + , "Find the index permutation of axes to match order. Return a list of indices. + * ``axes`` is a list of axis objects. + * ``orderstring`` is defined as in ``orderparse``." "``List``", "``orderparse(orderstring)``:" , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: * Letters t, x, y, z meaning time, longitude, latitude, level @@ -216,7 +234,9 @@ Cdms Module Functions , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. - * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. + + **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. @@ -338,9 +358,13 @@ CoordinateAxis Constructors "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: - * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or - * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. + * ``name`` is the string ``name`` of the ``Axis``. + * ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. + To define an axis as unlimited, either: + + * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or + * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. @@ -426,7 +450,7 @@ CoordinateAxis Methods, Additional to CoordinateAxis * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. - * otherwise the interval wraps around the axis endpoint." + * otherwise the interval wraps around the axis endpoint. * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." @@ -571,7 +595,8 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``id`` is an alphanumeric string identifier, containing no blanks. * ``ar`` is the one-dimensional axis array. * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the file. * ``lon`` is a longitude axis in the file. * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. @@ -1348,17 +1373,19 @@ HorizontalGrid Methods "Tuple", "``getBounds()``", "Get the grid boundary arrays." ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: - * for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). - * for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). - * for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." - "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." - ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. + * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. + * ``lonBounds`` is defined similarly for the longitude array. + **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` @@ -1375,7 +1402,9 @@ HorizontalGrid Methods * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. * An interval of ``None`` returns the full index interval of the axis. * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. + * If the grid is already curvilinear, a copy of the grid object is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." @@ -1405,7 +1434,7 @@ RectGrid Methods, Additional to HorizontalGrid Methods * Also see the function ``area_weights`` in module ``pcmdi.weighting``." ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. **Example:** @@ -1472,8 +1501,20 @@ Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. - * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." + * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. + * ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. + **Note:** this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. + * ``array`` is the data values: a Variable, masked array, or Numpy array. + * ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. + * ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. + * ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. + * ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. + * ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. + * ``grid`` is a rectilinear grid object. + * ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. + * ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. + * ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1541,12 +1582,12 @@ Variable Methods "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. **Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." - ,, "``newLevel`` is an axis of the result pressure levels." - ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" - ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" - ,, "See also: ``regrid``, ``crossSectionRegrid``." + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()`` + * See also: ``regrid``, ``crossSectionRegrid``." "Integer", "``rank()``", "The number of dimensions of the variable." "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. From 519add279e225e2898584b790fe6f5eb5717486d Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 7 Jun 2018 15:29:06 -0700 Subject: [PATCH 170/239] Changes made to Chapters 2, 3, 4,5 and 6 --- docs/source/manual/cdms_2.rst | 47 +++++++++++++++++-------------- docs/source/manual/cdms_3.rst | 52 ++++++++++++++++++----------------- docs/source/manual/cdms_4.rst | 50 ++++++++++++++++----------------- docs/source/manual/cdms_5.rst | 22 ++++++++------- docs/source/manual/cdms_6.rst | 22 +++++++-------- 5 files changed, 100 insertions(+), 93 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index a4c914e2..dd64eda2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -157,9 +157,12 @@ Cdms Module Functions * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``:" , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. - * ``nlat`` is the axis length. The axis is not associated with a file or dataset." + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." + , "Create a Gaussian latitude axis. Axis values range from north to south. + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. @@ -214,7 +217,7 @@ Cdms Module Functions * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. - * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * ``mode`` is the open mode. See `Open Modes <#id3>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` @@ -319,9 +322,9 @@ It may be contained in a file or dataset, or may be transient file, and referencing a file CoordinateAxis slice reads data from the file. Axis objects are also used to define the domain of a Variable. -CDMS defines several different types of CoordinateAxis objects. See `MV module <#id3>`_ +CDMS defines several different types of CoordinateAxis objects. See `MV module <#id5>`_ documents methods that are common to all CoordinateAxis -types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D +types. See `HorizontalGrid <#id7>`_ specifies methods that are unique to 1D Axis objects. CoordinateAxis Types @@ -381,7 +384,7 @@ CoordinateAxis Methods :align: left - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#id15>`_ for a description of slice operators." "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." @@ -425,7 +428,9 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." - "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. + * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. + **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: * ``axis.topology == 'circular'``, or @@ -523,7 +528,7 @@ CdmsFile Constructors "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. * ``path`` is the file pathname, a string. - * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + * ``mode`` is the open mode indicator, as listed in `Open Modes <#id3>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." CdmsFile Methods Object Name Transient Variable @@ -536,7 +541,7 @@ CdmsFile Methods Object Name Transient Variable "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + ,, "object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -1106,7 +1111,7 @@ Dataset Constructors :widths: 50, 80 :align: left - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#id3>`__ . ``openDataset`` is a synonym for ``open``" Open Modes @@ -1130,7 +1135,7 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. **Example:** The following reads data for variable 'prc', year 1980: @@ -1206,7 +1211,7 @@ The command allows use of MV commands without any prefix. -Table `Variable Constructors in module MV <#table-variable-constructors-in-module-mv>`_, lists the constructors in MV. All functions return +Table `Variable Constructors in module MV <#id5>`_, lists the constructors in MV. All functions return a transient variable. In most cases the keywords axes, attributes, and id are available. axes is a list of axis objects which specifies the domain of the variable. attributes is a dictionary. id is a special @@ -1527,7 +1532,7 @@ Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." @@ -1598,7 +1603,7 @@ Variable Methods "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. - * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1739,7 +1744,7 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_. +ranges as defined in See `Index and Coordinate Intervals <#id11>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds @@ -1753,16 +1758,16 @@ Selector Keywords :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id11>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id11>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id11>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id11>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); = 1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id11>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For @@ -1776,7 +1781,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ are treated as positional. Such +form(s) listed in `Index and Coordinate Intervals <#id11>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index c2df2de6..784451b4 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -86,18 +86,20 @@ Table Time Constructors :widths: 10, 40, 80 :align: left - "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type." - ,, "``value`` is an integer or floating point value." - ,, "``relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``" - ,, "``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" - - "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type." - ,,"``year`` is an integer." - ,,"``month`` is an integer in the range 1 .. 12" - ,,"``day`` is an integer in the range 1 .. 31" - ,,"``hour`` is an integer in the range 0 .. 23" - ,,"``minute`` is an integer in the range 0 .. 59" - ,,"``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + "Reltime", "``cdtime.reltime(value, relunits)``", "Create a relative time type. + * ``value`` is an integer or floating point value. + * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]`` + * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. + * The default basetime is 1979-1-1, if no ``since`` clause is specified. + **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + + "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type. + * ``year`` is an integer. + * ``month`` is an integer in the range 1 .. 12 + * ``day`` is an integer in the range 1 .. 31 + * ``hour`` is an integer in the range 0 .. 23 + * ``minute`` is an integer in the range 0 .. 59 + * ``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" Relative Time @@ -146,19 +148,19 @@ Table Time Methods :widths: 20, 75, 80 :align: left - "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" - ,, "``calendar`` is the calendar type." - "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." - ,, "``t2`` is the time to compare." - ,, "``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" - ,, "``calendar`` is the calendar type. " - "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." - ,, "``calendar`` is the calendar type." + "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]`` + * ``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively. + * ``t2`` is the time to compare. + * ``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)] + * ``calendar`` is the calendar type. " + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time. + * ``calendar`` is the calendar type." "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 4f639f7f..9b2987cd 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -319,21 +319,21 @@ function: Table SCRIP Regridder Constructor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. csv-table:: :header: "Constructor", "Description" :widths: 80, 90 :align: left - "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object." - "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." - "", "``mapMethod`` is one of:" - "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." - "", "- ``'bilinear'``: bilinear interpolation" - "", "- ``'bicubic'``: bicubic interpolation" - "", "- ``'distwgt'``: distance-weighted interpolation." - "", "It is only necessary to specify the map method if it is not defined in the file." - "", "" - "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object. + * ``fileobj`` is a CDMS file object, as returned from ``cdms.open``. + * ``mapMethod`` is one of: + * ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved. + * ``'bilinear'``: bilinear interpolation + * ``'bicubic'``: bicubic interpolation + * ``'distwgt'``: distance-weighted interpolation. + * It is only necessary to specify the map method if it is not defined in the file. + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." Regridder Functions ^^^^^^^^^^^^^^^^^^^ @@ -407,17 +407,15 @@ Table CDMS Regridder Function :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." - , , "``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4." - , , - , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." - , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." - , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" - , , "- ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." - , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." - "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." - , , "``dataArray`` is the result data array." - , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). + * ``dataArray`` is the result data array. + * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." SCRIP Regridder Functions ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -469,11 +467,11 @@ Table SCRIP Regridder Functions :align: left "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable." - ,,"``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - ,,"``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``." - ,,"``gradientLon``: df/dj. Same shape as ``array``." - ,,"``gradientLatLon``: d(df)/(di)(dj). Same shape as array." + "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. + * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. + * ``gradientLon``: df/dj. Same shape as ``array``. + * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array." "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid." "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid." "CurveGrid or Generic-Grid", "``getInputGrid()``", "Return the input grid, or None if no input grid is associated with the regridder." diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index b53c45ea..0831ec8a 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -187,27 +187,29 @@ Table Plot Keywords "``comment1``", "string", "Comment plotted above ``file_comment``" "``comment2``", "string", "Comment plotted above ``comment1``" "``comment3``", "string", "Comment plotted above ``comment2``" - "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if ``xaxis`` is longitude, ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" + "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if + * ``xaxis`` is longitude, + * ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" "``file_comment``", "string", "Comment, defaults to ``variable.parent.comment``" "``grid``", "CDMS grid object", "Grid associated with the data. Defaults to ``variable.getGrid()``" "``hms``", "string", "Hour, minute, second" "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" "``name``", "string", "Variable name, defaults to ``variable.id``" - "``time``", "cdtime relative or absolute", "Time associated with the data." - ,,"Example:" - ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" + "``time``", "cdtime relative or absolute", "Time associated with the data. + **Example:** + ``cdtime.reltime(30.0, 'days since 1978-1-1').``" "``units``", "string", "Data units. Defaults to ``variable.units``" "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" - "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. + * ``xaxis`` defaults to ``grid.getAxis(0)`` + * ``yaxis`` defaults to ``grid.getAxis(1)``" "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." - "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" - "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions:" - ,,"- If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1" - ,,"- If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." - + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions: + * If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1 + * If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index ade53ebe..1c73923e 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -235,12 +235,12 @@ Table Axis Elements :widths: 18,1,1,1,80 "``associate``", "N", "N", "Y", "IDs of variables containing alternative sets of coordinates." - "``axis``", "N", "Y", "Y", "The spatial type of the axis:" - ,,,,"- 'T' - time" - ,,,,"- 'X' - longitude" - ,,,,"- 'Y' - latitude" - ,,,,"- 'Z' - vertical level" - ,,,,"- '-' - not spatiotemporal" + "``axis``", "N", "Y", "Y", "The spatial type of the axis: + * 'T' - time + * 'X' - longitude + * 'Y' - latitude + * 'Z' - vertical level + * '-' - not spatiotemporal" "``bounds``", "N", "Y", "Y", "ID of the boundary variable" "``calendar``", "N", "Y", "N", "See dataset.calendar" "``climatology``", "N", "Y", "N", "Range of dates to which climatological statistics apply." @@ -251,9 +251,9 @@ Table Axis Elements "``expand``", "N", "N", "Y", "Coordinates prior to contraction" "``formula_terms``", "N", "Y", "N", "Variables that correspond to the terms in a formula." "``id``", "Y", "N", "N", "Axis identifier. Also the name of the axis in the underlying file(s), if name_in_file is undefined." - "``isvar``", "N", "N", "N", "* 'true' | 'false'" - ,,,,"- 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s)." - ,,,,"- Default: 'true'" + "``isvar``", "N", "N", "N", "'true' | 'false' + * 'false' if the axis does not have coordinate values explicitly defined in the underlying file(s). + * Default: 'true'" "``leap_month``", "N", "Y", "N", "For a user-defined calendar, the month which is lengthened by a day in leap years." "``leap_year``", "N", "Y", "N", "An example of a leap year for a user-defined calendar. All years that differ from this year by a multiple of four are leap years." "``length``", "N", "N", "N", "Number of axis values, including values for which no data is defined. Cf. partition_length." @@ -265,8 +265,8 @@ Table Axis Elements "``partition_length``", "N", "N", "N", "Number of axis points for which data is actually defined. If data is missing for some values, this will be smaller than the length." "``positive``", "N", "Y", "Y", "Direction of positive for a vertical axis" "``standard_name``", "N", "Y", "N", "Reference to an entry in the standard name table." - "``topology``", "N", "N", "Y", "- Axis topology." - ,,,,"- 'circular' | 'linear'" + "``topology``", "N", "N", "Y", "Axis topology. + * 'circular' | 'linear'" "``units``", "Y", "Y", "Y", "Units of a physical quantity" "``weights``", "N", "N", "N", "Name of the weights array" From b4f662824b9004b834e872328ef6f5399fcaf8bd Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 11 Jun 2018 15:43:35 -0700 Subject: [PATCH 171/239] Changes made to Sections 2, 4, 7 and Appendix --- docs/source/manual/cdms_2.rst | 112 ++++++++++++++------------- docs/source/manual/cdms_4.rst | 4 +- docs/source/manual/cdms_7.rst | 67 +++++++++------- docs/source/manual/cdms_appendix.rst | 81 ++++++++++++------- 4 files changed, 153 insertions(+), 111 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index dd64eda2..449e02e4 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -143,77 +143,78 @@ Cdms Module Functions :align: left - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. + "``Variable``", "``asVariable(s)``: + Transform ``s`` into a transient variable. * ``s`` is a masked array, Numpy array, or Variable. * If ``s`` is already a transient variable, ``s`` is returned. * See also: ``isVariable``." - "``Axis``", "``createAxis(data, bounds=None)``:" - , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. + "``Axis``", "``createAxis(data, bounds=None)``: + Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. * ``data`` is a one-dimensional, monotonic Numpy array. * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. * If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" - "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + "``Axis``", "``createEqualAreaAxis(nlat)``: + Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." - "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. + "``Axis``", "``createGaussianAxis(nlat)``: + Create a Gaussian latitude axis. Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." - "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: + Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. * ``xorigin`` is the origin of the longitude axis. * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" - "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``: + Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." - "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + "``RectGrid``", "``createGlobalMeanGrid(grid)``: + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. * ``grid`` is a RectGrid." - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" - , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: + Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. * ``lon`` is a longitude axis, created by ``cdms.createAxis``. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" - , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: + Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``. * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" - , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: + Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." - "``RectGrid``","``createZonalGrid(grid)``:" - ,"Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + "``RectGrid``","``createZonalGrid(grid)``: + Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." - "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" - , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: + Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." - , " * See ``setAutoBounds``." - "``Integer``", "``isVariable(s)``: " - , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``:" - , "Open or create a ``Dataset`` or ``CdmsFile``. + "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. + * See ``setAutoBounds``." + "``Integer``", "``isVariable(s)``: + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + "``Dataset``", "``open(url,mode='r')``: + Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. @@ -222,30 +223,30 @@ Cdms Module Functions * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" - "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. + "``List``", "``order2index (axes, orderstring)``: + Find the index permutation of axes to match order. Return a list of indices. * ``axes`` is a list of axis objects. * ``orderstring`` is defined as in ``orderparse``." - "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: + "``List``", "``orderparse(orderstring)``: + Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of: * Letters t, x, y, z meaning time, longitude, latitude, level * Numbers 0-9 representing position in axes * Dash (-) meaning insert the next available axis here. * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" - "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: + "``None``", "``setAutoBounds(mode)``: + Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." - "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. + "``None``", "``setClassifyGrids(mode)``: + Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." - "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. + "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: + Write a grid to a SCRIP grid file. * ``path`` is a string, the path of the SCRIP file to be created. * ``grid`` is a CDMS grid object. It may be rectangular. * ``gridTitle`` is a string ID for the grid." @@ -305,10 +306,14 @@ Getting and Setting Attributes :header: "Type", "Definition" :widths: 20, 80 - "various", "``value = obj.attname``" - , "Get an internal or external attribute value. If the attribute is external, it is read from the database. If the attribute is not already in the database, it is created as an external attribute. Internal attributes cannot be created, only referenced." - "various", "``obj.attname = value``" - , "Set an internal or external attribute value. If the attribute is external, it is written to the database." + "various", "``value = obj.attname`` + Get an internal or external attribute value. + * If the attribute is external, it is read from the database. + * If the attribute is not already in the database, it is created as an external attribute. + * Internal attributes cannot be created, only referenced." + "various", "``obj.attname = value`` + St an internal or external attribute value. + * If the attribute is external, it is written to the database." @@ -540,8 +545,7 @@ CdmsFile Methods Object Name Transient Variable :align: left - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -966,7 +970,8 @@ ResultEntry Attributes :widths: 20, 30, 80 "String", "``name``", "The name of this entry in the database." - "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" + "Dictionary", "``attributes``", "The attributes returned from the search. + * ``attributes[key]`` is a list of all string values associated with the key" ResultEntry Methods @@ -976,8 +981,8 @@ ResultEntry Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry." - ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." + "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. + **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." Accessing data @@ -1375,8 +1380,8 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." - "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + "Tuple", "``getBounds()``", "Get the grid boundary arrays. + * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). @@ -1434,10 +1439,9 @@ RectGrid Methods, Additional to HorizontalGrid Methods * Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``. * from cdms import MV - * latwts, lonwts = gri d.getWeights() - * weights = MV.outerproduct(latwts, lonwts) + * ``latwts``, ``lonwts`` = ``grid.getWeights()`` + * weights = MV.outerproduct(``latwts``, ``lonwts``) * Also see the function ``area_weights`` in module ``pcmdi.weighting``." - ,," " "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. @@ -1534,7 +1538,7 @@ Variable Methods "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 9b2987cd..d089ca99 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -466,7 +466,9 @@ Table SCRIP Regridder Functions :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." + "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. + * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable. * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 0e311778..04a90c7c 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -67,40 +67,55 @@ Table CDScan Command Options :header: "Option:, "Description" :widths: 20, 80 - "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. ``variable_id`` is the ID of the variable in the file, and ``alias`` is the name that will be substituted for it in the output dataset. Only variables with entries in the ``alias_file`` are renamed." - "``-c calendar``", "Specify the dataset calendar attribute. One of:" - , "- gregorian (default)" - , "- julian" - , "- noleap" - , "- proleptic_gregorian" - , "- standard" - , "- 360_day" + "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. + * ``variable_id`` is the ID of the variable in the file, and + * ``alias`` is the name that will be substituted for it in the output dataset. + * Only variables with entries in the ``alias_file`` are renamed." + "``-c calendar``", "Specify the dataset calendar attribute. One of: + * gregorian (default) + * julian + * noleap + * proleptic_gregorian + * standard + * 360_day" "``-d dataset_id``", "String identifier of the dataset. Should not contain blanks or non-printing characters. Default: 'None'" - "``-e newattr``", "Add or modify attributes of a file, variable, or axis." - ,"- The form of ``newattr`` is either:" - ," - ``var.attr = value`` to modify a variable or attribute, or" - ," - ``.attr = value`` to modify a global (file) attribute. In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." + "``-e newattr``", "Add or modify attributes of a file, variable, or axis. The form of ``newattr`` is either: + * ``var.attr = value`` to modify a variable or attribute, or + * ``.attr = value`` to modify a global (file) attribute. + * In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. + * If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." "``--exclude var,var,...``", "Exclude specified variables. The argument is a comma-separated list of variables containing no blanks. Also see ``--include``." "``-f file_list``", "File containing a list of absolute data file names, one per line." "``-h``", "Print a help message." - "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. ``time_delta`` is a float or integer. For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." + "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. + * ``time_delta`` is a float or integer. + * For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." "``--include var,var,...``", "Only include specified variables in the output. The argument is a comma-separated list of variables containing no blanks. Also see ``--exclude``." - "``-j``", "Scan time as a vector dimension. Time values are listed individually." - ,"- **Note:** Turns off the -i option." - "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." + "``-j``", "Scan time as a vector dimension. Time values are listed individually. + **Note:** Turns off the -i option." + "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. + * ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." "``-m levelid``", "Name of the vertical level dimension. The default is the vertical dimension as determined by CDMS. See Note 3." - "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. ``cdimport -h`` describes template strings." + "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. + * ``cdimport -h`` describes template strings." "``-q``", "Quiet mode." - "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." - "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. Each line consists of two blank-separated fields: ``directory suffix``. Each file path is compared to the directories in the suffix file. If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. If more than one such directory is found, the first directory found is used. If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." + "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where + * ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." + "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. + * ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. + * Each line consists of two blank-separated fields: ``directory suffix``. + * Each file path is compared to the directories in the suffix file. + * If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. + * If more than one such directory is found, the first directory found is used. + * If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." "``-t timeid``", "ID of the partitioned time dimension. The default is the name of the time dimension as determined by CDMS. See Note 1." - "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list:" - , "- zero is the initial time point, a floating-point value." - , "- delta is the time delta, floating-point." - , "- units are time units as specified in the [-r] option." - , "- calendar is optional, and is specified as in the [-c] option." - , "If omitted, it defaults to the value specified by [-c], otherwise as specified in the file." - , "**Example:** ``--time-linear '0,1,months since 1980,noleap'``" + "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list: + * zero is the initial time point, a floating-point value. + * delta is the time delta, floating-point. + * units are time units as specified in the [-r] option. + * calendar is optional, and is specified as in the [-c] option. + * If omitted, it defaults to the value specified by [-c], otherwise as specified in the file. + **Example:** ``--time-linear '0,1,months since 1980,noleap'``" "``-x xmlfile``", "Output file name. By default, output is written to standard output." **Notes:** diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 13bba1f8..6605166e 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -219,12 +219,23 @@ Table Slab Methods :widths: 20,50,80 :align: left - "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." - "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." - "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." - "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." + "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. + * ``dim`` is the dimension number, an integer in the range 0..rank- 1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getattribute(name)``", "Get the value of an attribute. + * ``name`` is the string name of the attribute. + The following special names can always be used: + ``filename``, ``comments``, ``grid_name``, ``grid_type``. ``time_statistic``, ``long_name``, ``units``." + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. + * If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." + "List", "``listall(all=None)``", "Print slab information. + * If ``all`` is nonzero, dimension values, weights, and bounds are also printed." + "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. + * ``dim`` is the dimension number, an integer in the range 0..rank-1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "None", "``setattribute(name, value)``", "Set an attribute. + * ``name`` is the string name of the attribute. + * ``value`` is the value of the attribute." @@ -241,34 +252,44 @@ Table cuDataset Methods :align: left "None", "``cleardefault()``", "Clear the default variable name." - "None", "``default_variable(vname``)", "Set the default variable name." - ,,"vname is the string variable name." - "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname." - ,,"dname is the string axis name." - ,,"vname is the string variable name. The default is the variable name set by default_variable." - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." + "None", "``default_variable(vname``)", "Set the default variable name. + * ``vname`` is the string variable name." + "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname. + * ``dname`` is the string axis name. + * ``vname`` is the string variable name. + * The default is the variable name set by ``default_variable.``" + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by ``default_variable.``" "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." - "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension." - ,,"dname is the string name of an axis." - ,,"vname is a string variable name. The default is the variable name set by default_variable." + "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. + * ``dname`` is the string name of an axis. + * ``vname`` is a string variable name. + * The default is the variable name set by ``default_variable``." "Various", "``getglobal (attribute)``", "Get the value of the global attribute. attribute is the string attribute name." - "Variable", "``getslab (vname, \*args)``", "Read data for a variable." - ,, "vname is the string name of the variable." - ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" - ,, "- ':' or None -- select the entire dimension" - ,, "- Ellipsis -- select entire dimensions between the ones given." - ,, "- a pair of successive arguments giving an interval in world coordinates." - ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" - "List", "``listall (vname=None, all=None)``", "Get info about data from the file." - ,, "vname is the string name of the variable." - ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" - "List", "``listattribute (vname=None )``", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." - "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "Variable", "``getslab (vname, \*args)``", "Read data for a variable. + * ``vname`` is the string name of the variable. + * ``args`` is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be: + * ':' or None -- select the entire dimension + * Ellipsis -- select entire dimensions between the ones given. + * a pair of successive arguments giving an interval in world coordinates. + * a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" + "List", "``listall (vname=None, all=None)``", "Get info about data from the file. + * ``vname`` is the string name of the variable. + * If all is non-zero, dimension values, weights, and bounds are returned as well" + "List", "``listattribute (vname=None )``", "Return a list of attribute names. + * ``vname`` is the name of the variable. + * The default is the variable name set by ``default_variable.``" + "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. + * ``vname`` is the name of the variable. + * The default is the variable name set by ``default_variable.``" "List", "``listglobal ()``", "Return a list of the global attribute names." "List", "``listvariable ()``", "Return a list of the variables in the file." - "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." - "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." - "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. + * ``vname`` is the string name of the variable. + * If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. + * ``vname`` is the string name of the variable. Output is sent to device." + "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. + * ``vname`` is the string name of the variable. Output is sent to device." "None", "``showglobal (device=sys.stdout)``", "Print the global file attributes. Output is sent to device." "None", "``showvariable (device=sys.stdout)``", "Print the list of variables in the file." From a294133c2edb7592562f9b43cf7f0c0221d20817 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 12 Jun 2018 15:46:39 -0700 Subject: [PATCH 172/239] Changes made to Chapter 6 and Appendix --- docs/source/manual/cdms_6.rst | 6 +++--- docs/source/manual/cdms_appendix.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 1c73923e..5d9e6b5e 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -162,9 +162,9 @@ Dataset Attributes :widths: 10,5,5,5,80 "appendices", "N", "N", "Y", "Version number" - "calendar", "N", "N", "Y", "Calendar used for encoding time axes." - ,,,,"``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard``" - ,,,,"Note: for the CF convention, the calendar attribute is placed on the time axis." + "calendar", "N", "N", "Y", "Calendar used for encoding time axes. + * ``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard`` + * Note: for the CF convention, the calendar attribute is placed on the time axis." "comment", "N", "Y", "Y", "Additional dataset information" "conventions", "Y", "Y", "Y", "The netCDF metadata standard. Example: 'CF-1.0'" "cdms_filemap", "Y", "N", "N", "Map of partitioned axes to files. See note below." diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 6605166e..0f3ceb76 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -258,8 +258,8 @@ Table cuDataset Methods * ``dname`` is the string axis name. * ``vname`` is the string variable name. * The default is the variable name set by ``default_variable.``" - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by ``default_variable.``" - "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. ``dname`` is the string name of an axis. ``vname`` is a string variable name. The default is the variable name set by ``default_variable.``" + "Various", "``getattribute (vname, attribute``)", "Get an attribute value. ``vname`` is a string variable name. attribute is the string attribute name." "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. * ``dname`` is the string name of an axis. * ``vname`` is a string variable name. From 08f62a5a3bf3fbcf33f453589cd679a609dbe745 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 13 Jun 2018 15:41:46 -0700 Subject: [PATCH 173/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 278 +++++++++++++++++++--------------- 1 file changed, 157 insertions(+), 121 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 449e02e4..c667c97f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -178,7 +178,7 @@ Cdms Module Functions * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``: - Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of the input grid. * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. @@ -202,22 +202,24 @@ Cdms Module Functions * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. - * ``grid`` is a RectGrid." + * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. - * See ``setAutoBounds``." + "``Integer``", "``getAutoBounds()``: + Get the current autobounds mode. Returns 0, 1, or 2. + * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: - * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. - * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. + * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. + * If the protocol is 'file' or is omitted, a local file or dataset is opened. * ``mode`` is the open mode. See `Open Modes <#id3>`__ * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` @@ -246,10 +248,10 @@ Cdms Module Functions * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: - Write a grid to a SCRIP grid file. - * ``path`` is a string, the path of the SCRIP file to be created. - * ``grid`` is a CDMS grid object. It may be rectangular. - * ``gridTitle`` is a string ID for the grid." + Write a grid to a SCRIP grid file. + * ``path`` is a string, the path of the SCRIP file to be created. + * ``grid`` is a CDMS grid object. It may be rectangular. + * ``gridTitle`` is a string ID for the grid." : @@ -374,10 +376,10 @@ CoordinateAxis Constructors * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` - * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. - * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. - * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. - * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." + * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_. + * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_. + * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_. + * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ ." CoordinateAxis Methods @@ -389,30 +391,42 @@ CoordinateAxis Methods :align: left - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#id15>`_ for a description of slice operators." - "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." - "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." - "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." - "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. + * Data is returned in the physical ordering defined in the dataset. + * See `Variable Slice Operators <#id15>`_ for a description of slice operators." + "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. + * Dataset axes are read-only." + "``None``", "``assignValue(array)``", "Set the entire value of the axis. + * ``array`` is a Numpy array, of the same dimensionality as the axis." + "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. + * If copyData is 1 (the default) the data itself is copied." + "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. + * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. + * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. + * ``modulo`` is the modulus value. Any given axis value + * ``x`` is treated as equivalent to ``x + modulus``. + *If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. + * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. + * ``calendar`` is defined as in ``getCalendar()``." "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: - * ``Axis``: ``(n,2)`` * ``Axis2D``: ``(i,j,4)`` * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. - * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. + * See ``setAutoBounds``." "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: - * ``cdtime.GregorianCalendar``: the standard Gregorian calendar - * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar - * ``cdtime.JulianCalendar``: years divisible by 4 are leap years - * ``cdtime.NoLeapCalendar``: a year is 365 days - * ``cdtime.Calendar360``: a year is 360 days - * ``None``: no calendar can be identified + * ``cdtime.GregorianCalendar``: the standard Gregorian calendar + * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar + * ``cdtime.JulianCalendar``: years divisible by 4 are leap years + * ``cdtime.NoLeapCalendar``: a year is 365 days + * ``cdtime.Calendar360``: a year is 360 days + * ``None``: no calendar can be identified + **Note** If the axis is not a time axis, the global, file-related calendar is returned." - * **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." @@ -435,7 +449,7 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. - **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: * ``axis.topology == 'circular'``, or @@ -444,24 +458,24 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: - * ``(x,y)`` - * ``(x,y,indicator)`` - * ``(x,y,indicator,cycle)`` - * ``None or ':'`` - * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: - * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi - * ``'n'`` - select node values which are contained in the interva - * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval - * ``'e'`` - same as n, but include an extra node on either sid - * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval - * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. - * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. - * An interval of ``None`` or ``':'`` returns the full index interval of the axis. - * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. - * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` - * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. - * otherwise the interval wraps around the axis endpoint. - * see also: ``mapinterval``, ``variable.subregion()``" + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None or ':'`` + * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: + * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi + * ``'n'`` - select node values which are contained in the interva + * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval + * ``'e'`` - same as n, but include an extra node on either sid + * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval + * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * An interval of ``None`` or ``':'`` returns the full index interval of the axis. + * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. + * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` + * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. + * otherwise the interval wraps around the axis endpoint. + * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." CoordinateAxis Slice Operators @@ -549,8 +563,8 @@ CdmsFile Methods Object Name Transient Variable **Example:** The following reads data for variable 'prc', year 1980: - * >>> f = cdms.open('test.nc') - * >>> x = f('prc', time=('1980-1','1981-1'))" + * >>> f = cdms.open('test.nc') + * >>> x = f('prc', time=('1980-1','1981-1'))" CdmsFile Methods Object Identifier Variable, Axis or Grid --------------------------------------------------------- @@ -564,15 +578,15 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid **Example:** The following gets the persistent variable - * ``v``, equivalent to - * ``v = f.variables['prc']``. - * f = cdms.open('sample.nc') - * v = f['prc'] + * ``v``, equivalent to + * ``v = f.variables['prc']``. + * f = cdms.open('sample.nc') + * v = f['prc'] **Example:** The following gets the axis named time, equivalent to - * ``t = f.axes['time']``. - * ``t = f['time']``" + * ``t = f.axes['time']``. + * ``t = f['time']``" "``None``", "``close()``", "Close the file." CdmsFile Methods Copy Axis, Grid @@ -584,13 +598,13 @@ CdmsFile Methods Copy Axis, Grid :align: left "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. - * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. - * ``axis`` is the axis object to be copied. - * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." + * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. + * ``axis`` is the axis object to be copied. + * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. - * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. - * ``grid`` is the grid object to be copied. - * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." + * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. + * ``grid`` is the grid object to be copied. + * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." CdmsFile Methods Create Axis, RectGrid and Variable ---------------------------------------------------- @@ -605,19 +619,19 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``ar`` is the one-dimensional axis array. * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. - * ``lat`` is a latitude axis in the file. - * ``lon`` is a longitude axis in the file. - * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). - * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. - * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + * ``lat`` is a latitude axis in the file. + * ``lon`` is a longitude axis in the file. + * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). + * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. * ``id`` is a String name which is unique with respect to all other objects in the file. * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. * ``axes`` is a list of Axis and/or Grid objects. * ``fill_value`` is the missing value (optional)." "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. - * ``var`` is the ``Variable`` to be copied. - * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." @@ -633,7 +647,7 @@ CdmsFile Methods Read CurveGrid, Generic-Grid "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. - * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." @@ -794,13 +808,13 @@ Database Methods "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." "Dataset", "``open(dsetid, mode='r')``", "Open a dataset. - * ``dsetid``, is the string dataset identifier + * ``dsetid``, is the string dataset identifier - * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. - * ``openDataset``, is a synonym for ``open``." + * ``openDataset``, is a synonym for ``open``." "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database. - * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. **Example:** * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. @@ -949,9 +963,9 @@ SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. - * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. - * ``tag`` restricts the search to objects of the class denoted by the tag. - **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. + * ``tag`` restricts the search to objects of the class denoted by the tag. + **Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -982,7 +996,7 @@ ResultEntry Methods :widths: 20, 30, 80 "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. - **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." + **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." Accessing data @@ -1142,26 +1156,25 @@ Dataset Methods "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. - **Example:** The following reads data for variable 'prc', year 1980: - - * f = cdms.open('test. xml') + **Example:** The following reads data for variable 'prc', year 1980: - * x = f('prc', time=('1980-1','1981-1'))" + * f = cdms.open('test. xml') + * x = f('prc', time=('1980-1','1981-1'))" "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. - **Example:** + **Example:** - * f = cdms.open('sampl e.xml') - * v = f['prc'] + * f = cdms.open('sampl e.xml') + * v = f['prc'] - * gets the persistent variable v equivalent to ``v=f.variables['prc']``. + * gets the persistent variable v equivalent to ``v=f.variables['prc']``. - **Example:** + **Example:** - * t = f['time'] + * t = f['time'] - * gets the axis named time, equivalent to ``t=f.axes['time']``" + * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. * ``lat`` is a latitude axis in the dataset. @@ -1381,22 +1394,24 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." "Tuple", "``getBounds()``", "Get the grid boundary arrays. - * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: - * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). - * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). - * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. - * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. - * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. - * ``lonBounds`` is defined similarly for the longitude array. - **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." - "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." + * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. + * ``lonBounds`` is defined similarly for the longitude array. + **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setMask(mask, persistent=0)``", "Set the grid mask. + * If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. + * ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` * ``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively. @@ -1409,13 +1424,18 @@ HorizontalGrid Methods * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: * ``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co'). - * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. - * An interval of ``None`` returns the full index interval of the axis. - * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. + * An interval of ``None`` returns the full index interval of the axis. + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. - * If the grid is already curvilinear, a copy of the grid object is returned. - * ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied. - **Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + * If the grid is already curvilinear, a copy of the grid object is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied. + **Note:** This method does not apply to generic grids. + * Transient-GenericGrid, ``toGenericGrid(gridid=None)`` Convert to a generic grid. + * If the grid is already generic, a copy of the grid is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied." RectGrid Methods, Additional to HorizontalGrid Methods @@ -1425,7 +1445,11 @@ RectGrid Methods, Additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees. + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. + * String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. + + * (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. + **Note** It is assumed that the latitude and longitude axes are defined in degrees. * The latitude weights are defined as: * ``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`` @@ -1442,18 +1466,19 @@ RectGrid Methods, Additional to HorizontalGrid Methods * ``latwts``, ``lonwts`` = ``grid.getWeights()`` * weights = MV.outerproduct(``latwts``, ``lonwts``) * Also see the function ``area_weights`` in module ``pcmdi.weighting``." - "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." + "None", "``setType(gridtype)``", "Set the grid type. + * ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. **Example:** - * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. - * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` - * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. + * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. **Note:** The result grid is not associated with any file or dataset." "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. - **Note:** The result grid is not associated with any file or dataset." + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1566,8 +1591,12 @@ Variable Methods * an axis object; will match if it is the same object as axis. * ``order`` can be a string containing the characters t,x,y,z, or * . * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." - "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." - "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." + "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for ``getAxisList``." + "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, + * ``start`` is the start index of the domain relative to the axis object, + * ``length`` is the length of the axis, and + * ``true\_length`` is the actual number of (defined) points in the domain. + * *See also:* ``getAxisList``." "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." @@ -1583,9 +1612,10 @@ Variable Methods A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude). **Note:** The order string is of the form required for the order argument of a regridder function. - * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned. + * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. + * If no ``argument(s)`` are present, all file paths associated with the variable are returned. - * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. + * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." @@ -1600,14 +1630,20 @@ Variable Methods "Integer", "``rank()``", "The number of dimensions of the variable." "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. - * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. - * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any. - * See also: ``crossSectionRegrid``, ``pressureRegrid``." + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. + * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. + * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. - * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. + * If trailing dimensions are omitted, all values of those dimensions are retrieved. + * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." From 51583732906af20f30da593fea2f7120d0f6e0df Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 14 Jun 2018 15:12:29 -0700 Subject: [PATCH 174/239] Changes made to al sections --- docs/source/manual/cdms_2.rst | 31 ++++++++++++++-------------- docs/source/manual/cdms_3.rst | 6 ++++-- docs/source/manual/cdms_4.rst | 4 ++-- docs/source/manual/cdms_7.rst | 6 +++--- docs/source/manual/cdms_appendix.rst | 4 +++- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index c667c97f..da9b71ff 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -213,7 +213,8 @@ Cdms Module Functions Get the current autobounds mode. Returns 0, 1, or 2. * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: - * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. + * See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``. * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. @@ -399,7 +400,7 @@ CoordinateAxis Methods "``None``", "``assignValue(array)``", "Set the entire value of the axis. * ``array`` is a Numpy array, of the same dimensionality as the axis." "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. - * If copyData is 1 (the default) the data itself is copied." + * If ``copyData`` is 1 (the default) the data itself is copied." "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. @@ -428,10 +429,10 @@ CoordinateAxis Methods **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." - "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." - "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." - "``Integer``", "``isLongitude()``", "Returns true iff the axis is a longitude axis." - "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." + "``Integer``", "``isLatitude()``", "Returns true if the axis is a latitude axis." + "``Integer``", "``isLevel()``", "Returns true if the axis is a level axis." + "``Integer``", "``isLongitude()``", "Returns true if the axis is a longitude axis." + "``Integer``", "``isTime()``", "Returns true if the axis is a time axis." "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." @@ -580,8 +581,8 @@ CdmsFile Methods Object Identifier Variable, Axis or Grid * ``v``, equivalent to * ``v = f.variables['prc']``. - * f = cdms.open('sample.nc') - * v = f['prc'] + * ``f = cdms.open('sample.nc')`` + * ``v = f['prc']`` **Example:** The following gets the axis named time, equivalent to @@ -644,7 +645,7 @@ CdmsFile Methods Read CurveGrid, Generic-Grid :widths: 10, 30, 80 :align: left - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid (self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." @@ -1400,7 +1401,7 @@ HorizontalGrid Methods * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." @@ -1631,12 +1632,12 @@ Variable Methods "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. - * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. + * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid. * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. - * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. - * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. - **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. - * See also: ``crossSectionRegrid``, ``pressureRegrid``." + * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + * See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 784451b4..437cb786 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -91,7 +91,7 @@ Table Time Constructors * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]`` * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. * The default basetime is 1979-1-1, if no ``since`` clause is specified. - **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" + **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type. * ``year`` is an integer. @@ -99,7 +99,9 @@ Table Time Constructors * ``day`` is an integer in the range 1 .. 31 * ``hour`` is an integer in the range 0 .. 23 * ``minute`` is an integer in the range 0 .. 59 - * ``second`` is a floating point number in the range 0.0 ,, 60.0. **Example:** ``c = cdtime.comptime(1996, 2, 28)``" + * ``second`` is a floating point number in the range 0.0 ,, 60.0. + + **Example:** ``c = cdtime.comptime(1996, 2, 28)``" Relative Time diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index d089ca99..9e2448bc 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -308,7 +308,7 @@ Table CDMS Regridder Constructor :widths: 50, 90 :align: left - "``regridFunction = Regridder(inputGrid, outputGrid)``", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "``regridFunction = Regridder(inputGrid, outputGrid)``", "Create a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ Table CDMS Regridder Function * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. - * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). * ``dataArray`` is the result data array. * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 04a90c7c..cf5968a7 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -120,12 +120,12 @@ Table CDScan Command Options **Notes:** -- Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. +#. Files can be in netCDF, GrADS/GRIB, HDF, or DRS format, and can be listed in any order. Most commonly, the files are the result of a single experiment, and the 'partitioned' dimension is time. The time dimension of a variable is the coordinate variable having a name that starts with 'time' or having an attribute axis='T'. If this is not the case, specify the time dimension with the -t option. The time dimension should be in the form supported by cdtime. If this is not the case (or to override them) use the -r option. -- By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. +#. By default, the time values are listed explicitly in the output XML. This can cause a problem if the time dimension is very long, say for 6-hourly data. To handle this the form cdscan -i delta may be used. This generates a compact time representation of the form . An exception is raised if the time dimension for a given file is not linear. -- Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. +#. Another form of the command is cdscan -l lev1,lev2,..,levn . This asserts that the dataset is partitioned in both time and vertical level dimensions. The level dimension of a variable is the dimension having a name that starts with "lev", or having an attribute "axis=Z". If this is not the case, set the level name with the -m option. - Adding or modifying attributes with the -e option: - time.units = "days since 1979-1-1" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 0f3ceb76..e5fef367 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -258,7 +258,9 @@ Table cuDataset Methods * ``dname`` is the string axis name. * ``vname`` is the string variable name. * The default is the variable name set by ``default_variable.``" - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. ``dname`` is the string name of an axis. ``vname`` is a string variable name. The default is the variable name set by ``default_variable.``" + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. + * ``dname`` is the string name of an axis. ``vname`` is a string variable name. + * The default is the variable name set by ``default_variable.``" "Various", "``getattribute (vname, attribute``)", "Get an attribute value. ``vname`` is a string variable name. attribute is the string attribute name." "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. * ``dname`` is the string name of an axis. From 46e564f62bb520268064960fee7783299d8397ce Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 15 Jun 2018 11:25:21 -0700 Subject: [PATCH 175/239] Changes made to Section 2 and API --- Lib/avariable.py | 16 ++++++++++------ docs/source/manual/cdms_2.rst | 34 +++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index ccd2c92d..58009ef5 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -514,7 +514,10 @@ def getAxisIds(self): Returns ------- - array list of axis ids""" + + array list of axis ids + + """ return [x[0].id for x in self.getDomain()] @@ -1691,12 +1694,13 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. -Parameters ----------- - ar - is a masked array, scalar, or numpy.ma.masked. + Parameters + ---------- - _: None + ar + is a masked array, scalar, or numpy.ma.masked. + + _: None """ diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index da9b71ff..01509022 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -494,15 +494,16 @@ CoordinateAxis Slice Operators "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element. - * **Example:** a longitude axis has value - * ``[0.0, 2.0, ..., 358.0]`` - * of length ``180`` - * map the coordinate interval: - * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval - * ``-2 <= n < 3`` wraps around, since - * ``-2 < 0``, and has a stride of ``1`` - * this is equivalent to the two contiguous index intervals - * ``2 <= n < 0`` and ``0 <= n < 3``" + **Example:** a longitude axis has value + + * ``[0.0, 2.0, ..., 358.0]`` + * of length ``180`` + * map the coordinate interval: + * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval + * ``-2 <= n < 3`` wraps around, since + * ``-2 < 0``, and has a stride of ``1`` + * this is equivalent to the two contiguous index intervals + * ``2 <= n < 0`` and ``0 <= n < 3``" Example 1 ''''''''''' @@ -1401,7 +1402,9 @@ HorizontalGrid Methods * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). * For generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. * For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). - * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + * By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None). + * For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. + * By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." @@ -1714,15 +1717,16 @@ Index and Coordinate Intervals :header: "Interval Definition", "Example Interval Definition", "Example" :widths: 30, 80, 80 - "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0``" - ,,"``cdtime.reltime(48,'hour s since 1980-1')``" - ,,"``'1980-1-3'``" + "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0`` + ``cdtime.reltime(48,'hour s since 1980-1')`` + + ``'1980-1-3'``" "``(x,y)``", "indices i such that x ≤ axis[i] ≤ y", "``(-180,180)``" "``(x,y,'co')``", "``x ≤ axis[i] < y``. The third item is defined as in mapInterval.", "``(-90,90,'cc')``" "``(x,y,'co',cycle)``", "``x ≤ axis[i]< y``, with wraparound", "``( 180, 180, 'co', 360.0)``" "","**Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true.", - "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)``" - ,,"``slice(,,-1)`` reverses the direction of the axis." + "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)`` + ``slice(,,-1)`` reverses the direction of the axis." "``':'``", "all axis values of one dimension", "``Ellipsis``", "all values of all intermediate axes", From 134054c584342c7e91e8a9b62869dee2c98ecc46 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 18 Jun 2018 15:58:01 -0700 Subject: [PATCH 176/239] Changes made to 2 and API --- Lib/forecast.py | 35 ++++++++++++++++++----------------- docs/source/manual/cdms_2.rst | 29 +++++++++++++++-------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Lib/forecast.py b/Lib/forecast.py index 91ca48da..05b076bd 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -75,27 +75,28 @@ def comptime(t): class forecast(): """represents a forecast starting at a single time - Parameters - ---------- + Parameters + ---------- - tau0time - is the first time of the forecast, i.e. the time at which tau=0. - dataset_list - is used to get the forecast file from the forecast time. - - Example - ------- + tau0time + is the first time of the forecast, i.e. the time at which tau=0. - Each list item should look like this example: - [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] - Normally dataset_list = fm[i][1] where fm is the output of - cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. + dataset_list + is used to get the forecast file from the forecast time. + + Example + ------- + + Each list item should look like this example: + [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] + Normally dataset_list = fm[i][1] where fm is the output of + cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. - Note - ---- + Note + ---- - N.B. This is like a CdmsFile. Creating a forecast means opening a file, - so later on you should call forecast.close() to close it. + N.B. This is like a CdmsFile. Creating a forecast means opening a file, + so later on you should call forecast.close() to close it. """ def __init__(self, tau0time, dataset_list, path="."): diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 01509022..466f1f36 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -408,7 +408,7 @@ CoordinateAxis Methods "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. * ``modulo`` is the modulus value. Any given axis value * ``x`` is treated as equivalent to ``x + modulus``. - *If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. * ``calendar`` is defined as in ``getCalendar()``." @@ -561,7 +561,7 @@ CdmsFile Methods Object Name Transient Variable :align: left - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_ . + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id14>`_ . **Example:** The following reads data for variable 'prc', year 1980: @@ -1156,7 +1156,7 @@ Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id12>`_. + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id14>`_. **Example:** The following reads data for variable 'prc', year 1980: @@ -1565,13 +1565,14 @@ Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id11>`_ " + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id12>`_ " "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. - * If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." + * If copyData is 1 (the default) the variable data is copied as well. + * If copyData is 0, the result transient variable shares the original transient variables data array." "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time. * ``newLevel`` is an axis of the result pressure levels. * ``newLatitude`` is an axis of the result latitudes. @@ -1647,7 +1648,7 @@ Variable Methods "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. * If trailing dimensions are omitted, all values of those dimensions are retrieved. - * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id11>`_ . Also see ``axis.mapIntervalExt``. + * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#id13>`_ . Also see ``axis.mapIntervalExt``. * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument. * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." @@ -1789,7 +1790,7 @@ selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index -ranges as defined in See `Index and Coordinate Intervals <#id11>`_. +ranges as defined in See `Index and Coordinate Intervals <#id13>`_. The following keywords are available: Another form of selector components is the positional form, where the component order corresponds @@ -1803,16 +1804,16 @@ Selector Keywords :header: "Keyword", "Description", "Value" :widths: 30, 80, 80 - "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id11>`_ + "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#id13>`_ "``grid``", "Regrid the result to the grid.", " Grid object" - "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id11>`_ - "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id11>`_ - "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id11>`_ + "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#id13>`_ + "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#id13>`_ + "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#id13>`_ "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" - "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); = 1: return a masked array." + "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", " 0: return a transient variable (default); = 1: return a masked array." "``required``", "Require that the axis IDs be present.", " List of axis identifiers." "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." - "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id11>`_ + "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#id13>`_ Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For @@ -1826,7 +1827,7 @@ example: reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the -form(s) listed in `Index and Coordinate Intervals <#id11>`_ are treated as positional. Such +form(s) listed in `Index and Coordinate Intervals <#id13>`_ are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section. From a473fe30e5f9124416dc1d1182906cac9b2a4421 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 19 Jun 2018 15:55:42 -0700 Subject: [PATCH 177/239] Made changes to sections 1 and 2 --- docs/source/manual/cdms_1.rst | 2 +- docs/source/manual/cdms_2.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 386fbb76..ac6f4f86 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -301,7 +301,7 @@ with a corresponding mask value of one are set to the value of the variables ``missing_value`` attribute. The data and ``missing_value`` attribute are then written to the file. -Masking is covered in `Section 2.9 `__. See also the +Masking is covered in `Section 2.9 `__. See also the documentation of the Python Numpy and MA modules, on which ``cdms.MV`` is based, at diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 466f1f36..221c4261 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -223,9 +223,9 @@ Cdms Module Functions * If the protocol is 'file' or is omitted, a local file or dataset is opened. * ``mode`` is the open mode. See `Open Modes <#id3>`__ - * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')`` - * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``: Find the index permutation of axes to match order. Return a list of indices. * ``axes`` is a list of axis objects. @@ -624,7 +624,7 @@ CdmsFile Methods Create Axis, RectGrid and Variable * ``lat`` is a latitude axis in the file. * ``lon`` is a longitude axis in the file. * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). - * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * ``type`` is one of ``'gaussian'``,\ ``'uniform'``,\ ``'equalarea'`` , or ``'generic'``. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. * ``id`` is a String name which is unique with respect to all other objects in the file. From c2d8bd375d8a10cf0d9a1c01063b616717286d92 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 6 Mar 2018 21:48:40 -0800 Subject: [PATCH 178/239] Issue#231 (#232) * fix #225 passing transiant variable as axis * Fix macOSX * fix ESMF and NPY_STRING * fix data._mask comparison for numpy 1.14 --- Lib/axis.py | 12 ++++++------ tests/test_EsmfMask.py | 9 +-------- tests/test_cdms_info.py | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index b2c71df1..15a706cb 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -1932,13 +1932,8 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data[:] else: self._data_ = numpy.array(data[:]) - elif isinstance(data, numpy.ndarray): - if copy == 0: - self._data_ = data - else: - self._data_ = numpy.array(data) elif isinstance(data, numpy.ma.MaskedArray): - if numpy.ma.getmask(data) is not numpy.ma.nomask: + if numpy.ma.getmask(data).any() is numpy.bool_(True): raise CDMSError( 'Cannot construct an axis with a missing value.') data = data.data @@ -1946,6 +1941,11 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data else: self._data_ = numpy.array(data) + elif isinstance(data, numpy.ndarray): + if copy == 0: + self._data_ = data + else: + self._data_ = numpy.array(data) elif data is None: self._data_ = None else: diff --git a/tests/test_EsmfMask.py b/tests/test_EsmfMask.py index 60da15ac..e401b6cb 100644 --- a/tests/test_EsmfMask.py +++ b/tests/test_EsmfMask.py @@ -1,6 +1,5 @@ import unittest import cdms2 -import vcs import ESMF import cdat_info import os @@ -61,16 +60,10 @@ def testMask2(self): data2 = cdms2.MV2.masked_where(cdms2.MV2.less(sft,50.),data) tGrid = cdms2.createUniformGrid(-88.875, 72, 2.5, 0, 144, 2.5) - x=vcs.init() + for mthd in ["conservative", "linear"]: print("USING REGRID METHOD:",mthd) data3 = data2.regrid(tGrid, regridTool="esmf", regridMethod=mthd, mask=data2.mask) - print("pltting") - x.plot(data3) - print("pnging") - x.png("masked_{}".format(mthd)) - print("clearing") - x.clear() diff --git a/tests/test_cdms_info.py b/tests/test_cdms_info.py index 5a618097..82a96b27 100644 --- a/tests/test_cdms_info.py +++ b/tests/test_cdms_info.py @@ -8,7 +8,7 @@ def testInfo(self): f = cdms2.open(os.path.join(cdat_info.get_sampledata_path(),"clt.nc")) s=f("clt") s.info() - def tstAxis(self): + def testAxis(self): axis = cdms2.createAxis(cdms2.createVariable([10.], id='height', missing=1e20)) print(axis) From 44add33d154fc087c9df5d09648cf9e0640fbdf8 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 1 May 2018 09:49:51 -0700 Subject: [PATCH 179/239] Fix python3 slice issue(setitem) and flake8 (#243) --- Src/Cdunifmodule.c | 8 +++++++- regrid2/Lib/esmf.py | 2 +- regrid2/Lib/mvESMFRegrid.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index 3911836e..486d8db2 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -3090,7 +3090,9 @@ static int PyCdunifVariableObject_ass_subscript(PyCdunifVariableObject *self, if (PySlice_Check(index)) { Py_ssize_t slicelen; int length; - if( self->dimensions[0] == self->file->recdim ){ + length = INT_MAX; + if( self->dimids[0]== self->file->recdim && + self->dimensions[0] == 0){ length = INT_MAX; } else { length = self->dimensions[0]; @@ -3098,6 +3100,10 @@ static int PyCdunifVariableObject_ass_subscript(PyCdunifVariableObject *self, PySlice_GetIndicesEx((PySliceObject *) index, length, &indices->start, &indices->stop, &indices->stride, &slicelen); + + if(indices->stop == indices->start){ + indices->stop = indices->start + indices->stride; + } return PyCdunifVariable_WriteArray(self, indices, value); } if (PyTuple_Check(index)) { diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 02eb38b7..39b8044f 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -836,7 +836,7 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): # default is keep the masked values intact zeroregion = ESMF.Region.SELECT if self.regridMethod == CONSERVE: - zeroregion = None # will initalize to zero + zeroregion = None # will initalize to zero self.regridHandle( srcfield=srcField.field, diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 8fe7f0b4..908034e2 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -368,7 +368,7 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): zero_region = ESMF.Region.SELECT if 'zero_region' in args.keys(): - zero_region=args.get('zero_region') + zero_region = args.get('zero_region') self.srcFld.field.data[:] = srcData.T self.dstFld.field.data[:] = dstData.T From 405fe2445348e8310dc3b0cbecb33fc0158884b8 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 1 May 2018 19:09:37 -0700 Subject: [PATCH 180/239] fix python 3 aggregation issue and flake8 (#244) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 --- Src/Cdunifmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index 486d8db2..903793d0 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -536,7 +536,9 @@ static int cdopen(const char* controlpath, int ncmode, CuFileType *filetype) { /* Take care for mode flag */ if ((cdms_classic == 0) || (cdms_shuffle != 0) || (cdms_deflate != 0) || (cdms_netcdf4 == 1)) { - ncmode = ncmode | NC_NETCDF4; + if(strstr(controlpath, "http") == NULL){ + ncmode = ncmode | NC_NETCDF4; + } } #ifdef PARALLEL /* ok we can only use MPIIO if not using shuffle or deflate for reason From e1b587fcad83740d3326e58fbf1099b92333e63f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 5 Jun 2018 18:14:24 -0700 Subject: [PATCH 181/239] Netcdf46 (#249) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env --- .circleci/config.yml | 147 +++++++++++++++++++++++++ .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 --- ci-support/circleci_mac_dep.sh | 102 ----------------- ci-support/circleci_mac_machine_pre.sh | 8 -- ci-support/conda_upload.sh | 83 +++----------- circle.yml | 35 ------ tests/dodsrccircleci | 8 +- tests/test_cdscan.py | 1 + 9 files changed, 171 insertions(+), 232 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 ci-support/circleci_mac.sh delete mode 100644 ci-support/circleci_mac_dep.sh delete mode 100644 ci-support/circleci_mac_machine_pre.sh delete mode 100644 circle.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..8a582e3b --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,147 @@ +version: 2 + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +aliases: + + - &setup_miniconda + name: setup_miniconda + command: | + mkdir -p workspace + git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat + ls workspace/cdat + # following will install miniconda3 under $WORKDIR/miniconda/bin + python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' + + - &create_conda_env + name: create_conda_env + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + conda config --set always_yes yes --set changeps1 no + conda update -y -q conda + conda config --set anaconda_upload no + conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" + conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" + if [ $(uname) == "Linux" ]; then + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + else + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + fi + + - &setup_cdms + name: setup_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + source activate py3 + mkdir $HOME/.esg + echo "Get ESGF certificates" + echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert + cp tests/dodsrccircleci $HOME/.dodsrc + echo "Create .dods_cookies" + curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + source activate py2 + rm -rf build + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + + - &run_cdms_tests + name: run_cdms_tests + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + set -e + source activate py2 + python run_tests.py -v2 + PY2_RESULT=$? + echo "*** py2 test result: "${PY2_RESULT} + source activate py3 + python run_tests.py -v2 + PY3_RESULT=$? + echo "*** py3 test result: "${PY3_RESULT} + echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt + echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt + + - &upload_cdms + name: upload_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export LABEL="nightly"; + # Retrieve results + PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) + PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) + echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} + echo "*** PY2_RESULT: "${PY2_RESULT} + echo "*** PY3_RESULT: "${PY3_RESULT} + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + #if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then + if [ $CIRCLE_BRANCH != "master" ]; then + export LABEL="unstable"; + echo "NOTE: upload LABEL="${LABEL} + conda install -n root conda-build anaconda-client; + bash ./ci-support/conda_upload.sh; + fi + +jobs: + macos_cdms: + macos: + xcode: "9.2.0" + environment: + WORKDIR: "workspace/test_macos_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + linux_cdms: + machine: + image: circleci/classic:latest + environment: + WORKDIR: "workspace/test_linux_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + +workflows: + version: 2 + cdms_test: + jobs: + - macos_cdms + - linux_cdms + + diff --git a/.travis.yml b/.travis.yml index 26d87cc8..0bb331b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh deleted file mode 100644 index 66e14816..00000000 --- a/ci-support/circleci_mac.sh +++ /dev/null @@ -1,15 +0,0 @@ -export UVCDAT_ANONYMOUS_LOG=False -export PATH=${HOME}/miniconda/bin:${PATH} -echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH -echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS -echo "CI_PULL_REQUEST"$CI_PULL_REQUEST -source activate py2 -python run_tests.py -v2 -s -RESULT=$? -source activate py3 -python run_tests.py -v2 -s -RESULT=$(( $RESULT + $? )) -echo "RESULT:"${RESULT} -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi -exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh deleted file mode 100644 index 385aef61..00000000 --- a/ci-support/circleci_mac_dep.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -cmd="ls" -echo $cmd -$cmd - -cmd="pwd" -echo $cmd -$cmd - -cmd="export PATH=${HOME}/miniconda/bin:${PATH}" -echo $cmd -$cmd - -# Create Python 3 environment -cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py3 pyopenssl" -echo $cmd -$cmd - - -cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# Create Python 2 environment -cmd="conda create -n py2 python=2.7" -echo $cmd -$cmd - -# Activate python 2 environment -cmd="source activate py2" -echo $cmd -$cmd - -cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py2 pyopenssl" -echo $cmd -$cmd -: - -# add relative path to ncdump -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" -#echo $cmd -#$cmd - -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" -#echo $cmd -#$cmd - -cmd="export UVCDAT_ANONYMOUS_LOG=False" -echo $cmd -$cmd - -# Retrieve certificates from ESGF -cmd="mkdir /Users/distiller/.esg" -echo $cmd -$cmd - -cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " -eval $cmd - -echo "Create .dods_cookies" -cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" -echo $cmd -$cmd - -#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" -#$cmd - -#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" -#echo $cmd -#$cmd - -#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" -#echo $cmd -#$cmd - -#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" -#echo $cmd -#$cmd - -# compile cdms on py2 and py3 environemt. - -cmd="python setup.py install" -echo $cmd -$cmd - -cmd="source activate py3" -echo $cmd -$cmd - -cmd="python setup.py install" -echo $cmd -$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh deleted file mode 100644 index 386629ec..00000000 --- a/ci-support/circleci_mac_machine_pre.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh -bash miniconda.sh -b -p $HOME/miniconda -export PATH=${HOME}/miniconda/bin:${PATH} -conda config --set always_yes yes --set changeps1 no -conda update -y -q conda -conda config --set anaconda_upload no -#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ef61e574..ebde3a90 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,83 +1,34 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -echo "Trying to upload conda" -mkdir ${HOME}/conda-bld -export CONDA_BLD_PATH=${HOME}/conda-bld -export VERSION="2.12" +export VERSION="3.0" +echo "Trying to upload to conda" +echo "" +echo "Activating base env" +source activate base +echo "Making sure conda-build is installed" +conda install "conda-build<3.10" +echo "Updating conda" +conda update -y -q conda if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" - yum install -y wget git gcc - # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null - wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null - bash miniconda2.sh -b -p ${HOME}/miniconda - export SYSPATH=$PATH - export PATH=${HOME}/miniconda/bin:${SYSPATH} - echo $PATH - conda config --set always_yes yes --set changeps1 no - conda config --set anaconda_upload false --set ssl_verify false - conda install -n root -q anaconda-client "conda-build<3.3" - conda install -n root gcc future - which python - export UVCDAT_ANONYMOUS_LOG=False - BRANCH=${TRAVIS_BRANCH} -# echo "Creating python 3 env" -# conda create -n py3 python=3.6 -# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy -# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy -# echo "Creating certificate" -# source activate py3 -# mkdir ${HOME}/.esg -# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert -# ls ${HOME}/.esg -# cd travis_home -# ls -# cp tests/dodsrc ${HOME}.dodsrc -# source deactivate else echo "Mac OS" OS=osx-64 - BRANCH=${CIRCLE_BRANCH} fi -which python -if [ `uname` == "Linux" ]; then - conda install -n root -q anaconda-client "conda-build<3.3" -else - conda install -n root -q anaconda-client conda-build -fi -# pin conda so that conda-build does not update it -#if [ `uname` == "Darwin" ]; then -# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 -#fi +mkdir ~/conda-bld conda config --set anaconda_upload no +export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -cd ${HOME} -git clone git://github.com/UV-CDAT/conda-recipes +git clone git://github.com/CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -python ./prep_for_build.py -b ${BRANCH} -echo "Building now" -echo "use nesii/label/dev-esmf for esmf" -conda build -V -conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat -# -# binstar config set 'false' instead of false (not quote) I have to do it manually -# this is true for OSX. -# binstar is changing verify_ssl to ssl_verify, but the later is not always working -# -# binstar config --set verify_ssl false -# binstar config --set ssl_verify false -# -mkdir -p ~/.continuum/anaconda-client/ -echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml -echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml -if [ `uname` == "Darwin" ]; then - # fix conda and anaconda-client conflict - conda install conda==4.2.16 -fi -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force - +export BRANCH=${CIRCLE_BRANCH} +python ./prep_for_build.py -b ${BRANCH} +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 5d2059a9..00000000 --- a/circle.yml +++ /dev/null @@ -1,35 +0,0 @@ -general: - #branches: - # ignore: - # We only want to build pull requests for testing. If something is merged, - # then we are prepping for release an there is no need to build it again. - # - master -# artifacts: -# - tests_html -# - tests_png - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -#machine: -machine: -# xcode: -# version: 7.2 - pre: - - sudo -H pip install --upgrade virtualenv - - ls - - pwd - - bash cdms/ci-support/circleci_mac_machine_pre.sh - #services: - # - docker - -dependencies: - override: - - bash ./ci-support/circleci_mac_dep.sh - # - docker pull cdat/conda:conda-forge-cdms2 - -test: - override: - - bash ./ci-support/circleci_mac.sh - # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b9b0608f..b2d0bbe8 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert -HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert -HTTP.SSL.CAPATH=/Users/distiller/.esg/ +HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert +HTTP.SSL.KEY=$HOME/.esg/esgf.cert +HTTP.SSL.CAPATH=$HOME/.esg/ diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index e53bdcba..97104482 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -58,6 +58,7 @@ def testopenFile(self): pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() + os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From 97279beaa7826f808a7780fbbec5584999fdc59f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 5 Jun 2018 18:15:04 -0700 Subject: [PATCH 182/239] Revert "Netcdf46 (#249)" (#250) This reverts commit a9e29eaaecd1158071660d4ce26ccafb56820639. --- .circleci/config.yml | 147 ------------------------- .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 +++ ci-support/circleci_mac_dep.sh | 102 +++++++++++++++++ ci-support/circleci_mac_machine_pre.sh | 8 ++ ci-support/conda_upload.sh | 83 +++++++++++--- circle.yml | 35 ++++++ tests/dodsrccircleci | 8 +- tests/test_cdscan.py | 1 - 9 files changed, 232 insertions(+), 171 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 ci-support/circleci_mac.sh create mode 100644 ci-support/circleci_mac_dep.sh create mode 100644 ci-support/circleci_mac_machine_pre.sh create mode 100644 circle.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8a582e3b..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,147 +0,0 @@ -version: 2 - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -aliases: - - - &setup_miniconda - name: setup_miniconda - command: | - mkdir -p workspace - git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat - ls workspace/cdat - # following will install miniconda3 under $WORKDIR/miniconda/bin - python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' - - - &create_conda_env - name: create_conda_env - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - conda config --set always_yes yes --set changeps1 no - conda update -y -q conda - conda config --set anaconda_upload no - conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" - conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" - if [ $(uname) == "Linux" ]; then - conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 - conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 - else - conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc - conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc - fi - - - &setup_cdms - name: setup_cdms - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export UVCDAT_ANONYMOUS_LOG=False - source activate py3 - mkdir $HOME/.esg - echo "Get ESGF certificates" - echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert - cp tests/dodsrccircleci $HOME/.dodsrc - echo "Create .dods_cookies" - curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" - if [ $(uname) == "Linux" ];then - export LDSHARED="$CC -shared -pthread" - LDSHARED="$CC -shared -pthread" python setup.py install - else - python setup.py install - fi - source activate py2 - rm -rf build - if [ $(uname) == "Linux" ];then - export LDSHARED="$CC -shared -pthread" - LDSHARED="$CC -shared -pthread" python setup.py install - else - python setup.py install - fi - - - &run_cdms_tests - name: run_cdms_tests - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export UVCDAT_ANONYMOUS_LOG=False - set -e - source activate py2 - python run_tests.py -v2 - PY2_RESULT=$? - echo "*** py2 test result: "${PY2_RESULT} - source activate py3 - python run_tests.py -v2 - PY3_RESULT=$? - echo "*** py3 test result: "${PY3_RESULT} - echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt - echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt - - - &upload_cdms - name: upload_cdms - command: | - export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH - export LABEL="nightly"; - # Retrieve results - PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) - PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) - echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} - echo "*** PY2_RESULT: "${PY2_RESULT} - echo "*** PY3_RESULT: "${PY3_RESULT} - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi - #if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then - if [ $CIRCLE_BRANCH != "master" ]; then - export LABEL="unstable"; - echo "NOTE: upload LABEL="${LABEL} - conda install -n root conda-build anaconda-client; - bash ./ci-support/conda_upload.sh; - fi - -jobs: - macos_cdms: - macos: - xcode: "9.2.0" - environment: - WORKDIR: "workspace/test_macos_cdms" - steps: - - checkout - - run: *setup_miniconda - - run: *create_conda_env - - run: *setup_cdms - - run: *run_cdms_tests - - run: *upload_cdms - - store_artifacts: - path: tests_html - destination: tests_html - - store_artifacts: - path: tests_png - destination: tests_png - - linux_cdms: - machine: - image: circleci/classic:latest - environment: - WORKDIR: "workspace/test_linux_cdms" - steps: - - checkout - - run: *setup_miniconda - - run: *create_conda_env - - run: *setup_cdms - - run: *run_cdms_tests - - run: *upload_cdms - - store_artifacts: - path: tests_html - destination: tests_html - - store_artifacts: - path: tests_png - destination: tests_png - - -workflows: - version: 2 - cdms_test: - jobs: - - macos_cdms - - linux_cdms - - diff --git a/.travis.yml b/.travis.yml index 0bb331b0..26d87cc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh new file mode 100644 index 00000000..66e14816 --- /dev/null +++ b/ci-support/circleci_mac.sh @@ -0,0 +1,15 @@ +export UVCDAT_ANONYMOUS_LOG=False +export PATH=${HOME}/miniconda/bin:${PATH} +echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH +echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS +echo "CI_PULL_REQUEST"$CI_PULL_REQUEST +source activate py2 +python run_tests.py -v2 -s +RESULT=$? +source activate py3 +python run_tests.py -v2 -s +RESULT=$(( $RESULT + $? )) +echo "RESULT:"${RESULT} +if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi +if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi +exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh new file mode 100644 index 00000000..385aef61 --- /dev/null +++ b/ci-support/circleci_mac_dep.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +cmd="ls" +echo $cmd +$cmd + +cmd="pwd" +echo $cmd +$cmd + +cmd="export PATH=${HOME}/miniconda/bin:${PATH}" +echo $cmd +$cmd + +# Create Python 3 environment +cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# update openssl for myproxyclient +cmd="conda install -n py3 pyopenssl" +echo $cmd +$cmd + + +cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# Create Python 2 environment +cmd="conda create -n py2 python=2.7" +echo $cmd +$cmd + +# Activate python 2 environment +cmd="source activate py2" +echo $cmd +$cmd + +cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" +echo $cmd +$cmd + +# update openssl for myproxyclient +cmd="conda install -n py2 pyopenssl" +echo $cmd +$cmd +: + +# add relative path to ncdump +#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" +#echo $cmd +#$cmd + +#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" +#echo $cmd +#$cmd + +cmd="export UVCDAT_ANONYMOUS_LOG=False" +echo $cmd +$cmd + +# Retrieve certificates from ESGF +cmd="mkdir /Users/distiller/.esg" +echo $cmd +$cmd + +cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " +eval $cmd + +echo "Create .dods_cookies" +cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" +echo $cmd +$cmd + +#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" +#$cmd + +#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" +#echo $cmd +#$cmd + +#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" +#echo $cmd +#$cmd + +#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" +#echo $cmd +#$cmd + +# compile cdms on py2 and py3 environemt. + +cmd="python setup.py install" +echo $cmd +$cmd + +cmd="source activate py3" +echo $cmd +$cmd + +cmd="python setup.py install" +echo $cmd +$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh new file mode 100644 index 00000000..386629ec --- /dev/null +++ b/ci-support/circleci_mac_machine_pre.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh +bash miniconda.sh -b -p $HOME/miniconda +export PATH=${HOME}/miniconda/bin:${PATH} +conda config --set always_yes yes --set changeps1 no +conda update -y -q conda +conda config --set anaconda_upload no +#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ebde3a90..ef61e574 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,34 +1,83 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -export VERSION="3.0" -echo "Trying to upload to conda" -echo "" -echo "Activating base env" -source activate base -echo "Making sure conda-build is installed" -conda install "conda-build<3.10" -echo "Updating conda" -conda update -y -q conda +echo "Trying to upload conda" +mkdir ${HOME}/conda-bld +export CONDA_BLD_PATH=${HOME}/conda-bld +export VERSION="2.12" if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" + yum install -y wget git gcc + # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null + wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null + bash miniconda2.sh -b -p ${HOME}/miniconda + export SYSPATH=$PATH + export PATH=${HOME}/miniconda/bin:${SYSPATH} + echo $PATH + conda config --set always_yes yes --set changeps1 no + conda config --set anaconda_upload false --set ssl_verify false + conda install -n root -q anaconda-client "conda-build<3.3" + conda install -n root gcc future + which python + export UVCDAT_ANONYMOUS_LOG=False + BRANCH=${TRAVIS_BRANCH} +# echo "Creating python 3 env" +# conda create -n py3 python=3.6 +# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy +# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy +# echo "Creating certificate" +# source activate py3 +# mkdir ${HOME}/.esg +# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert +# ls ${HOME}/.esg +# cd travis_home +# ls +# cp tests/dodsrc ${HOME}.dodsrc +# source deactivate else echo "Mac OS" OS=osx-64 + BRANCH=${CIRCLE_BRANCH} fi -mkdir ~/conda-bld +which python +if [ `uname` == "Linux" ]; then + conda install -n root -q anaconda-client "conda-build<3.3" +else + conda install -n root -q anaconda-client conda-build +fi +# pin conda so that conda-build does not update it +#if [ `uname` == "Darwin" ]; then +# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 +#fi conda config --set anaconda_upload no -export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -git clone git://github.com/CDAT/conda-recipes +cd ${HOME} +git clone git://github.com/UV-CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -export BRANCH=${CIRCLE_BRANCH} -python ./prep_for_build.py -b ${BRANCH} +python ./prep_for_build.py -b ${BRANCH} +echo "Building now" +echo "use nesii/label/dev-esmf for esmf" +conda build -V +conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat +# +# binstar config set 'false' instead of false (not quote) I have to do it manually +# this is true for OSX. +# binstar is changing verify_ssl to ssl_verify, but the later is not always working +# +# binstar config --set verify_ssl false +# binstar config --set ssl_verify false +# +mkdir -p ~/.continuum/anaconda-client/ +echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml +echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml +if [ `uname` == "Darwin" ]; then + # fix conda and anaconda-client conflict + conda install conda==4.2.16 +fi +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force + -conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 -conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml new file mode 100644 index 00000000..5d2059a9 --- /dev/null +++ b/circle.yml @@ -0,0 +1,35 @@ +general: + #branches: + # ignore: + # We only want to build pull requests for testing. If something is merged, + # then we are prepping for release an there is no need to build it again. + # - master +# artifacts: +# - tests_html +# - tests_png + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +#machine: +machine: +# xcode: +# version: 7.2 + pre: + - sudo -H pip install --upgrade virtualenv + - ls + - pwd + - bash cdms/ci-support/circleci_mac_machine_pre.sh + #services: + # - docker + +dependencies: + override: + - bash ./ci-support/circleci_mac_dep.sh + # - docker pull cdat/conda:conda-forge-cdms2 + +test: + override: + - bash ./ci-support/circleci_mac.sh + # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b2d0bbe8..b9b0608f 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert -HTTP.SSL.KEY=$HOME/.esg/esgf.cert -HTTP.SSL.CAPATH=$HOME/.esg/ +HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert +HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert +HTTP.SSL.CAPATH=/Users/distiller/.esg/ diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index 97104482..e53bdcba 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -58,7 +58,6 @@ def testopenFile(self): pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() - os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From f6ca66930de7adaa1b50ee0919c208a0dde59554 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 12 Jun 2018 15:24:36 -0700 Subject: [PATCH 183/239] Netcdf46 (#251) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env * inverse dodsrc and curl commands * move unlink above cdscan test * fix ESGF test * add new dodsrc files * create dodsrc on-demand * put back tests for unstable --- .circleci/config.yml | 147 +++++++++++++++++++++++++ .travis.yml | 4 +- ci-support/circleci_mac.sh | 15 --- ci-support/circleci_mac_dep.sh | 102 ----------------- ci-support/circleci_mac_machine_pre.sh | 8 -- ci-support/conda_upload.sh | 83 +++----------- circle.yml | 35 ------ tests/dodsrccircleci | 8 +- tests/dodsrccircleciDarwin | 6 + tests/dodsrccircleciLinux | 6 + tests/test_all_formats.py | 17 ++- tests/test_cdscan.py | 11 +- 12 files changed, 203 insertions(+), 239 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 ci-support/circleci_mac.sh delete mode 100644 ci-support/circleci_mac_dep.sh delete mode 100644 ci-support/circleci_mac_machine_pre.sh delete mode 100644 circle.yml create mode 100644 tests/dodsrccircleciDarwin create mode 100644 tests/dodsrccircleciLinux diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..6988a468 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,147 @@ +version: 2 + +checkout: + post: + - ./ci-support/checkout_merge_commit.sh + +aliases: + + - &setup_miniconda + name: setup_miniconda + command: | + mkdir -p workspace + git clone -b validateNightly git@github.com:CDAT/cdat workspace/cdat + ls workspace/cdat + # following will install miniconda3 under $WORKDIR/miniconda/bin + python workspace/cdat/scripts/install_miniconda.py -w $WORKDIR -p 'py3' + + - &create_conda_env + name: create_conda_env + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + conda config --set always_yes yes --set changeps1 no + conda update -y -q conda + conda config --set anaconda_upload no + conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" + conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" + if [ $(uname) == "Linux" ]; then + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 + else + conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc + fi + + - &setup_cdms + name: setup_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + source activate py3 + mkdir $HOME/.esg + echo "Get ESGF certificates" + echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert + echo "Create .dods_cookies" + curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" + if [ $(uname) == "Linux" ];then + cp tests/dodsrccircleciLinux $HOME/.dodsrc + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + cp tests/dodsrccircleciDarwin $HOME/.dodsrc + python setup.py install + fi + source activate py2 + rm -rf build + if [ $(uname) == "Linux" ];then + export LDSHARED="$CC -shared -pthread" + LDSHARED="$CC -shared -pthread" python setup.py install + else + python setup.py install + fi + + - &run_cdms_tests + name: run_cdms_tests + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export UVCDAT_ANONYMOUS_LOG=False + set -e + source activate py2 + python run_tests.py -v2 + PY2_RESULT=$? + echo "*** py2 test result: "${PY2_RESULT} + source activate py3 + python run_tests.py -v2 + PY3_RESULT=$? + echo "*** py3 test result: "${PY3_RESULT} + echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt + echo $PY3_RESULT > $HOME/project/$WORKDIR/py3_result.txt + + - &upload_cdms + name: upload_cdms + command: | + export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH + export LABEL="nightly"; + # Retrieve results + PY2_RESULT=$(cat $HOME/project/$WORKDIR/py2_result.txt) + PY3_RESULT=$(cat $HOME/project/$WORKDIR/py3_result.txt) + echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} + echo "*** PY2_RESULT: "${PY2_RESULT} + echo "*** PY3_RESULT: "${PY3_RESULT} + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then + export LABEL="unstable"; + echo "NOTE: upload LABEL="${LABEL} + conda install -n root conda-build anaconda-client; + bash ./ci-support/conda_upload.sh; + fi + +jobs: + macos_cdms: + macos: + xcode: "9.2.0" + environment: + WORKDIR: "workspace/test_macos_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + linux_cdms: + machine: + image: circleci/classic:latest + environment: + WORKDIR: "workspace/test_linux_cdms" + steps: + - checkout + - run: *setup_miniconda + - run: *create_conda_env + - run: *setup_cdms + - run: *run_cdms_tests + - run: *upload_cdms + - store_artifacts: + path: tests_html + destination: tests_html + - store_artifacts: + path: tests_png + destination: tests_png + + +workflows: + version: 2 + cdms_test: + jobs: + - macos_cdms + - linux_cdms + + diff --git a/.travis.yml b/.travis.yml index 26d87cc8..0bb331b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ before_install: script: #- conda install -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - conda create -n py3 python=3.6 -- conda install -n py3 -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient +- conda install -n py3 -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl=17.2.0 nose requests flake8 myproxyclient - source activate py3 - if [ "$TRAVIS_OS_NAME" = "linux" ]; then conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy ; fi - export UVCDAT_ANONYMOUS_LOG=False @@ -37,7 +37,7 @@ script: - conda create -n py2 python=2.7 - source activate py2 - which python -- conda install -c nesii/channel/dev-esmf -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 +- conda install -c nesii/channel/dev-esmf -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 - export UVCDAT_ANONYMOUS_LOG=False - python setup.py install - python run_tests.py -v2 -s diff --git a/ci-support/circleci_mac.sh b/ci-support/circleci_mac.sh deleted file mode 100644 index 66e14816..00000000 --- a/ci-support/circleci_mac.sh +++ /dev/null @@ -1,15 +0,0 @@ -export UVCDAT_ANONYMOUS_LOG=False -export PATH=${HOME}/miniconda/bin:${PATH} -echo "CIRCLE CI BRANCH:"$CIRCLE_BRANCH -echo "CI_PULL_REQUESTS"$CI_PULL_REQUESTS -echo "CI_PULL_REQUEST"$CI_PULL_REQUEST -source activate py2 -python run_tests.py -v2 -s -RESULT=$? -source activate py3 -python run_tests.py -v2 -s -RESULT=$(( $RESULT + $? )) -echo "RESULT:"${RESULT} -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then LABEL='unstable' bash ./ci-support/conda_upload.sh ; fi -if [ $RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then LABEL='nightly' bash ./ci-support/conda_upload.sh ; fi -exit $RESULT diff --git a/ci-support/circleci_mac_dep.sh b/ci-support/circleci_mac_dep.sh deleted file mode 100644 index 385aef61..00000000 --- a/ci-support/circleci_mac_dep.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -cmd="ls" -echo $cmd -$cmd - -cmd="pwd" -echo $cmd -$cmd - -cmd="export PATH=${HOME}/miniconda/bin:${PATH}" -echo $cmd -$cmd - -# Create Python 3 environment -cmd="conda create -n py3 -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py3 pyopenssl" -echo $cmd -$cmd - - -cmd="conda install -n py3 -c nesii/label/dev-esmf -c conda-forge esmf esmpy netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# Create Python 2 environment -cmd="conda create -n py2 python=2.7" -echo $cmd -$cmd - -# Activate python 2 environment -cmd="source activate py2" -echo $cmd -$cmd - -cmd="conda install -n py2 -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient netcdf-fortran=4.4.4=5" -echo $cmd -$cmd - -# update openssl for myproxyclient -cmd="conda install -n py2 pyopenssl" -echo $cmd -$cmd -: - -# add relative path to ncdump -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py2/bin/ncdump" -#echo $cmd -#$cmd - -#cmd="install_name_tool -change /usr/lib/libcurl.4.dylib @rpath/libcurl.4.dylib ${HOME}/miniconda/envs/py3/bin/ncdump" -#echo $cmd -#$cmd - -cmd="export UVCDAT_ANONYMOUS_LOG=False" -echo $cmd -$cmd - -# Retrieve certificates from ESGF -cmd="mkdir /Users/distiller/.esg" -echo $cmd -$cmd - -cmd="echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o /Users/distiller/.esg/esgf.cert " -eval $cmd - -echo "Create .dods_cookies" -cmd="curl -L -v -c /Users/distiller/.esg/.dods_cookies --cert /Users/distiller/.esg/esgf.cert --key /Users/distiller/.esg/esgf.cert https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" -echo $cmd -$cmd - -#cmd="openssl pkcs12 -export -inkey /Users/distiller/.esg/esgf.cert -in /Users/distiller/.esg/esgf.cert -name esgf -out /Users/distiller/.esg/esgf.p12 -passout pass:esgf" -#$cmd - -#cmd="sudo security import /Users/distiller/.esg/esgf.p12 -A -P esgf -k /Library/Keychains/System.keychain" -#echo $cmd -#$cmd - -#cmd="sudo security add-trusted-cert -d -r trustRoot -k '/Library/Keychains/System.keychain' /Users/distiller/.esg/esgf.cert" -#echo $cmd -#$cmd - -#cmd="cp tests/dodsrccircleci /Users/distiller/.dodsrc" -#echo $cmd -#$cmd - -# compile cdms on py2 and py3 environemt. - -cmd="python setup.py install" -echo $cmd -$cmd - -cmd="source activate py3" -echo $cmd -$cmd - -cmd="python setup.py install" -echo $cmd -$cmd diff --git a/ci-support/circleci_mac_machine_pre.sh b/ci-support/circleci_mac_machine_pre.sh deleted file mode 100644 index 386629ec..00000000 --- a/ci-support/circleci_mac_machine_pre.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -curl https://repo.continuum.io/miniconda/Miniconda3-4.3.30.1-MacOSX-x86_64.sh -o miniconda.sh -bash miniconda.sh -b -p $HOME/miniconda -export PATH=${HOME}/miniconda/bin:${PATH} -conda config --set always_yes yes --set changeps1 no -conda update -y -q conda -conda config --set anaconda_upload no -#git clone git://github.com/uv-cdat/uvcdat-testdata diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh index ef61e574..ebde3a90 100644 --- a/ci-support/conda_upload.sh +++ b/ci-support/conda_upload.sh @@ -1,83 +1,34 @@ #!/usr/bin/env bash PKG_NAME=cdms2 USER=cdat -echo "Trying to upload conda" -mkdir ${HOME}/conda-bld -export CONDA_BLD_PATH=${HOME}/conda-bld -export VERSION="2.12" +export VERSION="3.0" +echo "Trying to upload to conda" +echo "" +echo "Activating base env" +source activate base +echo "Making sure conda-build is installed" +conda install "conda-build<3.10" +echo "Updating conda" +conda update -y -q conda if [ `uname` == "Linux" ]; then OS=linux-64 echo "Linux OS" - yum install -y wget git gcc - # wget --no-check https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3.sh 2> /dev/null - wget --no-check https://repo.continuum.io/miniconda/Miniconda2-4.3.30-Linux-x86_64.sh -O miniconda2.sh 2> /dev/null - bash miniconda2.sh -b -p ${HOME}/miniconda - export SYSPATH=$PATH - export PATH=${HOME}/miniconda/bin:${SYSPATH} - echo $PATH - conda config --set always_yes yes --set changeps1 no - conda config --set anaconda_upload false --set ssl_verify false - conda install -n root -q anaconda-client "conda-build<3.3" - conda install -n root gcc future - which python - export UVCDAT_ANONYMOUS_LOG=False - BRANCH=${TRAVIS_BRANCH} -# echo "Creating python 3 env" -# conda create -n py3 python=3.6 -# conda install -n py3 -c conda-forge -c uvcdat setuptools libcf distarray cdtime libcdms cdat_info numpy libdrs_f pyopenssl nose requests flake8 myproxyclient numpy -# conda install -n py3 -c nesii/channel/dev-esmf -c conda-forge esmpy -# echo "Creating certificate" -# source activate py3 -# mkdir ${HOME}/.esg -# echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o ${HOME}/.esg/esgf.cert -# ls ${HOME}/.esg -# cd travis_home -# ls -# cp tests/dodsrc ${HOME}.dodsrc -# source deactivate else echo "Mac OS" OS=osx-64 - BRANCH=${CIRCLE_BRANCH} fi -which python -if [ `uname` == "Linux" ]; then - conda install -n root -q anaconda-client "conda-build<3.3" -else - conda install -n root -q anaconda-client conda-build -fi -# pin conda so that conda-build does not update it -#if [ `uname` == "Darwin" ]; then -# echo "conda ==4.3.21" >> ~/miniconda/conda-meta/pinned # Pin conda as workaround for conda/conda#6030 -#fi +mkdir ~/conda-bld conda config --set anaconda_upload no +export CONDA_BLD_PATH=${HOME}/conda-bld echo "Cloning recipes" -cd ${HOME} -git clone git://github.com/UV-CDAT/conda-recipes +git clone git://github.com/CDAT/conda-recipes cd conda-recipes # uvcdat creates issues for build -c uvcdat confises package and channel rm -rf uvcdat -python ./prep_for_build.py -b ${BRANCH} -echo "Building now" -echo "use nesii/label/dev-esmf for esmf" -conda build -V -conda build $PKG_NAME -c nesii/label/dev-esmf -c uvcdat/label/nightly -c conda-forge -c uvcdat -# -# binstar config set 'false' instead of false (not quote) I have to do it manually -# this is true for OSX. -# binstar is changing verify_ssl to ssl_verify, but the later is not always working -# -# binstar config --set verify_ssl false -# binstar config --set ssl_verify false -# -mkdir -p ~/.continuum/anaconda-client/ -echo "ssl_verify: false" >> ~/.continuum/anaconda-client/config.yaml -echo "verify_ssl: false" >> ~/.continuum/anaconda-client/config.yaml -if [ `uname` == "Darwin" ]; then - # fix conda and anaconda-client conflict - conda install conda==4.2.16 -fi -anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l ${LABEL} ${CONDA_BLD_PATH}/$OS/$PKG_NAME-$VERSION.`date +%Y`*_0.tar.bz2 --force - +export BRANCH=${CIRCLE_BRANCH} +python ./prep_for_build.py -b ${BRANCH} +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 3.6 +conda build ${PKG_NAME} -c cdat/label/unstable -c conda-forge --python 2.7 +anaconda -t $CONDA_UPLOAD_TOKEN upload -u $USER -l $LABEL $CONDA_BLD_PATH/$OS/${PKG_NAME}-$VERSION.`date +%Y*`0.tar.bz2 --force diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 5d2059a9..00000000 --- a/circle.yml +++ /dev/null @@ -1,35 +0,0 @@ -general: - #branches: - # ignore: - # We only want to build pull requests for testing. If something is merged, - # then we are prepping for release an there is no need to build it again. - # - master -# artifacts: -# - tests_html -# - tests_png - -checkout: - post: - - ./ci-support/checkout_merge_commit.sh - -#machine: -machine: -# xcode: -# version: 7.2 - pre: - - sudo -H pip install --upgrade virtualenv - - ls - - pwd - - bash cdms/ci-support/circleci_mac_machine_pre.sh - #services: - # - docker - -dependencies: - override: - - bash ./ci-support/circleci_mac_dep.sh - # - docker pull cdat/conda:conda-forge-cdms2 - -test: - override: - - bash ./ci-support/circleci_mac.sh - # - docker run -it -v `pwd`:/git_repo -a STDOUT -a STDERR -P cdat/conda:conda-forge-cdms2 /git_repo/ci-support/circle.sh diff --git a/tests/dodsrccircleci b/tests/dodsrccircleci index b9b0608f..b2d0bbe8 100644 --- a/tests/dodsrccircleci +++ b/tests/dodsrccircleci @@ -1,6 +1,6 @@ HTTP.VERBOSE=0 -HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies -HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert -HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert -HTTP.SSL.CAPATH=/Users/distiller/.esg/ +HTTP.COOKIEJAR=$HOME/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=$HOME/.esg/esgf.cert +HTTP.SSL.KEY=$HOME/.esg/esgf.cert +HTTP.SSL.CAPATH=$HOME/.esg/ diff --git a/tests/dodsrccircleciDarwin b/tests/dodsrccircleciDarwin new file mode 100644 index 00000000..b9b0608f --- /dev/null +++ b/tests/dodsrccircleciDarwin @@ -0,0 +1,6 @@ +HTTP.VERBOSE=0 +HTTP.COOKIEJAR=/Users/distiller/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/Users/distiller/.esg/esgf.cert +HTTP.SSL.KEY=/Users/distiller/.esg/esgf.cert +HTTP.SSL.CAPATH=/Users/distiller/.esg/ + diff --git a/tests/dodsrccircleciLinux b/tests/dodsrccircleciLinux new file mode 100644 index 00000000..2269387e --- /dev/null +++ b/tests/dodsrccircleciLinux @@ -0,0 +1,6 @@ +HTTP.VERBOSE=0 +HTTP.COOKIEJAR=/home/circleci/.esg/.dods_cookies +HTTP.SSL.CERTIFICATE=/home/circleci/.esg/esgf.cert +HTTP.SSL.KEY=/home/circleci/.esg/esgf.cert +HTTP.SSL.CAPATH=/home/circleci/.esg/ + diff --git a/tests/test_all_formats.py b/tests/test_all_formats.py index 8a6cc387..bee09221 100644 --- a/tests/test_all_formats.py +++ b/tests/test_all_formats.py @@ -3,6 +3,8 @@ import sys import cdat_info import basetest +import platform +from shutil import copyfile class TestFormats(basetest.CDMSBaseTest): @@ -20,7 +22,11 @@ def testDRS(self): data = f['a'] self.assertEqual(data.missing_value, 1e20) - def testDAP(self): + def dtestDAP(self): + try: + os.unlink(os.environ['HOME']+'/.dodsrc') + except: + pass f = cdms2.open('http://test.opendap.org/opendap/hyrax/data/nc/coads_climatology.nc') data=f['SST'] self.assertEqual(data.missing_value, -1e34) @@ -32,7 +38,14 @@ def testGRIB2(self): self.assertEqual(data.missing_value, 9.999e20) # test disabled due to OSX issue - def dtestESGF(self): + def testESGF(self): + file = open(os.environ['HOME']+'/.dodsrc','w') + file.write("HTTP.VERBOSE=0\n") + file.write("HTTP.COOKIEJAR="+os.environ['HOME']+"/.esg/.dods_cookies\n") + file.write("HTTP.SSL.CERTIFICATE="+os.environ['HOME']+"/.esg/esgf.cert\n") + file.write("HTTP.SSL.KEY="+os.environ['HOME']+"/.esg/esgf.cert\n") + file.write("HTTP.SSL.CAPATH="+os.environ['HOME']+"/.esg/\n") + file.close() f = cdms2.open("https://aims3.llnl.gov/thredds/dodsC/cmip5_css01_data/cmip5/output1/BCC/bcc-csm1-1-m/1pctCO2/day/ocean/day/r1i1p1/v20120910/tos/tos_day_bcc-csm1-1-m_1pctCO2_r1i1p1_02800101-02891231.nc") self.assertIn('tos', f.listvariables()) data=f['tos'] diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py index e53bdcba..9bb24173 100644 --- a/tests/test_cdscan.py +++ b/tests/test_cdscan.py @@ -1,5 +1,9 @@ - import basetest +import os +try: + os.unlink(os.environ['HOME']+'/.dodsrc') +except: + pass import cdms2 from cdms2.cdscan import main as cdscan import os @@ -52,12 +56,9 @@ def testopenFile(self): ''' retrieve value from cdscan ''' - try: - os.unlink(os.environ['HOME']+'/.dodsrc') - except: - pass argv = 'cdscan -x test_dap.xml https://dataserver.nccs.nasa.gov/thredds/dodsC/bypass/CREATE-IP/Reanalysis/NASA-GMAO/GEOS-5/MERRA/mon/atmos/zg.ncml'.split() pth = cdat_info.get_sampledata_path() + os.chdir(pth) cdscan(argv) f=cdms2.open("test_dap.xml") From 180f9e1b837fb41521d16a001ca8777a9f6d2cab Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 12 Jun 2018 16:29:12 -0700 Subject: [PATCH 184/239] Netcdf46 (#252) * Fix python3 slice issue(setitem) and flake8 * update to libnetcdf 4.6 * try circleci unstable label * try version 2 circleci * try version 2 circleci * change workflow name * change cdtime to cdms * add certificate to circleci * add fix conda-upload in circleci 2.0 * update prep_for_build version * fix curl command * fix cicleci for cdms * use unstable channel change uvcdat for cdat * build cdms on circleci 2.0 * fix circleci config.yml * change Users/distiler to /Users/denisnadeau * add gcc_linux * add LDSHARED for linux * disable cert and py results * add gcc_linux-64 * change cdscan link * fix myproxy * add esmf and esmpy to py3 env * inverse dodsrc and curl commands * move unlink above cdscan test * fix ESGF test * add new dodsrc files * create dodsrc on-demand * put back tests for unstable * instal anaconda-client before calling conda-upload --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6988a468..6e1432ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -88,8 +88,9 @@ aliases: echo "*** CIRCLE BRANCH: "${CIRCLE_BRANCH} echo "*** PY2_RESULT: "${PY2_RESULT} echo "*** PY3_RESULT: "${PY3_RESULT} - if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then conda install -n root conda-build anaconda-client ; fi + if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH == "master" ]; then bash ./ci-support/conda_upload.sh ; fi if [ $PY2_RESULT -eq 0 -a $PY3_RESULT -eq 0 -a $CIRCLE_BRANCH != "master" ]; then export LABEL="unstable"; echo "NOTE: upload LABEL="${LABEL} From 09d70ec7c75303e6ca467947421929c187e71f3d Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 20 Jun 2018 14:46:57 -0700 Subject: [PATCH 185/239] Fix table titles --- docs/source/manual/cdms_3.rst | 25 ++++++++++++------------- docs/source/manual/cdms_4.rst | 16 ++++++++-------- docs/source/manual/cdms_5.rst | 4 ++-- docs/source/manual/cdms_6.rst | 24 ++++++++++++------------ docs/source/manual/cdms_7.rst | 4 ++-- docs/source/manual/cdms_appendix.rst | 8 ++++---- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 437cb786..e349b047 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -78,7 +78,7 @@ Time Constructors The following table describes the methods for creating time types. -Table Time Constructors +Time Constructors Types ~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: @@ -92,7 +92,6 @@ Table Time Constructors * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. * The default basetime is 1979-1-1, if no ``since`` clause is specified. **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``" - "Comptime", "``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``", "Create a component time type. * ``year`` is an integer. * ``month`` is an integer in the range 1 .. 12 @@ -109,23 +108,23 @@ Relative Time A relative time type has two members, value and units. Both can be set. -Table Relative Time Members -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Relative Time Member Types +~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. csv-table:: + :header: "Type", "Name", "Summary" + :widths: 15, 15, 50 + + + "Float", "value", "Number of units" + "String", "units", "Relative units, of the form “unit(s) since basetime" -+----------+---------+-------------------------------------------------------+ -| Type | Name | Summary | -+==========+=========+=======================================================+ -| Float | value | Number of units | -+----------+---------+-------------------------------------------------------+ -| String | units | Relative units, of the form “unit(s) since basetime | -+----------+---------+-------------------------------------------------------+ Component Time ^^^^^^^^^^^^^^ A component time type has six members, all of which are settable. -Table Component Time +Component Time Types ~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Name", "Summary" @@ -143,7 +142,7 @@ Time Methods The following methods apply both to relative and component times. -Table Time Methods +Time Methods Types ~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Method", "Definition" diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 9e2448bc..42afc8c7 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -300,8 +300,8 @@ makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. -Table CDMS Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CDMS Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" @@ -316,8 +316,8 @@ SCRIP Regridder SCRIP regridder functions are created with the ``regrid.readRegridder`` function: -Table SCRIP Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +SCRIP Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: @@ -399,7 +399,7 @@ data value, or 1.0e20 if undefined. The result array or transient variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values -Table CDMS Regridder Function +CDMS Regridder Function Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: @@ -458,7 +458,7 @@ following fields: In addition, a conservative regridder has the associated grid cell areas for source and target grids. -Table SCRIP Regridder Functions +SCRIP Regridder Function Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: @@ -503,8 +503,8 @@ Regrid data to a uniform output grid. >>> newrls = regridFunc(cltf) >>> f.close() -Table Regridder Constructure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Regridder Constructures +~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Line", "Notes" diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 0831ec8a..1a9cae90 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -177,8 +177,8 @@ where: - ``key=value``, ... are optional keyword/value pairs, listed in any order. These are defined in the table below. -Table Plot Keywords -^^^^^^^^^^^^^^^^^^^ +Plot Keywords +^^^^^^^^^^^^^ .. csv-table:: :header: "Key", "Type", "Value" diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 5d9e6b5e..b13ff9ed 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -50,8 +50,8 @@ where The CDML elements are: -Table CDML Tags -^^^^^^^^^^^^^^^^^^^ +CDML Tags +^^^^^^^^^ .. csv-table:: :header: "Tag", "Description" :widths: 8, 35 @@ -72,8 +72,8 @@ Special Characters XML reserves certain characters for markup. If they appear as content, they must be encoded to avoid confusion with markup: -Table Special Character Encodings -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Special Character Encodings +^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Character", "Encoding" :widths: 8, 15 @@ -211,8 +211,8 @@ into files. The format is: The pathname is appended to the value of the directory attribute, to obtain an absolute pathname. -Axis Element -^^^^^^^^^^^^ +Axis Elements +^^^^^^^^^^^^^ An axis element describes a single coordinate axis. The content can be a blank-separated list of axis values or a linear element. A linear @@ -227,8 +227,8 @@ length). ``linear-element ::=`` ** ** -Table Axis Elements -^^^^^^^^^^^^^^^^^^^ +Axis Element Attributes +^^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Attribute", "Required?", "CF", "GDT", "Notes" @@ -305,8 +305,8 @@ rectilinear in topology, ``grid-element ::=`` **** ``extra-attribute-element*`` **** -Table 6.5 RectGrid Attributes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +RectGrid Attributes +^^^^^^^^^^^^^^^^^^^ .. raw:: html @@ -361,8 +361,8 @@ start=\ **"``Integer``" **\ length=\ **"``Integer``" **\ partition\_length=\ **"``Integer``"**/>\*\* -Table Variable Attributes -^^^^^^^^^^^^^^^^^^^^^^^^^ +Variable Attributes +^^^^^^^^^^^^^^^^^^^ .. csv-table:: diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index cf5968a7..c7ea0283 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -60,8 +60,8 @@ where Output is written to standard output by default. Use the -x option to specify an output filename. -Table CDScan Command Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +CDScan Command Options +^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Option:, "Description" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index e5fef367..d74a905e 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -210,8 +210,8 @@ in CDMS, and ``cuDataset``, corresponding to ``Dataset`` in CDMS. Slab ~~~~ -Table Slab Methods -^^^^^^^^^^^^^^^^^^^^^^ +Slab Methods +^^^^^^^^^^^^ .. csv-table:: @@ -243,8 +243,8 @@ Table Slab Methods cuDataset ~~~~~~~~~ -Table cuDataset Methods -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +cuDataset Methods +^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Type", "Method", "Definition" From f6d99e33655e88d8c82916c523e0a35cf02aed5c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 21 Jun 2018 15:17:08 -0700 Subject: [PATCH 186/239] Change made to Section 4 --- docs/source/manual/cdms_4.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 42afc8c7..05402caa 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -13,7 +13,7 @@ CDMS provides several methods for interpolating gridded data: - from one vertical (lat/level) cross-section to another vertical cross-section. -CDMS Horizontal Regrider +CDMS Horizontal Regridder ^^^^^^^^^^^^^^^^^^^^^^^^ .. highlight:: python :linenothreshold: 3 @@ -308,7 +308,10 @@ CDMS Regridder Constructor :widths: 50, 90 :align: left - "``regridFunction = Regridder(inputGrid, outputGrid)``", "Create a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "``regridFunction = Regridder(inputGrid, outputGrid)``", "Create a regridder function which interpolates a data array from input to output grid. + * `CDMS regridder functions`_ describes the calling sequence of this function. + * ``inputGrid`` and ``outputGrid`` are CDMS grid objects. + **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -407,7 +410,8 @@ CDMS Regridder Function Types :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preserves the area-weighted mean on each horizontal slice. + * If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` @@ -470,7 +474,8 @@ SCRIP Regridder Function Types * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable. - * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. + * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. + * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. * ``gradientLon``: df/dj. Same shape as ``array``. * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array." From ced9db6621b9a8155f6f81222c7c8c76673e72b6 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 25 Jun 2018 10:49:06 -0700 Subject: [PATCH 187/239] fix bindex issue in hgrid --- Lib/hgrid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/hgrid.py b/Lib/hgrid.py index a2d5bc08..f34c4946 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -13,8 +13,8 @@ from .grid import AbstractGrid, LongitudeType, LatitudeType, CoordTypeToLoc from .axis import TransientVirtualAxis from .axis import getAutoBounds, allclose -import _bindex -#from . import _bindex +from cdms2 import bindex +from cdms2 import _bindex from functools import reduce import copy From 8d2c1945343d68ba84ba508606f7c2824968e556 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 25 Jun 2018 11:59:23 -0700 Subject: [PATCH 188/239] Changes to all --- Lib/MV2.py | 8 +-- Lib/avariable.py | 41 +++++++----- Lib/axis.py | 18 +++-- Lib/bindex.py | 2 +- Lib/cache.py | 18 ++--- Lib/cdmsNode.py | 6 +- Lib/cdurlparse.py | 2 +- Lib/coord.py | 16 +++-- Lib/cudsinterface.py | 120 +++++++++++++++++----------------- Lib/database.py | 36 +++++----- Lib/dataset.py | 21 +++--- Lib/forecast.py | 33 +++++----- Lib/fvariable.py | 2 +- Lib/gengrid.py | 24 +++---- Lib/grid.py | 22 +++---- Lib/gsHost.py | 36 +++++----- Lib/gsMosaic.py | 8 +-- Lib/gsStaticVariable.py | 12 ++-- Lib/gsTimeVariable.py | 34 +++++----- Lib/hgrid.py | 30 ++++----- Lib/internattr.py | 2 +- Lib/mvBaseWriter.py | 9 +-- Lib/mvCdmsRegrid.py | 25 +++---- Lib/mvSphereMesh.py | 6 +- Lib/mvVTKSGWriter.py | 11 ++-- Lib/mvVTKUGWriter.py | 9 +-- Lib/mvVsWriter.py | 11 ++-- Lib/tvariable.py | 13 ++-- Lib/variable.py | 13 ++-- docs/source/manual/cdms_2.rst | 22 +++++-- 30 files changed, 323 insertions(+), 287 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 95504879..850ceaa9 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -109,7 +109,7 @@ def __call__(self, a, axis=0, **kwargs): def commonDomain(a, b, omit=None): """commonDomain(a,b) tests that the domains of variables/arrays a and b are equal, - and returns the common domain if equal, or None if not equal. + and returns the common domain if equal, or None if not equal. The domains may differ in that one domain may have leading axes not common to the other; the result domain will contain those axes. @@ -770,7 +770,7 @@ def transpose(a, axes=None): class _minimum_operation: - + "Object to calculate minima" def __init__(self): @@ -891,12 +891,12 @@ def outer(self, a, b): def asarray(data, typecode=None, dtype=None): """asarray(data, typecode=None, dtype=None) is equivalent to array(data, dtype=None, copy=0) - + Returns ------- - data if dtype is None or data is a MaskedArray of the same dtype. + data if dtype is None or data is a MaskedArray of the same dtype. typecode arg is for backward compatibility. """ dtype = _convdtype(dtype, typecode) diff --git a/Lib/avariable.py b/Lib/avariable.py index 58009ef5..38bcf2aa 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -130,14 +130,15 @@ def getNumericCompatibility(): class AbstractVariable(CdmsObj, Slab): """Not to be called by users. - + Parameters ---------- variableNode is the variable tree node, if any. - parent + parent is the containing dataset instance. """ + def info(self, flag=None, device=None): Slab.info(self, flag, device) @@ -170,7 +171,7 @@ def __array__(self, t=None, context=None): # Numeric, ufuncs call this def __call__(self, *args, **kwargs): """ Selection of a subregion using selectors. - + Parameters ---------- raw: @@ -277,9 +278,10 @@ def generateGridkey(self, convention, vardict): Parameters ---------- - convention: + convention: Metadata convention class - vardict: + + vardict: Variable metedata Returns @@ -426,11 +428,11 @@ def getAxis(self, n): Parameters ---------- - n: + n: Axis number _: None - + Returns @@ -488,7 +490,7 @@ def getAxisListIndex(self, axes=None, omit=None, order=None): Other specificiations are as for axisMatchIndex. - Returns + Returns ------- a list of indices of axis objects; """ @@ -551,7 +553,8 @@ def getMissing(self, asarray=0): if asarray == 0 and isinstance(mv, numpy.ndarray): mv = mv[0] - if isinstance(mv, string_types) and self.dtype.char not in ['?', 'c', 'O', 'S']: + if isinstance(mv, string_types) and self.dtype.char not in [ + '?', 'c', 'O', 'S']: try: mv = float(mv) except BaseException: @@ -713,7 +716,7 @@ def getOrder(self, ids=0): id: 0 or 1 - + _: None Returns @@ -870,7 +873,7 @@ def getSlice(self, *specs, **keys): #. an instance of the slice class #. a tuple, which will be used as arguments to create a slice #. `None` or `:`, which means a slice covering that entire dimension - #. Ellipsis (...), which means to fill the slice list with `:` + #. Ellipsis (...), which means to fill the slice list with `:` leaving only enough room at the end for the remaining positional arguments @@ -905,7 +908,7 @@ def expertSlice(self, slicelist): def getRegion(self, *specs, **keys): """ Read a region of data. A region is an n-dimensional rectangular region specified in coordinate space. - + Parameters ---------- @@ -1471,7 +1474,8 @@ def _process_specs(self, specs, keys): nsupplied = len(specs) # numpy will broadcast if we have a new axis in specs # --------------------------------------------------- - if [x for x in specs if numpy.array_equal(x, numpy.newaxis)] == [numpy.newaxis]: + if [x for x in specs if numpy.array_equal(x, numpy.newaxis)] == [ + numpy.newaxis]: nnewaxis = 1 else: nnewaxis = 0 @@ -1693,7 +1697,7 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. - + Parameters ---------- @@ -1765,8 +1769,13 @@ def __getitem__(self, key): raise IndexError("Index too large: %d" % key) speclist = self._process_specs([key], {}) - if [x for x in speclist if (type(x) is numpy.ndarray or type(x) is list)] != []: - index = [x for x in speclist if (type(x) is numpy.ndarray or type(x) is list)] + if [x for x in speclist if (isinstance( + x, numpy.ndarray) or isinstance(x, list))] != []: + index = [ + x for x in speclist if ( + isinstance( + x, numpy.ndarray) or isinstance( + x, list))] return self.data.take(index) # Note: raw=0 ensures that a TransientVariable is returned return self.getSlice(numericSqueeze=1, raw=0, isitem=1, *speclist) diff --git a/Lib/axis.py b/Lib/axis.py index 15a706cb..6ff39330 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -217,16 +217,20 @@ def mapLinearIntersection(xind, yind, iind, yind: same for right endpoint j - + Returns ------- - True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: + True if the coordinate interval (a,b) intersects the node nodeSubI or + cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: * aMinusEps,aPlusEps = a +/- epsilon * bPlusEps,bMinusEps = b +/- epsilon - and the intersection option iind = 'n','b','e','s' specifies whether the intersection is with respect to the node value nodeSubI ('n' or 'e') or the cell bounds [boundLeft,boundRight]. + + and the intersection option iind = 'n','b','e','s' specifies whether the + intersection is with respect to the node value nodeSubI ('n' or 'e') or the cell + bounds [boundLeft,boundRight]. See Also mapLinearExt @@ -280,8 +284,8 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', Returns ------- - The corresponding index interval (i,j), where i is the string user ID, - + is true if the request manager should search the replica catalog for the actual file to transfer. """ if callback is None: @@ -360,11 +360,11 @@ def copyFile(self, fromURL, filekey, lcpath=None, Parameters ---------- - + is the string user ID, - + is true iff the request manager should search the replica catalog for the actual file to transfer. """ @@ -406,11 +406,11 @@ def getFile(self, fromURL, filekey, naptime=5, maxtries=60, Get the file with . If the file is in the cache, read it. - + If another process is transferring it into the cache, wait for the transfer to complete. - + Parameters --------- @@ -429,7 +429,7 @@ def getFile(self, fromURL, filekey, naptime=5, maxtries=60, is the logical collection path, - + is the user string ID, diff --git a/Lib/cdmsNode.py b/Lib/cdmsNode.py index 0fd13e9b..9f2e7bf7 100644 --- a/Lib/cdmsNode.py +++ b/Lib/cdmsNode.py @@ -500,7 +500,8 @@ class VariableNode(CdmsNode): # Create a variable. # If validate is true, validate immediately def __init__(self, id, datatype, domain): - assert isinstance(datatype, string_types), 'Invalid datatype: ' + repr(datatype) + assert isinstance( + datatype, string_types), 'Invalid datatype: ' + repr(datatype) assert datatype in CdDatatypes, 'Invalid datatype: ' + repr(datatype) assert datatype in CdDatatypes, 'Invalid datatype: ' + repr(datatype) CdmsNode.__init__(self, "variable", id) @@ -534,7 +535,8 @@ class AxisNode(CdmsNode): # data is a numpy array, if specified def __init__(self, id, length, datatype=CdLong, data=None): assert isinstance(length, int), 'Invalid length: ' + repr(length) - assert isinstance(datatype, string_types), 'Invalid datatype: ' + repr(datatype) + assert isinstance( + datatype, string_types), 'Invalid datatype: ' + repr(datatype) assert datatype in CdDatatypes, 'Invalid datatype: ' + repr(datatype) if data is not None: assert isinstance( diff --git a/Lib/cdurlparse.py b/Lib/cdurlparse.py index 7ac727ee..c4c04445 100644 --- a/Lib/cdurlparse.py +++ b/Lib/cdurlparse.py @@ -188,7 +188,7 @@ def urldefrag(url): Returns ------- - a tuple of the defragmented URL and the fragment. + a tuple of the defragmented URL and the fragment. If the URL contained no fragments, the second element is the empty string. """ s, n, p, a, q, frag = urlparse(url) diff --git a/Lib/coord.py b/Lib/coord.py index cb5aa229..6df98e7d 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -74,7 +74,7 @@ class AbstractCoordinateAxis(CdmsObj): Returns ------- a copy of self as a transient axis. If copyData is 1, make a separate copy of the data. - + """ axis_count = 0 # Transient axis count @@ -87,7 +87,7 @@ def isAbstractCoordinate(self): def clone(self, copyData=1): """ - + """ raise CDMSError(MethodNotImplemented) @@ -297,7 +297,7 @@ class AbstractAxis2D(AbstractCoordinateAxis): _:None - + Returns ------- a copy of self as a transient axis. @@ -306,6 +306,7 @@ class AbstractAxis2D(AbstractCoordinateAxis): ---- If copyData is 1, make a separate copy of the data. """ + def __init__(self, parent=None, variableNode=None, bounds=None): AbstractCoordinateAxis.__init__( self, parent, variableNode, bounds=bounds) @@ -396,18 +397,19 @@ class TransientAxis2D(AbstractAxis2D, TransientVariable): Create a transient 2D axis. All arguments are as for TransientVariable. - + Parameters ---------- bounds: - is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and - nvert: + is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and + nvert: is the max number of vertices per cell. """ + def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): """ - + """ AbstractAxis2D.__init__(self, None, None, bounds=bounds) TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index 99c02bb7..fdc68339 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -63,7 +63,7 @@ def cleardefault(self): def listall(self, vname=None, all=None): """Get info about data from the file. - + Options vname @@ -71,7 +71,7 @@ def listall(self, vname=None, all=None): all (None/True/False/int) (None) include axes information - + """ if vname is None: vname = self.default_variable_name @@ -107,12 +107,12 @@ def listall(self, vname=None, all=None): def listattribute(self, vname=None): """Get attributes of data from the file. - + Options vname (str/None) (None) variable name - + """ if vname is None: vname = self.default_variable_name @@ -125,15 +125,15 @@ def listdimension(self, vname=None): Returns ------- - a list of the dimension names associated with a variable. + a list of the dimension names associated with a variable. If no argument, return the file.axes.keys() - + Options vname (str/None) (None) variable name - + """ if vname is None: return list(self.axes.keys()) @@ -151,7 +151,7 @@ def listglobal(self): a list of the global attributes in the file. _None_ - + """ return list(self.attributes.keys()) @@ -165,7 +165,7 @@ def listvariable(self): _None_ - + """ return list(self.variables.keys()) @@ -173,12 +173,12 @@ def listvariable(self): def showglobal(self, device=None): """Show the global attributes in the file. - + Options - + device (None/file) (None) output device - + """ if device is None: device = sys.stdout @@ -190,13 +190,13 @@ def showglobal(self, device=None): def showvariable(self, device=None): """Show the variables in the file. - + Options - + device (None/file) (None) output device - + """ if device is None: device = sys.stdout @@ -208,14 +208,14 @@ def showvariable(self, device=None): def showattribute(self, vname=None, device=None): """Show the attributes of vname. - + Options vname (str/None) (None) variable name device (None/file) (None) output device - + """ if device is None: device = sys.stdout @@ -231,15 +231,15 @@ def showattribute(self, vname=None, device=None): def showdimension(self, vname=None, device=None): """Show the dimension names associated with a variable. - + Options - + vname (str/None) (None) variable name device (None/file) (None) output device - + """ if device is None: device = sys.stdout @@ -255,16 +255,16 @@ def showdimension(self, vname=None, device=None): def showall(self, vname=None, all=None, device=None): """Show a full description of the variable. - + Options - + vname (str/None) (None) variable name all (None/True/False/int) (None) include axes information device (None/file) (None) output device - + """ if device is None: device = sys.stdout @@ -276,20 +276,20 @@ def showall(self, vname=None, all=None, device=None): def dimensionobject(self, dname, vname=None): """CDMS axis object for the dimension named dname. - + Options - + vname (str/None) (None) variable name - - Input + + Input dname (str) (0) dimension name - + Output axis (cdms2.axis.FileAxis) (0) file axis whose id is vname - + """ if vname is None: try: @@ -309,16 +309,16 @@ def dimensionobject(self, dname, vname=None): def dimensionarray(self, dname, vname=None): """Values of the dimension named dname. - + Options vname (str/None) (None) variable name - + Input dname (str) (0) dimension name - + Output axisvalues (numpy.ndarray) (0) array with values of axis whose id is vname @@ -327,35 +327,35 @@ def dimensionarray(self, dname, vname=None): def getdimensionunits(self, dname, vname=None): """Get the units for the given dimension. - + Options vname (str/None) (None) variable name - + Input dname (str) (0) dimension name - + Output - units + units (str) (0) units of axis whose id is vname - + """ x = self.dimensionobject(dname, vname) return x.units def getglobal(self, attribute): """Get the value of the global attribute. - + Input attribute (str) (0) global attribute name - + Output attribute_value (str/int/float/numpy.ndarray) (0) value of requested global attribute - + """ try: return self.attributes[attribute] @@ -364,26 +364,26 @@ def getglobal(self, attribute): def getattribute(self, vname, attribute): """Get the value of attribute for variable vname - + Input - vname + vname (str/None) (0) variable name attribute (str) (1) attribute name - + Output attribute_value (str/int/float/numpy.ndarray) (0) value of requested attribute - + """ v = self._v(vname) return getattr(v, attribute) def getslab(self, vname, *args, **keys): """ - - + + getslab ('name', arg1, arg2, ....) returns a cdms variable containing the data. @@ -394,13 +394,13 @@ def getslab(self, vname, *args, **keys): (3) a pair of successive arguments giving an interval in world coordinates. (4) a cdms-style tuple of world coordinates e.g. (start, stop, 'cc') - + Options - + args (*tuple/*cdms2.selectors.Selector) () tuple of type (val1,val2,'cob') for any given dimension or cdms selector - + Keys squeeze (int/True/False) (0) squeezes (removes) dimensions of length 1 @@ -414,15 +414,15 @@ def getslab(self, vname, *args, **keys): grid (cdms2.grid.AbstractGrid) (None) regrid the result to the grid passed - + Input vname (str/None) (0) variable name - + Output variable (cdms2.tvariable.TransientVariable) (0) variable requested - + """ nargs = len(args) v = self._v(vname) @@ -469,13 +469,15 @@ def getslab(self, vname, *args, **keys): def readScripGrid(self, whichGrid="destination", checkGrid=1): """Read a SCRIP curvilinear or generic grid from the dataset. - - The dataset can be a SCRIP grid file or mapping file. If a mapping file, 'whichGrid' chooses the grid to read, either "source" or "destination". - - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. + + The dataset can be a SCRIP grid file or mapping file. If a mapping file, 'whichGrid' + chooses the grid to read, either "source" or "destination". + + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' + if necessary. Returns the grid object. - + Options whichGrid @@ -483,10 +485,10 @@ def readScripGrid(self, whichGrid="destination", checkGrid=1): checkGrid (int) (1) if 1 the grid cells are checked for convexity - + Output grid (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested - + """ from . import hgrid, gengrid diff --git a/Lib/database.py b/Lib/database.py index 0cba0284..91531a44 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -39,13 +39,13 @@ def connect(uri=None, user="", password=""): """ - + Method: connect(uri=None, user="", password="") Description: Open a CDMS database connection. Arguments - + uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. user: user id password: password @@ -201,11 +201,11 @@ def __init__(self, uri, db): def close(self): """ Method - + close() Description - + Close a database connection. @@ -282,15 +282,15 @@ def getObjFromDataset(self, dn): def openDataset(self, dsetid, mode='r'): """ Method - + openDataset(dsetid, mode='r') Description - + Open a dataset. Arguments - + dsetid: string dataset identifier mode: open mode ('r' - read-only, 'r+' - read-write, 'w' - create) @@ -334,21 +334,21 @@ def searchFilter(self, filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None): """ Method - + searchFilter (filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) Description - + Search a CDMS database. Arguments - - + filter: string search filter Simple filters have the form "tag = value". Simple filters can be combined using logical operators '&', '|', '!' in prefix notation. For example, the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. More formally - + filter = "(" filtercomp ")" filtercomp = "&" filterlist | # and @@ -386,11 +386,11 @@ def searchFilter(self, filter=None, tag=None, relbase=None, ------- SearchResult instance. - Entries can be accessed sequentially. + Entries can be accessed sequentially. For each entry, - entry.name is the name of the entry, + entry.name is the name of the entry, entry.attributes is a dictionary of the attributes returned by the search, @@ -401,7 +401,7 @@ def searchFilter(self, filter=None, tag=None, relbase=None, Entries can be refined with searchPredicate(). Example - ------- + ------- (1) Find all variables named "cli": result = db.searchFilter(filter="id=cli",tag="variable") @@ -465,7 +465,7 @@ def searchPredicate(self, predicate, tag=None): class LDAPSearchResult(AbstractSearchResult): - + def __init__(self, db, LDAPresult): self.db = db self.result = LDAPresult @@ -489,15 +489,15 @@ def __getitem__(self, key): def searchPredicate(self, predicate, tag=None): """ Method - + searchPredicate(predicate, tag=None) Description - + Refine a search result, with a predicate search. Arguments - + predicate: Function name or lambda function. The function takes a single CDMS object, and returns true (1) if the object satisfies the predicate, 0 if not. tag: Restrict the search to objects in one class. diff --git a/Lib/dataset.py b/Lib/dataset.py index e338b9d0..bb9ecabd 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -5,17 +5,16 @@ from __future__ import print_function from .error import CDMSError import sys -#from . import Cdunif +# from . import Cdunif import Cdunif import numpy -#from . import cdmsNode +# from . import cdmsNode import cdmsNode import os -import sys import string import urllib from urllib.parse import urlparse, urlunparse -#from . import cdmsobj +# from . import cdmsobj import cdmsobj import re from .CDMLParser import CDMLParser @@ -1197,7 +1196,7 @@ def openFile(self, filename, mode): def getLogicalCollectionDN(self, base=None): """Return the logical collection distinguished name of this dataset. - + Note ---- @@ -1233,7 +1232,7 @@ def getVariables(self, spatial=0): return retval def getAxis(self, id): - """Get the axis object with the given id. + """Get the axis object with the given id. Returns ------- @@ -1750,7 +1749,7 @@ def copyGrid(self, grid, newname=None): new name for grid (default None) grid: - file grid + file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) Returns @@ -2021,11 +2020,13 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds String identifier of the new variable. extend: * 1 define the first dimension as the unlimited dimension. - * 0 do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. + * 0 do not define an unlimited dimension. The default is the define the first + dimension as unlimited only if it is a time dimension. fill_value: The missing value flag. index: - The extended dimension index for writting. The default index is determined by lookup relative to the existing extended dimension. + The extended dimension index for writting. The default index is determined by + lookup relative to the existing extended dimension. grid: The variable grid. `none` the value of var.getGrid() will used. @@ -2359,7 +2360,7 @@ def getVariable(self, id): ---------- id: str id of the variable to get - + _: None Returns diff --git a/Lib/forecast.py b/Lib/forecast.py index 05b076bd..2633da45 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -4,7 +4,6 @@ """CDMS Forecast""" - from __future__ import print_function import numpy import cdtime @@ -19,7 +18,7 @@ def two_times_from_one(t): Parameters ---------- - Input + Input is a time representation, either as the long int used in the cdscan script, or a string in the format "2010-08-25 15:26:00", or as a cdtime comptime (component time) object. @@ -78,15 +77,15 @@ class forecast(): Parameters ---------- - tau0time + tau0time is the first time of the forecast, i.e. the time at which tau=0. - dataset_list + dataset_list is used to get the forecast file from the forecast time. - + Example ------- - + Each list item should look like this example: [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] Normally dataset_list = fm[i][1] where fm is the output of @@ -101,7 +100,7 @@ class forecast(): def __init__(self, tau0time, dataset_list, path="."): """ - + """ self.fctl, self.fct = two_times_from_one(tau0time) @@ -135,7 +134,7 @@ def available_forecasts(dataset_file, path="."): Returns ------- a list of forecasts (as their generating times) which are available through the specified cdscan-generated dataset xml file. - + Note ---- The forecasts are given in 64-bit integer format, but can be converted @@ -197,7 +196,7 @@ class forecasts(): def __init__(self, dataset_file, forecast_times, path="."): """ - + """ # Create dataset_list to get a forecast file from each forecast time. @@ -255,7 +254,7 @@ def reduce_inplace(self, min_time, max_time, openclosed='co'): """ Example ------- - + For a forecasts object f, f( min_time, max_time ) will reduce the scope of f, to forecasts whose start time t has min_time<=t Date: Mon, 25 Jun 2018 15:12:25 -0700 Subject: [PATCH 189/239] Corrections made to API Lib --- Lib/MV2.py | 11 ++++++++--- Lib/cache.py | 9 ++++++--- Lib/database.py | 4 +++- Lib/forecast.py | 3 ++- Lib/grid.py | 3 ++- Lib/hgrid.py | 11 ++++++++--- Lib/selectors.py | 5 ++++- Lib/slabinterface.py | 5 +++-- Lib/tvariable.py | 19 ++++++++++++++----- Lib/variable.py | 10 +++++++--- 10 files changed, 57 insertions(+), 23 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 850ceaa9..ee69b74d 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -185,9 +185,11 @@ def commonGrid(a, b, axes): and consistent with the list of axes. If so, the common grid is returned, else None is returned. a and b can be numpy arrays, in which case the result is None. - The common grid is 'consistent' with axes if the grid axes (e.g., the axes of latitude and longitude coordinate variables) are members of the list 'axes'. + The common grid is 'consistent' with axes if the grid axes (e.g., the axes of + latitude and longitude coordinate variables) are members of the list 'axes'. - If the grid(s) of a, b are rectilinear, the result is None, as the grids are implicitly defined by the axes. + If the grid(s) of a, b are rectilinear, the result is None, as the grids + are implicitly defined by the axes. """ if isinstance(b, AbstractVariable): gb = b.getGrid() @@ -561,7 +563,10 @@ def choose(myindices, t): Returns ------- - an array shaped like indices containing elements chosen from t. If an element of t is the special element masked, any element of the result that "chooses" that element is masked. The result has only the default axes. + an array shaped like indices containing elements chosen from t. + If an element of t is the special element masked, any element of + the result that "chooses" that element is masked. The result has + only the default axes. """ maresult = numpy.ma.choose(myindices, list(map(_makeMaskedArg, t))) F = getattr(t, "fill_value", 1.e20) diff --git a/Lib/cache.py b/Lib/cache.py index 0e837879..33253236 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -35,7 +35,8 @@ def lock(filename): Note: This function is UNIX-specific. - Note: It is important to delete the lock via unlock() if the process is interrupted, otherwise subsequent locks will fail. + Note: It is important to delete the lock via unlock() if the process is + interrupted, otherwise subsequent locks will fail. """ path = lockpath(filename) @@ -177,7 +178,8 @@ def copyFile(fromURL, toURL, callback=None, """ Copy file to local file . - For FTP transfers, if cache._useWindow is true, display a progress dialog, otherwise just print progress messages. + For FTP transfers, if cache._useWindow is true, display a progress dialog, + otherwise just print progress messages. For request manager transfers, is the logical collection distinguished name, @@ -188,7 +190,8 @@ def copyFile(fromURL, toURL, callback=None, is the string user ID, - is true if the request manager should search the replica catalog for the actual file to transfer. + is true if the request manager should search the replica catalog for the actual + file to transfer. """ if callback is None: if _useWindow: diff --git a/Lib/database.py b/Lib/database.py index 91531a44..05fadac5 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -345,7 +345,9 @@ def searchFilter(self, filter=None, tag=None, relbase=None, Arguments - filter: string search filter - Simple filters have the form "tag = value". Simple filters can be combined using logical operators '&', '|', '!' in prefix notation. For example, the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. + Simple filters have the form "tag = value". Simple filters can be combined + using logical operators '&', '|', '!' in prefix notation. For example, + the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. More formally diff --git a/Lib/forecast.py b/Lib/forecast.py index 2633da45..0653b64f 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -133,7 +133,8 @@ def available_forecasts(dataset_file, path="."): Returns ------- - a list of forecasts (as their generating times) which are available through the specified cdscan-generated dataset xml file. + a list of forecasts (as their generating times) which are available + through the specified cdscan-generated dataset xml file. Note ---- diff --git a/Lib/grid.py b/Lib/grid.py index 1aad2227..194d869a 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -731,7 +731,8 @@ def flatAxes(self): """ Returns ------- - (flatlat, flatlon) where flatlat is a 1D NumPy array having the same length as the number of cells in the grid, similarly for flatlon.""" + (flatlat, flatlon) where flatlat is a 1D NumPy array having the same + length as the number of cells in the grid, similarly for flatlon.""" if self._flataxes_ is None: alat = self.getLatitude()[:] diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 062fd236..0ab0031e 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -164,18 +164,23 @@ def checkConvex(self): def fixCutCells(self, nonConvexCells, threshold=270.0): """ - For any mapping from a spherical to a planar surface, there is a linear cut. Grid cells that span the cut may appear to be nonconvex, which causes problems with meshfill graphics. This routine attempts to 'repair' the cut cell boundaries so that meshfill recognizes they are convex. + For any mapping from a spherical to a planar surface, there is a linear cut. + Grid cells that span the cut may appear to be nonconvex, which causes problems + with meshfill graphics. This routine attempts to 'repair' the cut cell boundaries + so that meshfill recognizes they are convex. Parameters ---------- nonConvexCells: - 1D numpy array of indices of nonconvex cells, as returned from checkConvex. + 1D numpy array of indices of nonconvex cells, as returned from + checkConvex. threshold: positive floating-point value in degrees. - If the difference in longitude values of consecutive boundaries nodes exceeds the threshold, the cell is considered a cut cell. + If the difference in longitude values of consecutive boundaries nodes exceeds the + threshold, the cell is considered a cut cell. On return, the grid boundaries are modified. Return value is a 1D array of indices of cells that cannot be repaired. diff --git a/Lib/selectors.py b/Lib/selectors.py index 947a4e37..35daab8d 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -18,7 +18,10 @@ def __init__(self, args): class Selector: """Selector class - Positional args are SelectorComponents or Selectors Keyword args and their value are passed to kwselect to create selectors. All the selector components are put into the components list of this Selector, along with all the componentsof any Selector arguments. + Positional args are SelectorComponents or Selectors Keyword args and + their value are passed to kwselect to create selectors. All the selector + components are put into the components list of this Selector, along with + all the componentsof any Selector arguments. """ diff --git a/Lib/slabinterface.py b/Lib/slabinterface.py index b978523f..c2a4cf4d 100644 --- a/Lib/slabinterface.py +++ b/Lib/slabinterface.py @@ -21,8 +21,9 @@ class Slab: _:None Note: This is an abstract class to inherit in AbstractVariable About axes: - weight and bounds attributes always set but may be None if bounds are None, getdimattribute returns result of querying the axis. - """ + weight and bounds attributes always set but may be None if bounds + are None, getdimattribute returns result of querying the axis. """ + std_slab_atts = ['filename', 'missing_value', 'comments', diff --git a/Lib/tvariable.py b/Lib/tvariable.py index 28b07cd9..3a279475 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -160,7 +160,9 @@ def __init__(self, data, typecode=None, copy=1, savespace=0, ---------- createVariable - (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order='C') The savespace argument is ignored, for backward compatibility only. + (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, + axes=None, attributes=None, id=None, dtype=None, order='C') The savespace argument is ignored, + for backward compatibility only. """ try: if data.fill_value is not None: @@ -267,7 +269,9 @@ def __new__(cls, data, typecode=None, copy=0, savespace=0, ---------- createVariable - (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order='C') The savespace argument is ignored, for backward compatibility only. + (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, + grid=None, axes=None, attributes=None, id=None, dtype=None, order='C') The savespace + argument is ignored, for backward compatibility only. """ # Compatibility: assuming old typecode, map to new if dtype is None and typecode is not None: @@ -797,7 +801,8 @@ def getHaloEllipsis(self, side): ---------- side: - a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east side, etc. This does not involve any communication. + a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), + (-1, 0) to access the south side, (0, 1) the east side, etc. This does not involve any communication. _:None @@ -812,7 +817,10 @@ def getHaloEllipsis(self, side): def fetchHaloData(self, pe, side): """ - Fetch the halo data from another processor. The halo side is a subdomain of the halo that is exposed to other processors. It is an error to call this method when MPI is not enabled. This is a collective method (must be called by all processes), which involves synchronization of data among all processors. + Fetch the halo data from another processor. The halo side is a subdomain of the halo that + is exposed to other processors. It is an error to call this method when MPI is not enabled. + This is a collective method (must be called by all processes), which involves synchronization + of data among all processors. Parameters ---------- @@ -821,7 +829,8 @@ def fetchHaloData(self, pe, side): processor owning the halo data. This is a no operation when pe is None. side: - a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east side, etc. + a tuple of zeros and one +1 or -1. To access the "north" side for instance, + set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east side, etc. Note: collective, all procs must invoke this method. If some processors should not fetch then pass None for pe. """ diff --git a/Lib/variable.py b/Lib/variable.py index cf243ed3..17090e40 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -236,7 +236,8 @@ def genMatch(self, axis, interval, matchnames): is an index interval (istart, iend). matchnames - is a partially filled list [id, timestart, timeend, levstart, levend, fc] If a filemap is used, matchnames has indices, otherwise has coordinates. + is a partially filled list [id, timestart, timeend, levstart, levend, fc] If a filemap + is used, matchnames has indices, otherwise has coordinates. Function modifies matchnames based on axis and interval, returns the modified matchnames tuple. @@ -294,7 +295,9 @@ def getPartition(self, axis): Parameters ---------- axis: - is either a time or level axis. If cdms_filemap is being used, get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. + is either a time or level axis. If cdms_filemap is being used, get the + partition from the _varpart_ attribute, otherwise (for templating) use + axis.partition. _: None @@ -334,7 +337,8 @@ def expertPaths(self, slist): is a tuple of length npart, having the dimension numbers of the partitioned dimensions; partitionSlices - is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. + is the list of file-specific (filename, slice) corresponding to the paths and slices + within the files to be read. The exact form of partitionSlices depends on the value of npart: From 89b22f9132ff74c70f4ef11c35fbc2e36192bcb6 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 25 Jun 2018 15:56:39 -0700 Subject: [PATCH 190/239] Changes to API --- regrid2/Lib/gsRegrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 738a264d..685f7a5f 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -652,7 +652,7 @@ def setMask(self, inDataOrMask): _: None Note: this definition is compatible with the numpy masked arrays - + Note: note see setValidMask for the opposite definition Note: should be called before computing the weights From 0827d3b8638f1ae95e9ac2e94719f3e7e05c7480 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 25 Jun 2018 17:28:02 -0700 Subject: [PATCH 191/239] fix ascii art --- regrid2/Lib/esmf.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 39b8044f..23d0f489 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -91,9 +91,8 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- -.. figure:: /images/ESMF.jpg - :scale: 55% - :alt: +:: + 3 4-------------3 /\ | | / \ | | @@ -105,10 +104,6 @@ def setCells(self, cellIndices, cellTypes, connectivity, - - - - 3 8---------------7 /|\ /| /| / | \ / | / | From f2b2e65ccdf531facf140bed0507728de016e49f Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 26 Jun 2018 15:26:15 -0700 Subject: [PATCH 192/239] Changes to Sections 2, 4 and 5 --- docs/source/manual/cdms_2.rst | 1 + docs/source/manual/cdms_4.rst | 20 +- docs/source/manual/cdms_5.rst | 48 +- regrid2/Lib/Lib/PET0.ESMF_LogFile | 1 - regrid2/Lib/Lib/__init__.py | 36 - regrid2/Lib/Lib/crossSection.py | 1092 ------------------------ regrid2/Lib/Lib/crossSection.py.orig | 1095 ------------------------ regrid2/Lib/Lib/error.py | 3 - regrid2/Lib/Lib/esmf.py | 842 ------------------ regrid2/Lib/Lib/gsRegrid.py | 1179 -------------------------- regrid2/Lib/Lib/gs_horizontal.py | 214 ----- regrid2/Lib/Lib/horizontal.py | 422 --------- regrid2/Lib/Lib/mvESMFRegrid.py | 483 ----------- regrid2/Lib/Lib/mvGenericRegrid.py | 313 ------- regrid2/Lib/Lib/mvLibCFRegrid.py | 101 --- regrid2/Lib/Lib/mytest.py | 2 - regrid2/Lib/Lib/pressure.py | 490 ----------- regrid2/Lib/Lib/scrip.py | 447 ---------- regrid2/Lib/crossSection.py | 2 +- regrid2/Lib/esmf.py | 2 + regrid2/Lib/gsRegrid.py | 8 +- regrid2/Lib/horizontal.py | 4 +- regrid2/Lib/mvESMFRegrid.py | 6 +- regrid2/Lib/mvGenericRegrid.py | 6 +- regrid2/Lib/mvLibCFRegrid.py | 6 +- regrid2/Lib/pressure.py | 2 +- regrid2/Lib/scrip.py | 4 +- 27 files changed, 68 insertions(+), 6761 deletions(-) delete mode 100644 regrid2/Lib/Lib/PET0.ESMF_LogFile delete mode 100644 regrid2/Lib/Lib/__init__.py delete mode 100644 regrid2/Lib/Lib/crossSection.py delete mode 100644 regrid2/Lib/Lib/crossSection.py.orig delete mode 100644 regrid2/Lib/Lib/error.py delete mode 100644 regrid2/Lib/Lib/esmf.py delete mode 100644 regrid2/Lib/Lib/gsRegrid.py delete mode 100644 regrid2/Lib/Lib/gs_horizontal.py delete mode 100644 regrid2/Lib/Lib/horizontal.py delete mode 100644 regrid2/Lib/Lib/mvESMFRegrid.py delete mode 100644 regrid2/Lib/Lib/mvGenericRegrid.py delete mode 100644 regrid2/Lib/Lib/mvLibCFRegrid.py delete mode 100644 regrid2/Lib/Lib/mytest.py delete mode 100644 regrid2/Lib/Lib/pressure.py delete mode 100644 regrid2/Lib/Lib/scrip.py diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index c1f5c93b..71f3731b 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -6,6 +6,7 @@ Overview ^^^^^^^^ + .. highlight:: python :linenothreshold: 3 diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 05402caa..b045f288 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -411,12 +411,17 @@ CDMS Regridder Function Types :align: left "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preserves the area-weighted mean on each horizontal slice. - * If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + * If array is a Variable, a TransientVariable of the same rank as the input array is returned, otherwise a masked array is returned. * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` - * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. - * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. + * A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. + * A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. + * A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). * ``dataArray`` is the result data array. * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." @@ -479,11 +484,14 @@ SCRIP Regridder Function Types * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. * ``gradientLon``: df/dj. Same shape as ``array``. * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array." - "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid." - "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid." + "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. + * The array is 1-D, with length equal to the number of cells in the output grid." + "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. + * The array is 1-D, with length equal to the number of cells in the output grid." "CurveGrid or Generic-Grid", "``getInputGrid()``", "Return the input grid, or None if no input grid is associated with the regridder." "CurveGrid or Generic-Grid", "``getOutputGrid()``", "Return the output grid." - "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid" + "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. + * The array is 1-D, with length equal to the number of cells in the input grid" Examples ^^^^^^^^ diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 1a9cae90..1c6db95a 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -147,18 +147,23 @@ where: - array is a variable, masked array, or Numpy array having between two and five dimensions. The last dimensions of the array is termed the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't', - and 'w'. For example, if array is three-dimensional, the axes are - (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). - (Note that the t dimension need have no connection with time; any - spatial axis can be mapped to any plot dimension. For a graphics - method which is two-dimensional, such as boxfill, the y-axis is - plotted on the horizontal, and the x-axis on the vertical. + and 'w'. + + - For example, if array is three-dimensional, the axes are + (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). + + - (Note that the t dimension need have no connection with time; any + spatial axis can be mapped to any plot dimension.) - If array is a gridded variable on a rectangular grid, the plot - function uses a box-fill graphics method. If it is non-rectangular, - the meshfill graphics method is used. + - For a graphics method which is two-dimensional, such as boxfill, + the y-axis is plotted on the horizontal, and the x-axis on the vertical. - Note that some plot keywords apply only to rectangular grids only. + - If array is a gridded variable on a rectangular grid, the plot + function uses a box-fill graphics method. + + - If it is non-rectangular, the meshfill graphics method is used. + + - Note that some plot keywords apply only to rectangular grids only. - args are optional positional arguments: @@ -201,16 +206,27 @@ Plot Keywords ``cdtime.reltime(30.0, 'days since 1978-1-1').``" "``units``", "string", "Data units. Defaults to ``variable.units``" "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." - "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" - "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. + "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. + * Array of coordinate values, having the same length as the corresponding dimension. + * Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. + * Axis object. * ``xaxis`` defaults to ``grid.getAxis(0)`` * ``yaxis`` defaults to ``grid.getAxis(1)``" - "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." - "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" - "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions: + "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. + * Boundary array of shape ``(n,2)`` where ``n`` is the axis length. + * Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` + * if ``None``, similarly for ``ybounds``." + "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. + * Axis name. + * Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. + * Defaults to 0, with the following exceptions: * If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1 * If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." - "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." + "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. + * Axis units. + * Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." diff --git a/regrid2/Lib/Lib/PET0.ESMF_LogFile b/regrid2/Lib/Lib/PET0.ESMF_LogFile deleted file mode 100644 index 3494c8e2..00000000 --- a/regrid2/Lib/Lib/PET0.ESMF_LogFile +++ /dev/null @@ -1 +0,0 @@ -20170308 152041.534 INFO PET0 Running with ESMF Version 7.0.0 diff --git a/regrid2/Lib/Lib/__init__.py b/regrid2/Lib/Lib/__init__.py deleted file mode 100644 index 36b7f9e2..00000000 --- a/regrid2/Lib/Lib/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Interface to regridding facilities -""" - -__all__ = ["horizontal", "pressure", "crossSection", "scrip", - "error", "mvGenericRegrid", ] - -from .error import RegridError # noqa -from .horizontal import Horizontal, Regridder # noqa -from .pressure import PressureRegridder # noqa -from .crossSection import CrossSectionRegridder # noqa -from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa -from .scrip import DistwgtRegridder, readRegridder # noqa -from regrid2 import gsRegrid # noqa -from .mvGenericRegrid import GenericRegrid # noqa -from .mvLibCFRegrid import LibCFRegrid # noqa -try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - from .mvESMFRegrid import ESMFRegrid # noqa -except BaseException: - pass - -from . import git # noqa - -ESMF_HAS_BEEN_INITIALIZED = False -if not ESMF_HAS_BEEN_INITIALIZED: - try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - ESMF.Manager(debug=False) - # this turns off the PET file logs - ESMF_HAS_BEEN_INITIALIZED = True - except BaseException: - pass diff --git a/regrid2/Lib/Lib/crossSection.py b/regrid2/Lib/Lib/crossSection.py deleted file mode 100644 index cf23b45d..00000000 --- a/regrid2/Lib/Lib/crossSection.py +++ /dev/null @@ -1,1092 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError - - -class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, - latTypeOut=None, latSizeOut=None): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, - # latTypeOut = None, latSizeOut = None): - # - # PROCEDURE: - # - # The user must assemble at least the following four pieces of information: - # - # latIn - the axis specifying the latitude grid for the input data - # - # latOut - the axis specifying the latitude grid for the output data - # - # levIn - the axis specifying the pressure grid for the input data - # - # levOut - the axis specifying the pressure grid for the output data - # - # - # Additional information is required if a latitude grid is not global. It may be generic. - # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice - # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the - # computation requires the size of the global grid from which the subset was choosen. Consequently, - # the user must assemble: - # - # latTypeIn -- for input latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region - # - # latTypeOut -- for output latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region - # - # USAGE: - # - # To make an instance preparing for a global to global regrid, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) - # - # To make an instance preparing for a global to a regional grid which, for example, is a subset of - # a global gaussian grid of size 64, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) - # - # where the latOut axis must have been selected from the global 64 length gaussian grid - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.latOut = latOut - self.levIn = levIn - self.levOut = levOut - self.nlevi = len(levIn) - self.nlevo = len(levOut) - - latIn, self.nlati = checkdimension(latIn, 'input latitude') - latOut, self.nlato = checkdimension(latOut, 'output latitude') - - # --- check for a single grid point in the latitude-level plane - - if self.nlevo == 1 and self.nlato != 1: - sendmsg( - 'Error in output grid - a single level value requires a single latitude value') - raise ValueError - if self.nlevo != 1 and self.nlato == 1: - sendmsg( - 'Error in output grid - a single latitude value requires a single longitude value') - raise ValueError - if self.nlevo == 1 and self.nlato == 1: - calculateMean = 1 - msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' - sendmsg(msg) - else: - calculateMean = 0 - - # --- get the latitude coordinate grid boundaries for the input grid - - if latTypeIn is None: # global latIn - lat_wts_bndsIn = get_latitude_wts_bnds(latIn) - else: - lat_wts_bndsIn = get_region_latitude_wts_bnds( - latIn, latTypeIn, latSizeIn) - - lat_bndsIn = lat_wts_bndsIn[1] - bnin, bsin = latitude_bounds(lat_bndsIn) - - if calculateMean == 0: # meaningful grid - - # --- get the latitude coordinate grid boundaries for the output grid - - if latTypeOut is None: # global latOut - lat_wts_bndsOut = get_latitude_wts_bnds(latOut) - else: - lat_wts_bndsOut = get_region_latitude_wts_bnds( - latOut, latTypeOut, latSizeOut) - - lat_bndsOut = lat_wts_bndsOut[1] - bnout, bsout = latitude_bounds(lat_bndsOut) - - else: - bnout = numpy.array([90.0], numpy.float32) - bsout = numpy.array([-90.0], numpy.float32) - - # --- call maplength to get the rest of the self data needed by rgrdlength - - t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) - - self.latdx, self.latpt, self.wtlat = t - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the regridder function. - ar is the input array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = "zy" - else: - order = "tzy" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = str.lower(order) - - # Map order to positionIn - positionIn = [None] * 3 - for i in range(len(order)): - if order[i] == 'y': - positionIn[0] = i - if inputIsVariable: - axislist[i] = self.latOut - elif order[i] == 'z': - positionIn[1] = i - if inputIsVariable: - axislist[i] = self.levOut - else: - positionIn[2] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - # Mask fill_value and return results - if inputIsVariable == 1: - result = numpy.ma.masked_values(outar, missing) - result = cdms2.createVariable(result, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - result = numpy.ma.masked_values(result, missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', - positionIn=None, maskIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in - # the latitude-level plane. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, - # missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed - # in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence latitude, - # level and time. Latitude and level are required. If time is missing submit None in its - # slot in the tuple. Notice that the length of the tuple is - # always three. - # - # Explicitly, in terms of the shape of dataIn as returned by python's shape function - # - # positionIn[0] contains the position of latitude in dataIn - # positionIn[1] contains the position of level in dataIn or None - # positionIn[2] contains the position of time in dataIn or None - # - # As examples: - # If the c order shape of 3D data is - # (number of times, number of levels, number of latitudes) - # submit - # (2, 1, 0). - # - # If the c order shape of 2D data is - # (number of times, number of latitudes) - # submit - # (1, None, 0). - # - # Send in None if the shape is a subset of (time, level, latitude) which is evaluated - # as follows: - # 2D -- code assumes (1,0,None) - # 3D -- code assumes (2,1,0) - # - # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This - # mask only works on the latitude grid. It is not possible to mask out a region in the level - # plane. The 0.0 value removes the data from correponding grid point. The user can supply the - # following choices: - # - # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing - # data in the input data array, dataIn - # - # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, - # dataIn. This user supplied mask might be used to mask a latitude region. It is not - # required to account for missing data in the input data. The code uses missingValueIn - # and missingMatch to supply the 0.0s for grid points with missing data in the input - # data array, dataIn. - # - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # WARNING: This code does not regrid cross sections which have a single dummy longitude value! - # - # - #-----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # try to identify a single dummy longitude - - dataShape = dataIn.shape - - if len(dataShape) > 3: - msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is not None: - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # set missing value to be used in dataOut - - if missingValueOut is None: - if missingValueIn is not None: - # default - omit = missingValueIn - else: - # default - omit = 1.0e20 - else: - # user choice - omit = missingValueOut - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - # produce the input for rgdlength not generated by maplength - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is None: # construct the default positionIn tuple - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - if numberDim == 2: # fill end of list with a None - positionList.append(None) - - positionIn = tuple(positionList) - - if len(positionIn) != 3: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' - sendmsg(msg) - raise TypeError - - # set ilon, ilat in Fortran order except that the first index is 0 - - # not 1 - ilat = numberDim - 1 - positionIn[0] - - itim1 = itim2 = -1 - ntim1 = ntim2 = 0 - - if numberDim == 2: # lat and level field - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - - if numberDim == 3: # lon_lat field + level + time - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - itim2 = numberDim - 1 - positionIn[2] - ntim2 = dataShape[positionIn[2]] - - # check for consistency between the grid axiss and the dataIn shape - - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # allocate memory for aout -- the array with original number of levels - # but the new number of latitudes - - aoutList = list(dataIn.shape) - aoutList[positionIn[0]] = self.nlato - # memory for aout - aout = numpy.zeros(tuple(aoutList), numpy.float32) - - # generate the mask - - amskin = sectionmask( - dataIn, - positionIn, - maskIn, - missingValueIn, - missingMatch) - - # ------------- call rgdlength to regrid latitude --------------- - - _regrid.rgdlength( - ilat, - itim1, - itim2, - ntim1, - ntim2, - self.nlati, - self.nlato, - omit, - self.latdx, - self.latpt, - self.wtlat, - amskin, - dataIn, - aout) - - # ------------- call rgdpressure to regrid pressure ------------- - - # allocate memory for ap -- the array with new number of levels and the - # new number of latitudes - - apList = list(dataIn.shape) - apList[positionIn[0]] = self.nlato - apList[positionIn[1]] = self.nlevo - # memory for ap - ap = numpy.zeros(tuple(apList), numpy.float32) - - nlon = 0 - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.levIn[:].astype(numpy.float64) - levOut = self.levOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlato, - nlon, - ntim2, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - aout, - ap) - - if missingMatch == 'none': # if no missing do not pass None - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - return ap - - -def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" - - data = x[:] - try: - xsize = len(x) - except TypeError: - sendmsg('Hgrid instance error -- instance requires a ' + name) - raise TypeError - - if data.dtype.char != 'f': - x[:] = x[:].astype(numpy.float32) - - # ----- check for consistency ----- - - if x[0] > x[xsize - 1]: - for n in range(1, xsize): - if x[n] > x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - else: - for n in range(1, xsize): - if x[n] < x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - - return x, xsize - - -def generic_wts_bnds(lat): - try: - bnds = lat.getBounds() - if bnds is None: # No bounds defined - newLat = lat.clone() - newLat.setBounds(None) - bnds = lat.getBounds() - except BaseException: # just an array.... - newLat = cdms2.createAxis(lat) - newLat.setBounds(None) - bnds = newLat.getBounds() - outBnds = bnds[:, 0].tolist() - outBnds.append(bnds[-1][-1]) - outBnds = numpy.array(outBnds) - wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] - wts = numpy.array(wts) / numpy.sum(wts) - return wts, outBnds - - -def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - small = 0.001 # use as tolerance in checking values - - nlat = len(checklatpass) - - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if checklatpass[0] < checklatpass[nlat - - 1]: # need a copy? - checklat = numpy.array(checklatpass, numpy.float64) - checklat = checklat[::-1] - reverse_latitude = 'yes' - else: - checklat = checklatpass - - # ------ check the pass for evenly spaced latitudes ------- - - firstdelta = abs(checklat[0] - checklat[1]) - maxdiff = 0.0 - for i in range(1, nlat - 1): - diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) - if diff > maxdiff: - maxdiff = diff - - if maxdiff < small: - # if abs(90. - checklat[0]) > small or abs(-90. - - # checklat[nlat - 1]) > small: - # grid_type = 'even' # evenly spaced without poles - # wts, bnds = generic_wts_bnds(checklat) - # if reverse_latitude == 'yes': - # wts = wts[::-1] - # bnds = bnds[::-1] - # return (wts, bnds) - # else: - grid_type = 'uniform' # evenly spaced with poles - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for gaussian latitudes ------- - - grid_type = 'gaussian' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for equalarea latitudes ------- - - grid_type = 'equalarea' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ must be generic latitude ------- - wts, bnds = generic_wts_bnds(checklatpass) - return (wts, bnds) - - -def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" - - latbnds = lat_bnds.astype(numpy.float32) - - if latbnds[0] > latbnds[len(latbnds) - 1]: - bn = latbnds[:-1] - bs = latbnds[1:] - else: - bn = latbnds[1:] - bs = latbnds[:-1] - - return (bn, bs) - - -def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - - latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] - - if latType not in latTypeList: - sendmsg( - "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", - latType) - raise ValueError - return - - if latSize is None: - sendmsg('Error in latSize -- it must be a number') - raise ValueError - return - - nlat = len(latRegionpass) - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if latRegionpass[0] < latRegionpass[nlat - - 1]: # need a copy? - latRegion = numpy.array(latRegionpass, numpy.float64) - latRegion = latRegion[::-1] - reverse_latitude = 'yes' - else: - latRegion = latRegionpass - - small = 0.001 # use as tolerance in checking values - - # ------ check the pass for gaussian latitudes ------- - - if latType != 'generic': - # n to s global pts, wts and bnds - pts_wts_bnds = _regrid.gridattr(latSize, latType) - latvals = pts_wts_bnds[0] - - imatch = -1 - i = 0 - while(imatch == -1): - if abs(latvals[i] - latRegion[0]) < small: # first index found - startIndex = i - imatch = 0 - i = i + 1 - imatch = -1 - while(imatch == -1): - if abs(latvals[i] - latRegion[nlat - 1] - ) < small: # last index found - lastIndex = i - imatch = 0 - i = i + 1 - - wts = pts_wts_bnds[1][startIndex:lastIndex + 1] - bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] - - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - - return (wts, bnds) - -# else: # must be generic latitude ------- -# -# wts, bnds = generic_wts_bnds(latIn) -# if reverse_latitude == 'yes': -# wts = wts[::-1] -# bnds = bnds[::-1] -# return (wts, bnds) - - -def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" - # Logic outline - # START NO USER MASK SECTION ? - # - # START USER MASK SECTION ? - # USER SUPPLIED MASK IS 2D ? - # USER SUPPLIED MASK IS FULL SIZE ? - - # ---- check the missingMatch pass -------- - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' - sendmsg(msg) - raise ValueError - - # ----- Check for missing data in dataIn, set missingFlag and miss, the va - - # missingFlag = 0 if there is no missing data - # missingFlag = 1 if there is missing data found using greater than missingValueIn - # missingFlag = 1 if there is missing data found using the default 1.0e20 - # missingFlag = 2 if there is missing data found using equal to missingValueIn - # missingFlag = 3 if there is missing data found using less than - # missingValueIn - - missingFlag = 0 - - # use value from the file - if missingValueIn is not None: - - if missingMatch == 'greater': - if missingValueIn > 0: - miss = 0.99 * missingValueIn - else: - miss = 1.01 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.greater( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 1 - - elif missingMatch == 'equal': - miss = missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.equal( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 2 - - elif missingMatch == 'less': - if missingValueIn > 0: - miss = 1.01 * missingValueIn - else: - miss = 0.99 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.less( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 3 - - # ----- get the shape of dataIn and set the number of dimensions in the da - - dataShape = dataIn.shape - # set size and check against positionIn - numberDataDim = len(dataShape) - - # remove the None fillers - reducedPositionIn = [] - for i in range(len(positionIn)): - if positionIn[i] is not None: - reducedPositionIn.append(positionIn[i]) - - if numberDataDim != len(reducedPositionIn): - msg = 'positionIn does not describe the number of dimensions in the data' - sendmsg(msg) - raise ValueError - - # ----- Determine the order of latitude and level in the data ------- - - # sequence is standard (lat,lon) - if positionIn[0] > positionIn[1]: - levlatFlag = 1 - else: - levlatFlag = 0 - - # ------------------------------------------------------------------------------------------------------ - # ----------------------------------------- Generate the mask ----------- - # ------------------------------------------------------------------------------------------------------ - - # ------------------------------------------------------------------------------------------------------ - # ---------- START NO USER MASK SECTION - - if maskIn is None: # ---- need to generate the mask from scratch ---- - - # allocate memory - amskin = numpy.ones(dataShape, numpy.float32) - - # ---------- START USER MASK SECTION - - else: # ---- use the users supplied mask ---- - - numberMaskDim = len(maskIn.shape) - - if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D - - # mask shape is (lat,lon) - if levlatFlag == 1: - checkmaskShape = ( - dataShape[positionIn[1]], dataShape[positionIn[0]]) - # mask shape is (lon,lat) - else: - checkmaskShape = ( - dataShape[positionIn[0]], dataShape[positionIn[1]]) - - if maskIn.shape != checkmaskShape: # check the mask shape - msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' - sendmsg(msg) - raise IndexError - - # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED - - if numberDataDim > 2: - # replicate the mask to size of dataIn - amskin = numpy.resize(maskIn, dataShape) - - else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE - - amskin = maskIn - - if numberMaskDim != numberDataDim: - msg = 'Error -- user supplied mask must be 2D or the size of the data' - sendmsg(msg) - raise IndexError - - if amskin.shape != dataIn.shape: - msg = 'Error -- full size mask supplied must have the same shape as the input data' - sendmsg(msg) - raise IndexError - - # there is missing data in dataIn to add to amskin - if missingFlag != 0: - if missingFlag == 1: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - elif missingFlag == 2: - amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) - elif missingFlag == 3: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - - amskin = amskin.astype(numpy.float32) - - return amskin - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None - - -def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" - - nlev = len(levvals) - - nlat = len(latvals) - theta = (math.pi / 180.) * latvals - - xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory - - t0 = 60. - p0 = 1000. - - for j in range(nlat): - for i in range(nlev): - x = math.cos(theta[j])**2 - y = t0 * ((levvals[i] / p0)**.3) - xsection[i, j] = x * y - 30. - - return xsection - - -def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" - - if data1.shape != data2.shape: - print('Error in shape in rmserror') - print(('data1 shape = ', data1.shape)) - print(('data2 shape = ', data2.shape)) - raise ValueError - - d1 = numpy.ravel(data1) - d2 = numpy.ravel(data2) - - sq = (d1 - d2) * (d1 - d2) - error = numpy.sum(sq) / len(d1) - rmserror = numpy.sqrt(error) - - return rmserror - - -if __name__ == '__main__': - import math - - latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) - levList = [10., 40., 75., 100., 150., 250., 350., 500., - 650., 850., 1000.] # pick some levels - levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - latOut = cdms2.createGaussianAxis(64) - levList = [10., 30., 50., 70., 100., 200., 300., 400., - 500., 700., 850., 1000.] # pick some levels - levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - - xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) - - # make some artificial data - dataIn = section(latIn[:], levIn[:]) - var = cdms2.createVariable( - dataIn, axes=( - levIn, latIn), attributes={ - 'units': 'N/A'}, id='test') - - dataOut = xregridf(dataIn) - - # make the exact answer - dataCheck = section(latOut[:], levOut[:]) - # find the rms error - error = rmserror(dataOut, dataCheck) - - print('expected cross section test case rms error = 0.18581882') - # print 'expected cross section test case rms error = 0.23062' - print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/Lib/crossSection.py.orig b/regrid2/Lib/Lib/crossSection.py.orig deleted file mode 100644 index c06eae4a..00000000 --- a/regrid2/Lib/Lib/crossSection.py.orig +++ /dev/null @@ -1,1095 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -import numpy -import copy -from . import _regrid -from .error import RegridError - - -class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, - latTypeOut=None, latSizeOut=None): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, - # latTypeOut = None, latSizeOut = None): - # - # PROCEDURE: - # - # The user must assemble at least the following four pieces of information: - # - # latIn - the axis specifying the latitude grid for the input data - # - # latOut - the axis specifying the latitude grid for the output data - # - # levIn - the axis specifying the pressure grid for the input data - # - # levOut - the axis specifying the pressure grid for the output data - # - # - # Additional information is required if a latitude grid is not global. It may be generic. - # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice - # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the - # computation requires the size of the global grid from which the subset was choosen. Consequently, - # the user must assemble: - # - # latTypeIn -- for input latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region - # - # latTypeOut -- for output latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region - # - # USAGE: - # - # To make an instance preparing for a global to global regrid, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) - # - # To make an instance preparing for a global to a regional grid which, for example, is a subset of - # a global gaussian grid of size 64, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) - # - # where the latOut axis must have been selected from the global 64 length gaussian grid - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.latOut = latOut - self.levIn = levIn - self.levOut = levOut - self.nlevi = len(levIn) - self.nlevo = len(levOut) - - latIn, self.nlati = checkdimension(latIn, 'input latitude') - latOut, self.nlato = checkdimension(latOut, 'output latitude') - - # --- check for a single grid point in the latitude-level plane - - if self.nlevo == 1 and self.nlato != 1: - sendmsg( - 'Error in output grid - a single level value requires a single latitude value') - raise ValueError - if self.nlevo != 1 and self.nlato == 1: - sendmsg( - 'Error in output grid - a single latitude value requires a single longitude value') - raise ValueError - if self.nlevo == 1 and self.nlato == 1: - calculateMean = 1 - msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' - sendmsg(msg) - else: - calculateMean = 0 - - # --- get the latitude coordinate grid boundaries for the input grid - - if latTypeIn is None: # global latIn - lat_wts_bndsIn = get_latitude_wts_bnds(latIn) - else: - lat_wts_bndsIn = get_region_latitude_wts_bnds( - latIn, latTypeIn, latSizeIn) - - lat_bndsIn = lat_wts_bndsIn[1] - bnin, bsin = latitude_bounds(lat_bndsIn) - - if calculateMean == 0: # meaningful grid - - # --- get the latitude coordinate grid boundaries for the output grid - - if latTypeOut is None: # global latOut - lat_wts_bndsOut = get_latitude_wts_bnds(latOut) - else: - lat_wts_bndsOut = get_region_latitude_wts_bnds( - latOut, latTypeOut, latSizeOut) - - lat_bndsOut = lat_wts_bndsOut[1] - bnout, bsout = latitude_bounds(lat_bndsOut) - - else: - bnout = numpy.array([90.0], numpy.float32) - bsout = numpy.array([-90.0], numpy.float32) - - # --- call maplength to get the rest of the self data needed by rgrdlength - - t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) - - self.latdx, self.latpt, self.wtlat = t - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the regridder function. - ar is the input array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = "zy" - else: - order = "tzy" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = str.lower(order) - - # Map order to positionIn - positionIn = [None] * 3 - for i in range(len(order)): - if order[i] == 'y': - positionIn[0] = i - if inputIsVariable: - axislist[i] = self.latOut - elif order[i] == 'z': - positionIn[1] = i - if inputIsVariable: - axislist[i] = self.levOut - else: - positionIn[2] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - # Mask fill_value and return results - print("INPUT IS VAR:", inputIsVariable) - if inputIsVariable == 1: - result = numpy.ma.masked_values(outar, missing) - result = cdms2.createVariable(result, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - result = numpy.ma.masked_values(result, missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', - positionIn=None, maskIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in - # the latitude-level plane. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, - # missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed - # in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence latitude, - # level and time. Latitude and level are required. If time is missing submit None in its - # slot in the tuple. Notice that the length of the tuple is - # always three. - # - # Explicitly, in terms of the shape of dataIn as returned by python's shape function - # - # positionIn[0] contains the position of latitude in dataIn - # positionIn[1] contains the position of level in dataIn or None - # positionIn[2] contains the position of time in dataIn or None - # - # As examples: - # If the c order shape of 3D data is - # (number of times, number of levels, number of latitudes) - # submit - # (2, 1, 0). - # - # If the c order shape of 2D data is - # (number of times, number of latitudes) - # submit - # (1, None, 0). - # - # Send in None if the shape is a subset of (time, level, latitude) which is evaluated - # as follows: - # 2D -- code assumes (1,0,None) - # 3D -- code assumes (2,1,0) - # - # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This - # mask only works on the latitude grid. It is not possible to mask out a region in the level - # plane. The 0.0 value removes the data from correponding grid point. The user can supply the - # following choices: - # - # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing - # data in the input data array, dataIn - # - # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, - # dataIn. This user supplied mask might be used to mask a latitude region. It is not - # required to account for missing data in the input data. The code uses missingValueIn - # and missingMatch to supply the 0.0s for grid points with missing data in the input - # data array, dataIn. - # - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # WARNING: This code does not regrid cross sections which have a single dummy longitude value! - # - # - #-----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # try to identify a single dummy longitude - - dataShape = dataIn.shape - - if len(dataShape) > 3: - msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is not None: - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # set missing value to be used in dataOut - - if missingValueOut is None: - if missingValueIn is not None: - # default - omit = missingValueIn - else: - # default - omit = 1.0e20 - else: - # user choice - omit = missingValueOut - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - # produce the input for rgdlength not generated by maplength - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is None: # construct the default positionIn tuple - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - if numberDim == 2: # fill end of list with a None - positionList.append(None) - - positionIn = tuple(positionList) - - if len(positionIn) != 3: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' - sendmsg(msg) - raise TypeError - - # set ilon, ilat in Fortran order except that the first index is 0 - - # not 1 - ilat = numberDim - 1 - positionIn[0] - - itim1 = itim2 = -1 - ntim1 = ntim2 = 0 - - if numberDim == 2: # lat and level field - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - - if numberDim == 3: # lon_lat field + level + time - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - itim2 = numberDim - 1 - positionIn[2] - ntim2 = dataShape[positionIn[2]] - - # check for consistency between the grid axiss and the dataIn shape - - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # allocate memory for aout -- the array with original number of levels - # but the new number of latitudes - - aoutList = list(dataIn.shape) - aoutList[positionIn[0]] = self.nlato - # memory for aout - aout = numpy.zeros(tuple(aoutList), numpy.float32) - - # generate the mask - - amskin = sectionmask( - dataIn, - positionIn, - maskIn, - missingValueIn, - missingMatch) - - # ------------- call rgdlength to regrid latitude --------------- - - _regrid.rgdlength( - ilat, - itim1, - itim2, - ntim1, - ntim2, - self.nlati, - self.nlato, - omit, - self.latdx, - self.latpt, - self.wtlat, - amskin, - dataIn, - aout) - - # ------------- call rgdpressure to regrid pressure ------------- - - # allocate memory for ap -- the array with new number of levels and the - # new number of latitudes - - apList = list(dataIn.shape) - apList[positionIn[0]] = self.nlato - apList[positionIn[1]] = self.nlevo - # memory for ap - ap = numpy.zeros(tuple(apList), numpy.float32) - - nlon = 0 - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.levIn[:].astype(numpy.float64) - levOut = self.levOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlato, - nlon, - ntim2, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - aout, - ap) - - if missingMatch == 'none': # if no missing do not pass None - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - return ap - - -def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" - - data = x[:] - try: - xsize = len(x) - except TypeError: - sendmsg('Hgrid instance error -- instance requires a ' + name) - raise TypeError - - if data.dtype.char != 'f': - x[:] = x[:].astype(numpy.float32) - - # ----- check for consistency ----- - - if x[0] > x[xsize - 1]: - for n in range(1, xsize): - if x[n] > x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - else: - for n in range(1, xsize): - if x[n] < x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - - return x, xsize - - -def generic_wts_bnds(lat): - try: - bnds = lat.getBounds() - if bnds is None: # No bounds defined - newLat = lat.clone() - newLat.setBounds(None) - bnds = lat.getBounds() - except BaseException: # just an array.... - newLat = cdms2.createAxis(lat) - newLat.setBounds(None) - bnds = newLat.getBounds() - outBnds = bnds[:, 0].tolist() - outBnds.append(bnds[-1][-1]) - outBnds = numpy.array(outBnds) - wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] - wts = numpy.array(wts) / numpy.sum(wts) - return wts, outBnds - - -def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - small = 0.001 # use as tolerance in checking values - - nlat = len(checklatpass) - - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if checklatpass[0] < checklatpass[nlat - - 1]: # need a copy? - checklat = numpy.array(checklatpass, numpy.float64) - checklat = checklat[::-1] - reverse_latitude = 'yes' - else: - checklat = checklatpass - - # ------ check the pass for evenly spaced latitudes ------- - - firstdelta = abs(checklat[0] - checklat[1]) - maxdiff = 0.0 - for i in range(1, nlat - 1): - diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) - if diff > maxdiff: - maxdiff = diff - - if maxdiff < small: - # if abs(90. - checklat[0]) > small or abs(-90. - - # checklat[nlat - 1]) > small: - # grid_type = 'even' # evenly spaced without poles - # wts, bnds = generic_wts_bnds(checklat) - # if reverse_latitude == 'yes': - # wts = wts[::-1] - # bnds = bnds[::-1] - # return (wts, bnds) - # else: - grid_type = 'uniform' # evenly spaced with poles - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for gaussian latitudes ------- - - grid_type = 'gaussian' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for equalarea latitudes ------- - - grid_type = 'equalarea' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ must be generic latitude ------- - wts, bnds = generic_wts_bnds(checklat) - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - -def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" - - latbnds = lat_bnds.astype(numpy.float32) - - if latbnds[0] > latbnds[len(latbnds) - 1]: - bn = latbnds[:-1] - bs = latbnds[1:] - else: - bn = latbnds[1:] - bs = latbnds[:-1] - - return (bn, bs) - - -def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - - latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] - - if latType not in latTypeList: - sendmsg( - "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", - latType) - raise ValueError - return - - if latSize is None: - sendmsg('Error in latSize -- it must be a number') - raise ValueError - return - - nlat = len(latRegionpass) - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if latRegionpass[0] < latRegionpass[nlat - - 1]: # need a copy? - latRegion = numpy.array(latRegionpass, numpy.float64) - latRegion = latRegion[::-1] - reverse_latitude = 'yes' - else: - latRegion = latRegionpass - - small = 0.001 # use as tolerance in checking values - - # ------ check the pass for gaussian latitudes ------- - - if latType != 'generic': - # n to s global pts, wts and bnds - pts_wts_bnds = _regrid.gridattr(latSize, latType) - latvals = pts_wts_bnds[0] - - imatch = -1 - i = 0 - while(imatch == -1): - if abs(latvals[i] - latRegion[0]) < small: # first index found - startIndex = i - imatch = 0 - i = i + 1 - imatch = -1 - while(imatch == -1): - if abs(latvals[i] - latRegion[nlat - 1] - ) < small: # last index found - lastIndex = i - imatch = 0 - i = i + 1 - - wts = pts_wts_bnds[1][startIndex:lastIndex + 1] - bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] - - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - - return (wts, bnds) - -# else: # must be generic latitude ------- -# -# wts, bnds = generic_wts_bnds(latIn) -# if reverse_latitude == 'yes': -# wts = wts[::-1] -# bnds = bnds[::-1] -# return (wts, bnds) - - -def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" - # Logic outline - # START NO USER MASK SECTION ? - # - # START USER MASK SECTION ? - # USER SUPPLIED MASK IS 2D ? - # USER SUPPLIED MASK IS FULL SIZE ? - - # ---- check the missingMatch pass -------- - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' - sendmsg(msg) - raise ValueError - - # ----- Check for missing data in dataIn, set missingFlag and miss, the va - - # missingFlag = 0 if there is no missing data - # missingFlag = 1 if there is missing data found using greater than missingValueIn - # missingFlag = 1 if there is missing data found using the default 1.0e20 - # missingFlag = 2 if there is missing data found using equal to missingValueIn - # missingFlag = 3 if there is missing data found using less than - # missingValueIn - - missingFlag = 0 - - # use value from the file - if missingValueIn is not None: - - if missingMatch == 'greater': - if missingValueIn > 0: - miss = 0.99 * missingValueIn - else: - miss = 1.01 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.greater( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 1 - - elif missingMatch == 'equal': - miss = missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.equal( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 2 - - elif missingMatch == 'less': - if missingValueIn > 0: - miss = 1.01 * missingValueIn - else: - miss = 0.99 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.less( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 3 - - # ----- get the shape of dataIn and set the number of dimensions in the da - - dataShape = dataIn.shape - # set size and check against positionIn - numberDataDim = len(dataShape) - - # remove the None fillers - reducedPositionIn = [] - for i in range(len(positionIn)): - if positionIn[i] is not None: - reducedPositionIn.append(positionIn[i]) - - if numberDataDim != len(reducedPositionIn): - msg = 'positionIn does not describe the number of dimensions in the data' - sendmsg(msg) - raise ValueError - - # ----- Determine the order of latitude and level in the data ------- - - # sequence is standard (lat,lon) - if positionIn[0] > positionIn[1]: - levlatFlag = 1 - else: - levlatFlag = 0 - - # ------------------------------------------------------------------------------------------------------ - # ----------------------------------------- Generate the mask ----------- - # ------------------------------------------------------------------------------------------------------ - - # ------------------------------------------------------------------------------------------------------ - # ---------- START NO USER MASK SECTION - - if maskIn is None: # ---- need to generate the mask from scratch ---- - - # allocate memory - amskin = numpy.ones(dataShape, numpy.float32) - - # ---------- START USER MASK SECTION - - else: # ---- use the users supplied mask ---- - - numberMaskDim = len(maskIn.shape) - - if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D - - # mask shape is (lat,lon) - if levlatFlag == 1: - checkmaskShape = ( - dataShape[positionIn[1]], dataShape[positionIn[0]]) - # mask shape is (lon,lat) - else: - checkmaskShape = ( - dataShape[positionIn[0]], dataShape[positionIn[1]]) - - if maskIn.shape != checkmaskShape: # check the mask shape - msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' - sendmsg(msg) - raise IndexError - - # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED - - if numberDataDim > 2: - # replicate the mask to size of dataIn - amskin = numpy.resize(maskIn, dataShape) - - else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE - - amskin = maskIn - - if numberMaskDim != numberDataDim: - msg = 'Error -- user supplied mask must be 2D or the size of the data' - sendmsg(msg) - raise IndexError - - if amskin.shape != dataIn.shape: - msg = 'Error -- full size mask supplied must have the same shape as the input data' - sendmsg(msg) - raise IndexError - - # there is missing data in dataIn to add to amskin - if missingFlag != 0: - if missingFlag == 1: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - elif missingFlag == 2: - amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) - elif missingFlag == 3: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - - amskin = amskin.astype(numpy.float32) - - return amskin - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None - - -def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" - - nlev = len(levvals) - - nlat = len(latvals) - theta = (math.pi / 180.) * latvals - - xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory - - t0 = 60. - p0 = 1000. - - for j in range(nlat): - for i in range(nlev): - x = math.cos(theta[j])**2 - y = t0 * ((levvals[i] / p0)**.3) - xsection[i, j] = x * y - 30. - - return xsection - - -def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" - - if data1.shape != data2.shape: - print('Error in shape in rmserror') - print(('data1 shape = ', data1.shape)) - print(('data2 shape = ', data2.shape)) - raise ValueError - - d1 = numpy.ravel(data1) - d2 = numpy.ravel(data2) - - sq = (d1 - d2) * (d1 - d2) - error = numpy.sum(sq) / len(d1) - rmserror = numpy.sqrt(error) - - return rmserror - - -if __name__ == '__main__': - import math - - latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) - levList = [10., 40., 75., 100., 150., 250., 350., 500., - 650., 850., 1000.] # pick some levels - levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - latOut = cdms2.createGaussianAxis(64) - levList = [10., 30., 50., 70., 100., 200., 300., 400., - 500., 700., 850., 1000.] # pick some levels - levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - - xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) - - # make some artificial data - dataIn = section(latIn[:], levIn[:]) - var = cdms2.createVariable( - dataIn, axes=( - levIn, latIn), attributes={ - 'units': 'N/A'}, id='test') - - dataOut = xregridf(dataIn) - - # make the exact answer - dataCheck = section(latOut[:], levOut[:]) - # find the rms error - error = rmserror(dataOut, dataCheck) - - print('expected cross section test case rms error = 0.18581882') - # print 'expected cross section test case rms error = 0.23062' - print('calculated cross section test case rms error = ', error) diff --git a/regrid2/Lib/Lib/error.py b/regrid2/Lib/Lib/error.py deleted file mode 100644 index 327dff22..00000000 --- a/regrid2/Lib/Lib/error.py +++ /dev/null @@ -1,3 +0,0 @@ -class RegridError (Exception): - def __init__(self, args="Unspecified error from regrid package"): - self.args = (args,) diff --git a/regrid2/Lib/Lib/esmf.py b/regrid2/Lib/Lib/esmf.py deleted file mode 100644 index 830910a1..00000000 --- a/regrid2/Lib/Lib/esmf.py +++ /dev/null @@ -1,842 +0,0 @@ -#!/usr/bin/env python - -""" -Copyright (c) 2008-2012, Tech-X Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the conditions -specified in the license file 'license.txt' are met. - -Authors: David Kindig and Alex Pletzer -""" -import re -import time -import numpy -from regrid2 import RegridError -import ESMF -from functools import reduce - -# constants -R8 = ESMF.TypeKind.R8 -R4 = ESMF.TypeKind.R4 -I8 = ESMF.TypeKind.I8 -I4 = ESMF.TypeKind.I4 -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER -CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class EsmfUnstructGrid: - """ - Unstructured grid - """ - - def __init__(self, numTopoDims, numSpaceDims): - """Constructor - - Parameters - ---------- - - numTopoDims - number of topological dimensions - - numSpaceDims - number of space dimensions - """ - # handle to the grid object - self.grid = None - # whether or not nodes were added - self.nodesAdded = False - # whether or not cells were added - self.cellsAdded = False - # the local processor rank - self.pe = 0 - # number of processors - self.nprocs = 1 - # communicator - self.comm = None - - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - self.grid = ESMF.Mesh( - parametric_dim=numTopoDims, - spatial_dim=numSpaceDims) - - def setCells(self, cellIndices, cellTypes, connectivity, - cellMask=None, cellAreas=None): - """ - Set Cell connectivity - - Parameters - ---------- - - cell indices (0-based) - - cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - - connectivity node connectivity array, see below for node ordering - - cellMask - - cellAreas area (volume) of each cell - - Note - ---- - - 3 - / \ - / \ - / \ - / \ - / \ - 1 --------- 2 - - - - - 4------------3 - | | - | | - | | - | | - | | - 1 ---------- 2 - - - - 3 8---------------7 - /|\ /| /| - / | \ / | / | - / | \ / | / | - / | \ / | / | - / | \ 5---------------6 | - 4-----|-----2 | | | | - \ | / | 4----------|----3 - \ | / | / | / - \ | / | / | / - \ | / | / | / - \|/ |/ |/ - 1 1---------------2 - - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX - - """ - n = len(cellIndices) - if not self.cellsAdded: - # node/cell indices are 1-based in ESMF - cellIndices += 1 - self.grid.add_elements(n, cellIndices, cellTypes, - connectivity, elementMask=cellMask, - elementArea=cellAreas) - self.cellsAdded = True - - def setNodes(self, indices, coords, peOwners=None): - """ - Set the nodal coordinates - - Parameters - ---------- - - indices Ids of the nodes (0-based) - - coords nodal coordinates - - peOwners processor ranks where the coordinates reside (0-based) - """ - n = len(indices) - if not self.nodesAdded: - if peOwners is None: - peOwners = numpy.ones((n,), numpy.int32) * self.pe - # node indices are 1-based - indices += 1 - self.grid.add_nodes(n, indices, coords, peOwners) - self.nodesAdded = True - - def toVTK(self, filename): - """ - Write grid to VTK file format - - Parameters - ---------- - - filename VTK file name - _: None - - """ - self.grid.write(filename) - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructGrid: - """ - Structured grid - """ - - def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, - periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, - hasBounds=False): - """ - Constructor - - Parameters - ---------- - - shape Tuple of cell sizes along each axis - - coordSys coordinate system - ESMF.CoordSys.CART Cartesian - ESMF.CoordSys.SPH_DEG (default) Degrees - ESMF.CoordSys.SPH_RAD Radians - - periodicity Does the grid have a periodic coordinate - 0 No periodicity - 1 Periodic in x (1st) axis - 2 Periodic in x, y axes - - staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX - The stagger constants are listed at the top - - hasBounds If the grid has bounds, Run AddCoords for the bounds - """ - # ESMF grid object - self.grid = None - # number of cells in [z,] y, x on all processors - self.shape = shape[::-1] - # number of dimensions - self.ndims = len(self.shape) - # whether or not cell areas were set - self.cellAreasSet = False - # whether or not nodal coords were set - self.nodesSet = False - # whether or not cell centered coordinates were set - self.centersSet = False - - # assume last 2 dimensions are Y,X - # For esmf reverse to X, Y - maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) - - self.centersSet = False - periodic_dim = 0 - pole_dim = 1 - if periodicity == 0: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], - coord_sys=coordSys) - elif periodicity == 1: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, - periodic_dim=periodic_dim, pole_dim=pole_dim, - staggerloc=[staggerloc], coord_sys=coordSys) - else: - msg = """ -esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. - """ % periodicity - raise RegridError(msg) - - # Grid add coordinates call must go here for parallel runs - # This occur before the fields are created, making the fields - # parallel aware. - if ((staggerloc == CENTER) and (not self.centersSet)): - self.centersSet = True - elif (staggerloc == CORNER) and (not self.nodesSet): - self.nodesSet = True - - if hasBounds is not None: - if self.ndims == 2: - self.grid.add_coords([CORNER], coord_dim=None, from_file=False) - if self.ndims == 3: - self.grid.add_coords( - [VCORNER], coord_dim=None, from_file=False) - - def getLocalSlab(self, staggerloc): - """ - Get the local slab (ellipsis). You can use this to grab - the data local to this processor - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple of slices - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([slice(lo[i], hi[i], None) - for i in range(self.ndims)])[::-1] - - def getLoHiBounds(self, staggerloc): - """ - Get the local lo/hi index values for the coordinates (per processor) - (hi is not inclusive, lo <= index < hi) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - lo, hi lists - """ - lo = self.grid.lower_bounds[staggerloc] - hi = self.grid.upper_bounds[staggerloc] - return lo, hi - - def getCoordShape(self, staggerloc): - """ - Get the local coordinate shape (may be different on each processor) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] - - def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): - """ - Populate the grid with staggered coordinates (e.g. corner or center). - - - Parameters - ---------- - - coords - The curvilinear coordinates of the grid. - List of numpy arrays. Must exist on all procs. - - staggerloc - The stagger location - ESMF.StaggerLoc.CENTER (default) - ESMF.StaggerLoc.CORNER - - globalIndexing - if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - - Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, - hence the dimensions are reversed here. - """ - # allocate space for coordinates, can only add coordinates once - for i in range(self.ndims): - ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) - if globalIndexing: - slab = self.getLocalSlab(staggerloc)[::-1] - # Populate self.grid with coordinates or the bounds as needed - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] - else: - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] - - def getCoords(self, dim, staggerloc): - """ - Return the coordinates for a dimension - - Parameters - --------- - - dim desired dimension (zero based indexing) - - staggerloc Stagger location - """ - gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) - shp = self.getCoordShape(staggerloc)[::-1] - return numpy.reshape(gridPtr, shp).T - - def setCellAreas(self, areas): - """ - Set the cell areas - - Parameters - --------- - - areas numpy array - - _: None - - """ - self.grid.add_item(item=ESMF.GridItem.Area) - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - areaPtr[:] = areas.T.flat - self.cellAreasSet = True - - def getCellAreas(self): - """ - - Returns - ------- - - cell areas or None if setCellAreas was not called - """ - if self.cellAreasSet: - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - return numpy.reshape(areaPtr, self.shape).T - else: - return None - - def getMask(self, staggerloc=CENTER): - """ - Get mask array. In ESMF, the mask is applied to cells. - - Returns - ------- - - mask numpy array. 1 is invalid by default. This array exists on all procs - """ - try: - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, staggerloc=staggerloc) - except BaseException: - maskPtr = None - return maskPtr.T - - def setMask(self, mask, staggerloc=CENTER): - """ - Set mask array. In ESMF, the mask is applied to cells. - - Parameters - ---------- - - mask numpy array. 1 is invalid by default. This array exists - on all procs - - _: None - """ - self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, - staggerloc=staggerloc) - slab = self.getLocalSlab(CENTER)[::-1] - maskPtr[:] = mask.T[slab] - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructField: - """ - Structured field. - """ - - def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): - """ - Creator for structured ESMF Field - - Parameters - ---------- - - esmfGrid - instance of an ESMF - - name field - name (must be unique) - - datatype - data type, one of 'float64', 'float32', 'int64', or 'int32' - (or equivalent numpy dtype) - - staggerloc - ESMF.StaggerLoc.CENTER - ESMF.StaggerLoc.CORNER - """ - # field object - self.field = None - # the local processor rank - self.pe = 0 - # the number of processors - self.nprocs = 1 - # associated grid - self.grid = esmfGrid - # staggering - self.staggerloc = staggerloc - # communicator - self.comm = None - - try: - from mpi4py import MPI - self.comm = MPI.COMM_WORLD - except BaseException: - pass - - etype = None - sdatatype = str(datatype) # in case user passes a numpy dtype - if re.search('float64', sdatatype): - etype = R8 - elif re.search('float32', sdatatype): - etype = R4 - elif re.search('int64', sdatatype): - etype = I8 - elif re.search('int32', sdatatype): - etype = I4 - else: - msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype - raise RegridError(msg) - - self.field = ESMF.Field( - grid=esmfGrid.grid, - name=name, - typekind=etype, - staggerloc=staggerloc) - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - def getPointer(self): - """ - Get field data as a flat array - - Returns - ------- - - pointer - """ - return numpy.ravel(self.field.data) - - def getData(self, rootPe): - """ - Get field data as a numpy array - - Parameters - ---------- - - rootPe if None then local data will be fetched, otherwise - gather the data on processor "rootPe" (all other - procs will return None). - - _: None - - Returns - ------- - - numpy array or None - """ - ptr = self.getPointer() - if rootPe is None: - shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] - # local data, copy - return numpy.reshape(ptr, shp).T - else: - # gather the data on rootPe - lo, hi = self.grid.getLoHiBounds(self.staggerloc) - los = [lo] - his = [hi] - ptrs = [ptr] - ptr = numpy.reshape(ptr, hi) - if self.comm is not None: - los = self.comm.gather(lo) # Local - his = self.comm.gather(hi) # Local - ptrs = self.comm.gather(ptr, root=rootPe) - - if self.pe == rootPe: # Local - # reassemble, find the largest hi indices to set - # the shape of the data container - bigHi = [0 for i in range(self.grid.ndims)] - for i in range(self.grid.ndims): - bigHi[i] = reduce(lambda x, y: max(x, y), - [his[p][i] for p in range(self.nprocs)]) - # allocate space to retrieve the data - bigData = numpy.empty(bigHi, ptr.dtype) - bigData[:] = 0.0 - - # populate the data - for p in range(self.nprocs): - slab = tuple([slice(los[p][i], his[p][i], None) for - i in range(self.grid.ndims)]) - # copy - bigData[slab].flat = ptrs[p] - return bigData.T # Local - - # rootPe is not None and self.pe != rootPe - return None - - def setLocalData(self, data, staggerloc, globalIndexing=False): - """ - Set local field data - - Parameters - ---------- - - data full numpy array, this method will take care of setting a - the subset of the data that reside on the local processor - - staggerloc stagger location of the data - - - globalIndexing if True array was allocated over global index - space, array was allocated over local index - space (on this processor) - """ - ptr = self.field.data - if globalIndexing: - slab = self.grid.getLocalSlab(staggerloc)[::-1] - ptr[:] = data.T[slab] - else: - ptr[:] = data.T - - -########################################################################## - -class EsmfRegrid: - """ - Regrid source grid data to destination grid data - """ - - def __init__(self, srcField, dstField, - srcFrac=None, - dstFrac=None, - srcMaskValues=None, - dstMaskValues=None, - regridMethod=BILINEAR, - ignoreDegenerate=False, - unMappedAction=IGNORE): - """ - Constuct regrid object - - Parameters - ---------- - - srcField - the source field object of type EsmfStructField - - dstField - the destination field object of type EsmfStructField - - srcMaskValues - Value of masked cells in source - - dstMaskValues - Value of masked cells in destination - - srcFrac - Cell fractions on source grid (type EsmfStructField) - - dstFrac - Cell fractions on destination grid (type EsmfStructField) - - regridMethod - ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - - unMappedAction - ESMF.UnmappedAction.{IGNORE,ERROR} - - ignoreDegenerate - Ignore degenerate cells when checking inputs - """ - self.srcField = srcField - self.dstField = dstField - self.regridMethod = regridMethod - self.srcAreaField = None - self.dstAreaField = None - self.srcFracField = srcFrac - self.dstFracField = dstFrac - self.regridHandle = None - self.ignoreDegenerate = ignoreDegenerate - - timeStamp = re.sub('\.', '', str(time.time())) - - # create and initialize the cell areas to zero - if regridMethod == CONSERVE: - self.srcAreaField = EsmfStructField(self.srcField.grid, - name='src_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcAreaField.getPointer() - dataPtr[:] = 0.0 - self.dstAreaField = EsmfStructField(self.dstField.grid, - name='dst_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstAreaField.getPointer() - dataPtr[:] = 0.0 - - # initialize fractional areas to 1 (unless supplied) - if srcFrac is None: - self.srcFracField = EsmfStructField(self.srcField.grid, - name='src_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcFracField.getPointer() - dataPtr[:] = 1.0 - - if dstFrac is None: - self.dstFracField = EsmfStructField(self.dstField.grid, - name='dst_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstFracField.getPointer() - dataPtr[:] = 1.0 - - srcMaskValueArr = None - if srcMaskValues is not None: - srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) - - dstMaskValueArr = None - if dstMaskValues is not None: - dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) - - self.regridHandle = ESMF.Regrid( - srcField.field, - dstField.field, - src_frac_field=self.srcFracField.field, - dst_frac_field=self.dstFracField.field, - src_mask_values=srcMaskValueArr, - dst_mask_values=dstMaskValueArr, - regrid_method=regridMethod, - unmapped_action=unMappedAction, - ignore_degenerate=self.ignoreDegenerate) - - def getSrcAreas(self, rootPe): - """ - Get the src grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.srcAreaField.data.T - return None - - def getDstAreas(self, rootPe): - """ - Get the dst grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.dstAreaField.data.T - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.srcFracField is not None: - # self.srcFracField.get_area() - return self.srcFracField.data.T - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.dstFracField is not None: - # self.dstFracField.get_area() - return self.dstFracField.data.T - return None - - def __call__(self, srcField=None, dstField=None, zero_region=None): - """ - Apply interpolation weights - - Parameters - ---------- - - srcField source field (or None if src field passed to - constructor is to be used) - - dstField destination field (or None if dst field passed - to constructor is to be used) - - zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) - """ - if srcField is None: - srcField = self.srcField - if dstField is None: - dstField = self.dstField - - # default is keep the masked values intact - zeroregion = ESMF.Region.SELECT - if self.regridMethod == CONSERVE: - zeroregion = None # will initalize to zero - - self.regridHandle( - srcfield=srcField.field, - dstfield=dstField.field, - zero_region=zeroregion) - - def __del__(self): - if self.regridHandle is not None: - self.regridHandle.destroy() diff --git a/regrid2/Lib/Lib/gsRegrid.py b/regrid2/Lib/Lib/gsRegrid.py deleted file mode 100644 index de150dba..00000000 --- a/regrid2/Lib/Lib/gsRegrid.py +++ /dev/null @@ -1,1179 +0,0 @@ -#!/usr/bin/env python - -""" -Regridding of curvilinear structured grids -Alex Pletzer and Dave Kindig, Tech-X (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. -""" -# standard python includes -# from re import search, sub -from ctypes import c_double, c_float, c_int, \ - c_wchar_p, CDLL, byref, POINTER -# import ctypes -import operator -import sys -import os -import copy -import numpy -import warnings -from regrid2 import RegridError -from functools import reduce -import fnmatch - -C_DOUBLE_P = POINTER(c_double) - -# libcf -try: - from pycf import libCFConfig, __path__ -except BaseException: - raise ImportError('Error: could not import pycf') - -LIBCFDIR = __path__[0] + "/pylibcf" - -__FILE__ = sys._getframe().f_code.co_filename - - -def catchError(status, lineno): - if status != 0: - raise RegridError("ERROR in %s: status = %d at line %d" - % (__FILE__, status, lineno)) - - -def getTensorProduct(axis, dim, dims): - """ - Convert an axis into a curvilinear coordinate by applying - a tensor product - - Parameters - ---------- - - axis 1D array of coordinates - - dim dimensional index of the above coordinate - - dims sizes of all coordinates - - Returns - ------- - - coordinate values obtained by tensor product - """ - return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), - numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) - - -def makeCurvilinear(coords): - """ - Turn a mixture of axes and curvilinear coordinates into - full curvilinear coordinates - - Parameters - ---------- - - coords list of coordinates - - Returns - ------- - - new list of coordinates and associated dimensions - """ - rank = len(coords) - - count1DAxes = 0 - dims = [] - for i in range(rank): - coord = coords[i] - if len(coord.shape) == 1: - # axis - dims.append(len(coord)) - count1DAxes += 1 - elif len(coord.shape) == rank: - # fully curvilinear - dims.append(coord.shape[i]) - else: - # assumption: all 1D axes preceed curvilinear - # coordinates!!! - dims.append(coord.shape[i - count1DAxes]) - - for i in range(rank): - nd = len(coords[i].shape) - if nd == rank: - # already in curvilinear form, keep as is - pass - elif nd == 1: - # it's an axis - coords[i] = getTensorProduct(coords[i][:], i, dims) - elif rank == 3 and nd == 2 and i > 0: - # assume leading coordinate is an axis - o1 = numpy.ones((len(coords[0]),), coords[i].dtype) - coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) - else: - raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" - % (__FILE__, str([x.shape for x in coords]))) - return coords, dims - - -def makeCoordsCyclic(coords, dims): - """ - Make coordinates cyclic - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - new, extended coordinates such that the longitudes cover the sphere - and new dimensions - """ - # assume lon is the last coordinate!! - - # check if already extended - eps = 1.e-3 - - # some models already overlap - diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # some models are already periodic - diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # make cyclic by appending a column to the coordinates - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-1] += 1 # append to the right - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:-1] = coords[i][...] - newCoords[i][..., -1] = coords[i][..., 0] - - # add modulo term, want deltas ~ order of dlon otherwise add - # or subtract a periodicity length - nlon = dims[-1] - dlon = 360.0 / float(nlon) # average resolution - tol = 360.0 - min(5, nlon) * dlon - mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) - mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) - newCoords[-1][..., -1] += 360.0 * mask1 - newCoords[-1][..., -1] -= 360.0 * mask2 - - return newCoords, newDims - - -def checkForCoordCut(coords, dims): - """ - Look for a cut in a coordinate system (e.g. tri-polar grid) - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - True for cut found - False for no cut - """ - - # Assume latitude is next to last coordinate and longitude is last - # coordinate!!! - - rank = len(dims) - if rank < 2: - # print 'no cut: dims < 2' - return False - if len(coords[-2].shape) < 2: - # Is the 'lat' coordinate an axis? - return False - - nlat, nlon = dims[-2], dims[-1] - lat = coords[-2] - eps = 1.e-7 - - # Check to see if the top row has already be dealt with by the modeling - # agency. Last row is repeated in reverse. - - topRow = coords[-2][..., nlat - 1, :] - revTop = coords[-2][..., nlat - 1, ::-1] - nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow - diffs = abs(revTop - nextRow) - - # If already accounted for all diffs are 0. - if numpy.all(diffs < eps): - # print "no cut: reversed" - return False - - # Lon of max latitude -- Looking for a rotated pole - maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) - inTopRow = False - if len(maxLats[0] > 0): - inTopRow = numpy.all(maxLats[-2] == nlat - 1) - if not inTopRow: - # The max lats are not in the top row. The cut may already be handled - # print 'no cut: max lat not in top row.' + \ - # 'Either: it is a funky grid or rotated pole' - return False - - # Only in top row. - maxLatInd = lat[..., nlat - 1, :].argmax() - maxLonInd = lat[..., maxLatInd].argmax() - rowOfMaxLat = lat[..., maxLonInd, :] - diffs = rowOfMaxLat - topRow - - if diffs.max() != 0: - # Rotated Pole - # print "no cut: rotated pole" - return False - - # Find locale minima. - # A rotated pole grid has only one minimum. A tripolar grid should - # have two, though they may not be at the same latitude - - minInds = numpy.where(abs(topRow - topRow.min()) < eps) - if len(minInds[0]) > 2: - # Account for the end points matching - # Multiple minima in the top row - return True - - # Now if we have an offset tri-pole. The extra poles are not at the same - # latitude - minCount = 0 - firstInd = topRow.argmin() - diffs = numpy.diff(topRow) - if firstInd == 0: - if revTop.argmin() == 0: - if topRow[firstInd] == revTop[0]: - minCount += 1 - else: - minCount += 1 - # Look for next Minima - index = firstInd + 1 - while diffs[index] > 0: - index += 1 - if index == nlon: - break - nextIndex = topRow[index + 1:].argmin() + index + 1 - if nextIndex != index + 1 and nextIndex != nlon - 1: - minCount += 1 - if minCount == 1: - # print "no cut: one pole" - return False - - return True - - -def handleCoordsCut(coords, dims, bounds): - """ - Generate connectivity across a cut. e.g. from a tri-polar grid. - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates list of rank - - dims input dimensions - - bounds boundaries for each coordinate - - Returns - ------- - - extended coordinates such that there is an extra row containing - connectivity information across the cut - """ - - # Assume latitude is next to last coordinate and longitude is - # last coordinate!!! - - dims = coords[-2].shape - - # Add row to top with connectivity information. This means rearranging - # the top row - def getIndices(array, nlon, newI): - """ - Find indices where a cell edge matches for two cells - - Parameters - ---------- - - array Array of booleans - - nlon number of longitudes - - newI index row with connectivity to be updated - - Returns - ------- - - new coordinates, new dimensions, index row - """ - for i in range(len(array)): - # An edge - if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa - if newI[i] < 0: - newI[i] = (nlon - 1) - i - if newI[(nlon - 1) - i] < 0: - newI[(nlon - 1) - i] = i - - # Assume mkCyclic == True - newI = numpy.arange(nlon - 1, -1, -1) - 1 - newI[nlon - 1] = 0 # Complete the rotation - - # Build new coordinate array and adjust dims - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-2] += 1 - - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:dims[-2], :] = coords[i][...] - newCoords[i][..., dims[-2], - :] = coords[i][..., dims[-2] - 1, newI] - - return newCoords, newDims, newI - - -class Regrid: - - def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, - handleCut=False, verbose=False): - """ - Constructor - - Parameters - ---------- - - src_grid source grid, a list of [x, y, ...] coordinates - or a cdms2.grid.Transient - - dst_grid destination grid, a list of [x, y, ...] coordinates - - src_bounds list of cell bounding coordinates (to be used when - handling a cut in coordinates) - - mkCyclic Add a column to the right side of the grid to complete - a cyclic grid - - handleCut Add a row to the top of grid to handle a cut for - grids such as the tri-polar grid - - verbose print diagnostic messages - - - Note: the grid coordinates can either be axes (rectilinear grid) or - n-dimensional for curvilinear grids. Rectilinear grids will - be converted to curvilinear grids. - """ - self.regridid = c_int(-1) - self.src_gridid = c_int(-1) - self.dst_gridid = c_int(-1) - self.rank = 0 - self.src_dims = [] - self.dst_dims = [] - self.src_coords = [] - self.dst_coords = [] - self.lib = None - self.extendedGrid = False - self.handleCut = False - self.dst_Index = [] - self.verbose = verbose - self.weightsComputed = False - self.maskSet = False - - # Open the shaped library - dynLibFound = False - for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': - if os.path.exists(LIBCFDIR + sosuffix): - dynLibFound = True - CFfile = self.find('pylibcf.*', __path__[0]) - if os.path.exists(CFfile): - try: - self.lib = CDLL(CFfile) - except BaseException: - pass -# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': -# if os.path.exists(LIBCFDIR + sosuffix): -# dynLibFound = True -# try: -# self.lib = CDLL(LIBCFDIR + sosuffix) -# break -# except: -# pass - if self.lib is None: - if not dynLibFound: - raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - - # Number of space dimensions - self.rank = len(src_grid) - - if len(dst_grid) != self.rank: - raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" - % (__FILE__, len(dst_grid), self.rank)) - - if self.rank <= 0: - raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" - % (__FILE__, self.rank)) - - # Convert src_grid/dst_grid to curvilinear grid, if need be - if self.rank > 1: - src_grid, src_dims = makeCurvilinear(src_grid) - dst_grid, dst_dims = makeCurvilinear(dst_grid) - - # Make sure coordinates wrap around if mkCyclic is True - if mkCyclic: - src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - for i in range(self.rank): - print(('...... src_gridNew[%d].shape = %s' - % (i, str(src_gridNew[i].shape)))) - # flag indicating that the grid was extended - if reduce(lambda x, y: x + y, - [src_dimsNew[i] - src_dims[i] - for i in range(self.rank)]) > 0: - self.extendedGrid = True - # reset - src_grid = src_gridNew - src_dims = src_dimsNew - - # Handle a cut in the coordinate system. Run after mkCyclic. - # e.g. a tri-polar grid - if handleCut and src_bounds is not None: - # Test for the presence of a cut. - isCut = checkForCoordCut(src_grid, src_dims) - if isCut: - # No cut - src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, - src_dims, src_bounds) - if dst_Index is not None: - self.handleCut = True - self.extendedGrid = self.extendedGrid - else: - self.handleCut = False - self.extendedGrid = self.extendedGrid - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - src_grid = src_gridNew - src_dims = src_dimsNew - self.dst_Index = dst_Index - - self.src_dims = (c_int * self.rank)() - self.dst_dims = (c_int * self.rank)() - - # Build coordinate objects - src_dimnames = (c_wchar_p * self.rank)() - dst_dimnames = (c_wchar_p * self.rank)() - for i in range(self.rank): - src_dimnames[i] = 'src_n%d' % i - dst_dimnames[i] = 'dst_n%d' % i - self.src_dims[i] = src_dims[i] - self.dst_dims[i] = dst_dims[i] - self.src_coordids = (c_int * self.rank)() - self.dst_coordids = (c_int * self.rank)() - save = 0 - standard_name = "" - units = "" - coordid = c_int(-1) - for i in range(self.rank): - data = numpy.array(src_grid[i], numpy.float64) - self.src_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "src_coord%d" % i - # assume [lev,] lat, lon ordering - if i == self.rank - 2: - standard_name = 'latitude' - units = 'degrees_north' - elif i == self.rank - 1: - standard_name = 'longitude' - units = 'degrees_east' - status = self.lib.nccf_def_coord(self.rank, self.src_dims, - src_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.src_coordids[i] = coordid - - data = numpy.array(dst_grid[i], numpy.float64) - self.dst_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "dst_coord%d" % i - status = self.lib.nccf_def_coord(self.rank, self.dst_dims, - dst_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.dst_coordids[i] = coordid - - # Build grid objects - status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", - byref(self.src_gridid)) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", - byref(self.dst_gridid)) - catchError(status, sys._getframe().f_lineno) - - # Create regrid object - status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, - byref(self.regridid)) - catchError(status, sys._getframe().f_lineno) - - def getPeriodicities(self): - """ - Get the periodicity lengths of the coordinates - - Returns - ------- - - numpy array, values inf indicate no periodicity - """ - coord_periodicity = numpy.zeros((self.rank,), numpy.float64) - status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, - coord_periodicity.ctypes.data_as(C_DOUBLE_P)) - catchError(status, sys._getframe().f_lineno) - return coord_periodicity - - def __del__(self): - """ - Destructor, will be called automatically - """ - status = self.lib.nccf_free_regrid(self.regridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.src_gridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.dst_gridid) - catchError(status, sys._getframe().f_lineno) - - for i in range(self.rank): - - status = self.lib.nccf_free_coord(self.src_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_coord(self.dst_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - def find(self, pattern, path): - result = "" - for root, dirs, files in os.walk(path): - for name in files: - if fnmatch.fnmatch(name, pattern): - result = os.path.join(root, name) - return result - - def setValidMask(self, inMask): - """ - Set valid mask array for the grid - - Parameters - ---------- - - inMask flat numpy array of type numpy.int32 or a valid cdms2 variable - with its mask set. - 0 - invalid, 1 - valid data - - Note: This must be invoked before computing the weights, the - mask is a property of the grid (not the data). - """ - if self.weightsComputed: - raise RegridError('Must set mask before computing weights') - - mask = numpy.array(inMask, dtype=numpy.int32) - - # extend src data if grid was made cyclic and or had a cut accounted - # for - newMask = self._extend(mask) - c_intmask = newMask.ctypes.data_as(POINTER(c_int)) - status = self.lib.nccf_set_grid_validmask(self.src_gridid, - c_intmask) - catchError(status, sys._getframe().f_lineno) - self.maskSet = True - - def setMask(self, inDataOrMask): - """ - Set mask array. The mask is defined for nodes - - Parameters - ---------- - - inDataOrMask cdms2 array or flat mask array, - 0 - valid data - 1 - invalid data - - Note: this definition is compatible with the numpy masked arrays - - Note: note see setValidMask for the opposite definition - - Note: should be called before computing the weights - """ - mask = None - if hasattr(inDataOrMask, 'getmask'): - # cdms2 variable - mask = inDataOrMask.getmask() - else: - # flat mask array - mask = inDataOrMask - # reversing the meaning 1 == valid, 0 == invalid - mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) - # now calling our own mask setter - self.setValidMask(mask) - - def computeWeights(self, nitermax=100, tolpos=1.e-2): - """ - Compute the the interpolation weights - - Parameters - ---------- - - nitermax max number of iterations - - tolpos max tolerance when locating destination positions in - index space - """ - status = self.lib.nccf_compute_regrid_weights(self.regridid, - nitermax, - c_double(tolpos)) - catchError(status, sys._getframe().f_lineno) - self.weightsComputed = True - - def apply(self, src_data_in, dst_data, missingValue=None): - """ - Apply interpolation - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - if not self.weightsComputed: - raise RegridError('Weights must be set before applying the regrid') - # extend src data if grid was made cyclic and or had a cut accounted - # for - src_data = self._extend(src_data_in) - - # Check - if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + - "%s != %s") % (__FILE__, str(src_data.shape), - str(tuple([d for d in self.src_dims])))) - if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + - "%s != %s") % (__FILE__, str(dst_data.shape), - str(tuple([d for d in self.dst_dims])))) - - # Create temporary data objects - src_dataid = c_int(-1) - dst_dataid = c_int(-1) - save = 0 - standard_name = "" - units = "" - time_dimname = "" - - status = self.lib.nccf_def_data(self.src_gridid, "src_data", - standard_name, units, time_dimname, - byref(src_dataid)) - catchError(status, sys._getframe().f_lineno) - - if src_data.dtype != dst_data.dtype: - try: # try recasting - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" - % (src_data.dtype, dst_data.dtype)) - src_data = src_data.astype(dst_data.dtype) - except BaseException: - try: - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" - % (src_data.dtype, dst_data.dtype)) - dst_data = dst_data.astype(src_data.dtype) - except BaseException: - raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" - % (__FILE__, src_data.dtype, dst_data.dtype)) - - # only float64 and float32 data types are supported for interpolation - if src_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif src_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" - % (__FILE__, src_data.dtype)) - - status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", - standard_name, units, time_dimname, - byref(dst_dataid)) - catchError(status, sys._getframe().f_lineno) - if dst_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif dst_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid dst_data type = %s" - % (__FILE__, dst_data.dtype)) - - # Now apply weights - status = self.lib.nccf_apply_regrid( - self.regridid, src_dataid, dst_dataid) - catchError(status, sys._getframe().f_lineno) - - # Clean up - status = self.lib.nccf_free_data(src_dataid) - catchError(status, sys._getframe().f_lineno) - status = self.lib.nccf_free_data(dst_dataid) - catchError(status, sys._getframe().f_lineno) - - return dst_data - - def __call__(self, src_data, dst_data, missingValue=None): - """ - Apply interpolation (synonymous to apply method) - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - self.apply(src_data, dst_data, missingValue) - - def getNumValid(self): - """ - Return the number of valid destination points. Destination points - falling outside the source domain, more gnerally, points which - could not be located on the source grid, reduce the number of - valid points. - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_nvalid(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getNumDstPoints(self): - """ - Return the number of points on the destination grid - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_ntargets(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getSrcGrid(self): - """ - Return the source grid - - Returns - ------- - - grid - """ - return self.src_coords - - def getDstGrid(self): - """ - Return the destination grid - - Returns - ------- - - grid - """ - return self.dst_coords - - def getIndicesAndWeights(self, dst_indices): - """ - Get the indices and weights for a single target location - - Parameters - ---------- - - dst_indices index set on the target grid - - Returns - ------- - - [index sets on original grid, weights] - """ - dinds = numpy.array(dst_indices) - sinds = (c_int * 2**self.rank)() - weights = numpy.zeros((2**self.rank,), numpy.float64) - status = self.lib.nccf_inq_regrid_weights(self.regridid, - dinds.ctypes.data_as( - POINTER(c_double)), - sinds, - weights.ctypes.data_as(POINTER(c_double))) - catchError(status, sys._getframe().f_lineno) - # convert the flat indices to index sets - ori_inds = [] - for i in range(2**self.rank): - inx = numpy.zeros((self.rank,), numpy.int32) - self.lib.nccf_get_multi_index(self.rank, self.src_dims, - sinds[i], - inx.ctypes.data_as(POINTER(c_int))) - ori_inds.append(inx) - - return ori_inds, weights - - def _extend(self, src_data): - """ - Extend the data by padding a column and a row, depending on whether the - grid was made cyclic and a fold was added or not - - Parameters - ---------- - - src_data input source data - - Returns - ------- - - extended source data (or source input data of no padding was applied) - """ - - # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] - # original dimensions, before extension - # assuming ..., lat, lon ordering - nlat, nlon = src_data.shape[-2:] - - # no cut and no cyclic extension - src_dataNew = src_data - - if self.handleCut or self.extendedGrid: - # copy data into new, extended container - src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) - # start filling in... - src_dataNew[..., :nlat, :nlon] = src_data[...] - - if self.handleCut: - # fill in polar cut (e.g. tripolar cut), top row - # self.dst_Index[i] knows how to fold - for i in range(nlon): - src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] - - if self.extendedGrid: - # make data periodic in longitudes - src_dataNew[..., -1] = src_dataNew[..., 0] - - return src_dataNew - - def _findIndices(self, targetPos, nitermax, tolpos, - dindicesGuess): - """ - Find the floating point indices - - Parameters - ---------- - - targetPos numpy array of target positions - - nitermax max number of iterations - - tolpos max toelrance in positions - - dindicesGuess guess for the floating point indices - - Returns - ------- - - indices, number of iterations, achieved tolerance - """ - posPtr = targetPos.ctypes.data_as(POINTER(c_double)) - adjustFunc = None - hit_bounds = numpy.zeros((self.rank), - dtype=int).ctypes.data_as(POINTER(c_int)) - # no periodicity - coord_periodicity = float( - 'inf') * numpy.ones((self.rank), targetPos.dtype) - coord_periodicity_ptr = coord_periodicity.ctypes.data_as( - POINTER(c_double)) - res = copy.copy(dindicesGuess) - resPtr = res.ctypes.data_as(POINTER(c_double)) - src_coords = (POINTER(c_double) * self.rank)() - niter = c_int(nitermax) - tol = c_double(tolpos) - for i in range(self.rank): - ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) - src_coords[i] = ptr - status = self.lib.nccf_find_indices_double(self.rank, - self.src_dims, - src_coords, - coord_periodicity_ptr, - posPtr, - byref(niter), - byref(tol), - adjustFunc, - resPtr, - hit_bounds) - catchError(status, sys._getframe().f_lineno) - return resPtr.contents.value, niter.value, tol.value - -###################################################################### - - -def testMakeCyclic(): - - y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) - x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) - yy = getTensorProduct(y, 0, [len(y), len(x)]) - xx = getTensorProduct(x, 1, [len(y), len(x)]) - coords = [yy, xx] - dims = [len(y), len(x)] - newCoords, newDims = makeCoordsCyclic(coords, dims) -# print 'cyclic lats' -# print newCoords[0] -# print 'cyclic lons' -# print newCoords[1] - - -def testHandleCut(): - - import cdms2 - # Need tripolar grid - filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" - f = cdms2.open(filename) - if not f: - return - - # so = f.variables['so'][0, 0, :, :] - if 'lon' in list(f.variables.keys()): - alllat = f.variables['lat'] - alllon = f.variables['lon'] - else: - alllat = f.getAxis("lat").getData() - alllon = f.getAxis("lon").getData() - - bounds = [f.variables['bounds_lon'][:].data, - f.variables['bounds_lat'][:].data] - coords = [alllat[:].data, alllon[:].data] - dims = alllat.shape - newCoords, newDims = makeCoordsCyclic(coords, dims) - newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) - - -# def testOuterProduct(): - - # 2d - # x = numpy.array([1, 2, 3, 4]) - # y = numpy.array([10, 20, 30]) - # xx = getTensorProduct(x, 0, [len(x), len(y)]) - # yy = getTensorProduct(y, 1, [len(x), len(y)]) - - # z = numpy.array([100, 200]) - # Mixed coordinates and axes - # aa = makeCurvilinear([z, yy, xx]) - # for g in aa: - # print g - -def test(): - def func1(coords): - return coords[0] * coords[1] + coords[2] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = numpy.array([1, 2, 3, 4, 5, 6]) - src_y = numpy.array([10, 20, 30, 40, 50]) - src_z = numpy.array([100, 200]) - - # destination grid, product of axes - dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) - dst_y = numpy.array([15., 20., 25., 30., 40.]) - dst_z = numpy.array([120.0, 180.0, 240.]) - - # regridding constructor - rg = Regrid([src_x, src_y, src_z], - [dst_x, dst_y, dst_z]) -# rg = Regrid([src_x, src_y], -# [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - maxNumIters = 20 - posTol = 1.e-3 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data = ', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -def testMasking(): - import numpy.ma as ma - - def func1(coords): - return coords[0] * coords[1] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) - src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) - - # destination grid, product of axes - dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, - 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) - dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) - - # regridding constructor - rg = Regrid([src_x, src_y], - [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - # Mask needs to be set before weights are computed - mask = rg.getSrcGrid()[0] == 3 - mask[:, 3] = True - rg.setValidMask(mask) - rg.setMask(mask) - maxNumIters = 20 - posTol = 1.e-2 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data =\n', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -if __name__ == '__main__': - # testOuterProduct() - test() - testMasking() - # testMakeCyclic() - # testHandleCut() diff --git a/regrid2/Lib/Lib/gs_horizontal.py b/regrid2/Lib/Lib/gs_horizontal.py deleted file mode 100644 index 20cfa4a6..00000000 --- a/regrid2/Lib/Lib/gs_horizontal.py +++ /dev/null @@ -1,214 +0,0 @@ -import sys -import os -import os.path -# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer -from ctypes import CDLL, c_double, c_uint -import cdms2 -import time -import config -sys.path.append("/home/painter1/libcf/") -libcf = CDLL(config.prefix + '/lib/libcf.so') - - -class GS_Regridder: - - def __init__(self, ingrid, outgrid, - infile=None, outfile=None, remapfile=None): - # Save the grids, make and save a Gridspec remap file. - # For now, we are using the libCF/Gridspec API which operates only on files; - # thus temporary files are written out and read back in. That requires the - # input grids to support a "write_gridspec" method. - # If a path is provided, it prefixes whatever filenames were input. - # If there is no path provided, each filename must include its path. - # Note: it's a bit messy to keep filenames and paths separate internally, - # but the presnet Gridspec function expects lots of directories. - - self.ingrid = ingrid - self.outgrid = outgrid - if (not hasattr(ingrid, "gsfile")): - ingrid.gsfile = None - ingrid.gspath = None - if (infile is None): - self.infile = ingrid.gsfile - self.inpath = ingrid.gspath - else: - self.infile = os.path.basename(infile) - self.inpath = os.path.dirname(infile) - if (not os.path.isfile(self.inpath + "/" + self.infile)): - raise OSError( - "cannot open infile " + - self.inpath + - "/" + - self.infile) - - if (not hasattr(outgrid, "gsfile")): - outgrid.gsfile = None - outgrid.gspath = None - if (outfile is None): - self.outfile = outgrid.gsfile - self.outpath = outgrid.gspath - else: - self.outfile = os.path.basename(outfile) - self.outpath = os.path.dirname(outfile) - if (not os.path.isfile(self.outpath + "/" + self.outfile)): - raise OSError( - "cannot open outfile " + - self.outpath + - "/" + - self.outfile) - - if (remapfile is None): - timestr = str(int(time.time())) - self.remapfile = "remap" + timestr - self.remappath = "/tmp" - else: - self.remapfile = os.path.basename(remapfile) - self.remappath = os.path.dirname(remapfile) - if (not os.path.isdir(self.remappath + "/")): - raise OSError( - "cannot open remapfile directory " + - self.remappath + - "/") - - ingrid.write_gridspec(self.inpath + "/" + self.infile) - outgrid.write_gridspec(self.outpath + "/" + self.outfile) - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - # No variables to interpolate; the gs_fregrid call will be just to - # make a remap file... - dir_in = 256 * "\x00" - dir_out = 256 * "\x00" - input_file = 256 * "\x00" - nfiles = 0 - output_file = 256 * "\x00" - nfiles_out = 0 - scalar_name = 256 * "\x00" - nscalar = 0 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - # For a call which only writes the remap files, gs_fregrid - # expects remapfile to be a full path. For a call in which - # remapping takes place, gs_fregrid expects remapfile to be - # a pure filename, in a path it gets from elsewhere, maybe dir_in. - # (ARRGH - but with the API slated to be replaced, I'll live with it) - remapf = os.path.abspath( - self.remappath + "/" + self.remapfile) + "\0" * 256 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - remapf, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - def __call__(self, ar): - # Interpolate the input variable to the new grid using the Gridspec - # remap file generated when this GS_Remapper object was initialized. - # >>>for now, ar is required to be a variable (MV) <<< - - # Here, convert ar into a file for gs_fregrid - # There's no special Gridspec way to write a variable; you write to any - # *.nc file. The tough part is making sure you have there exactly what's - # needed for the gs_fregrid call, especially because the grids are - # supposedly supergrids and you just have some keywords to use to figure - # out what goes where. And note that we'll need to check whether ar - # really lives on self.ingrid . Supposedly a future API will work - # better in this respect - - # Write the variable to a temporary file, as required by gs_fregrid. - # The remap path should be suitable. - # >>> this should be done more carefully, e.g. deal with failures; - # >>> more worth doing when we have mosaic variables. - timestr = str(int(time.time())) - varfile = cdms2.open( - self.inpath + - "/" + - "invvar" + - timestr + - ".nc", - 'w') - varfile.write(ar) - varfile.close() - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - dir_in = 256 * "\x00" # path is already encoded in input_file - dir_out = 256 * "\x00" # path is already encoded in output_file - input_file = varfile.id + 256 * "\x00" - nfiles = 1 - output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" - nfiles_out = 1 - scalar_name = ar.id + 256 * "\x00" - nscalar = 1 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - print(("__call__ remapfile=", self.remapfile)) - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - self.remapfile, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - # Read the output_file into a variable, and return the variable - f = cdms2.open(self.outpath + "/" + output_file) - vout = f(scalar_name) - f.close() - return vout diff --git a/regrid2/Lib/Lib/horizontal.py b/regrid2/Lib/Lib/horizontal.py deleted file mode 100644 index 67d673f4..00000000 --- a/regrid2/Lib/Lib/horizontal.py +++ /dev/null @@ -1,422 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import warnings -import cdms2 - -_debug = 0 # Set to 1 for debug - -# Map (n,2) boundary arrays to individual boundary arrays. Returns -# (lowerBounds, upperBounds) - - -def extractBounds(bounds): - if bounds[0, 0] < bounds[0, 1]: - lower = bounds[:, 0] - upper = bounds[:, 1] - else: - lower = bounds[:, 1] - upper = bounds[:, 0] - - return (lower.astype(numpy.float32), upper.astype(numpy.float32)) - -# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid -# objects. - - -class Horizontal: - - def __init__(self, ingrid, outgrid): - """ - Constructor for regridding class - - Parameters - ---------- - - ingrid cdms2, ndarray variable - - outgrid cdms2, ndarray variable - """ - - inlat = ingrid.getLatitude() - outlat = outgrid.getLatitude() - inlon = ingrid.getLongitude() - outlon = outgrid.getLongitude() - inlatBounds, inlonBounds = ingrid.getBounds() - outlatBounds, outlonBounds = outgrid.getBounds() - - self.nlati = len(inlat) - self.nlato = len(outlat) - self.nloni = len(inlon) - self.nlono = len(outlon) - self.inmask = ingrid.getMask() - self.outmask = outgrid.getMask() - # Make grid masks consistent with 'internal' convention: - # 0 == invalid - if self.inmask is not None: - self.inmask = 1. - self.inmask - if self.outmask is not None: - self.outmask = 1. - self.outmask - self.inshape = ingrid.shape - self.inorder = ingrid.getOrder() - self.outlat = outgrid.getLatitude().clone() - self.outlon = outgrid.getLongitude().clone() - - bsin, bnin = extractBounds(inlatBounds) - bwin, bein = extractBounds(inlonBounds) - bsout, bnout = extractBounds(outlatBounds) - bwout, beout = extractBounds(outlonBounds) - - if _debug == 1: - import sys - sys.stdout = open('debug_regrid.txt', 'w') - print(("bsin = ", numpy.array2string(bsin, precision=3))) - print(("bnin = ", numpy.array2string(bnin, precision=3))) - print(("bwin = ", numpy.array2string(bwin, precision=3))) - print(("bein = ", numpy.array2string(bein, precision=3))) - print(("bsout = ", numpy.array2string(bsout, precision=3))) - print(("bnout = ", numpy.array2string(bnout, precision=3))) - print(("bwout = ", numpy.array2string(bwout, precision=3))) - print(("beout = ", numpy.array2string(beout, precision=3))) - - self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( - self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) - - def __call__(self, ar, missing=None, order=None, - mask=None, returnTuple=0, **args): - """ - Call the regridder function. - @param ar is the input array. - @param order is of the form "tzyx", "tyx", etc. - @param missing is the missing data value, if any. - @param mask is either 2-D or the same shape as ar. - @param returnTuple If true, return the tuple (outArray, outWeights) where - outWeights is the fraction of each zone of the output grid - which overlaps non-missing zones of the input grid; it has - the same shape as the output array. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Compatibility - if mask is numpy.ma.nomask: - mask = None - - if ar.dtype.type is numpy.bool_: - ar = numpy.asarray(ar, numpy.float32) - - # Make sense of mask consistent with 'internal' convention (0 == - # invalid) - if mask is not None: - mask = 1. - mask - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - armask = ar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - armask = tempar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armask = armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if mask is None and missing is None: - missing = armiss - mask = armask - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = self.inorder - elif rank == 3: - order = "t" + self.inorder - else: - order = "tz" + self.inorder - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to ilon, ilat ... - itim1 = itim2 = 0 - ilon = ilat = -1 - idim = 0 - for i in range(rank - 1, -1, -1): - c = order[i] - if c == 'x': - ilon = idim - elif c == 'y': - ilat = idim - elif c == 'z': - itim1 = idim - elif c == 't': - if rank == 3: - itim1 = idim - else: - itim2 = idim - idim = idim + 1 - - # Map array shape to nloni, nlati, ... - ntim1 = ntim2 = 0 - shape = ar.shape - if ilon == -1: - raise RegridError("Input grid does not have a longitude axis") - if ilat == -1: - raise RegridError("Input grid does not have a latitude axis") - nlati = shape[rank - ilat - 1] - nloni = shape[rank - ilon - 1] - if nlati != self.nlati or nloni != self.nloni: - raise ( - 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % - (nlati, nloni, self.nlati, self.nloni)) - - if itim1 != 0: - ntim1 = shape[rank - itim1 - 1] - if itim2 != 0: - ntim2 = shape[rank - itim2 - 1] - - # Construct the input mask: - # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask - # if no user mask is specified) - # with the 'implicit mask' generated from the missing data, if any - if (mask is None) or len(mask.shape) == 2: - flag2D = 1 - if mask is not None: - assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' - inmask = mask - elif self.inmask is None: - inmask = numpy.ones(self.inshape) - else: - inmask = self.inmask - - if missing is not None: - if rank == 2: - firstslice = ar - elif rank == 3: - firstslice = ar[0] - else: - firstslice = ar[0, 0] - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - firstslice - - missing), - numpy.absolute( - 0.001 * - missing)), - inmask, - 0) - - # If the user mask was specified and is > 2-D, it overrides the grid - # mask - else: - assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' - inmask = mask - flag2D = 0 # 2-D user masks are handled above - # If armask is derived from the input array, it is probably consistent - # with the missing value - don't bother recalculating it - if missing is not None and armask is None: - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - ar - missing), - numpy.absolute( - 0.001 * missing)), - inmask, - 0) - # Cast the mask to float - inmask = inmask.astype(numpy.float32) - if missing is None: - missing = 1.0e20 - - # Cast the input array to 32-bit floats, if necessary - if ar.dtype.char != numpy.float32: - ar = ar.astype(numpy.float32) - - # Malloc return array - outshape = list(shape) - outshape[rank - ilat - 1] = self.nlato - outshape[rank - ilon - 1] = self.nlono - outar = numpy.zeros(tuple(outshape), numpy.float32) - - # Perform the regridding. The return array has the same shape - # as the output array, and is the fraction of the zone which overlaps - # a non-masked zone of the input grid. - amskout = _regrid.rgdarea( - ilon, - ilat, - itim1, - itim2, - ntim1, - ntim2, - nloni, - self.nlono, - nlati, - self.nlato, - flag2D, - missing, - self.londx, - self.lonpt, - self.wtlon, - self.latdx, - self.latpt, - self.wtlat, - inmask, - ar, - outar) - - # Correct the shape of output weights - amskout.shape = outar.shape - - # Set the missing data mask of the output array, if any. - hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) - if hasMissing: - slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) - else: - slabMask = None - - # Combine missing data mask and output grid mask - # Note: slabMask and outmask are Boolean here - if self.outmask is not None: - outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) - if hasMissing: - outmask = numpy.ma.logical_or(outmask, slabMask) - else: - outmask = slabMask - - # Create the result TransientVariable (if input ar is an AbstractVariable) - # or masked array - if inputIsVariable == 1: - for i in range(len(order)): - if order[i] == 'x': - axislist[i] = self.outlon - elif order[i] == 'y': - axislist[i] = self.outlat - result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array( - outar, mask=outmask, fill_value=missing) - - if returnTuple == 0: - return result - else: - return result, amskout - - -class Regridder(Horizontal): - def __init__(self, ingrid, outgrid): - warnings.warn( - "While this will work for now, please note that the Regridder class has been " + - "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + - "Please edit your code accordingly", - Warning) - Horizontal.__init__(self, ingrid, outgrid) - - -def input_mask(ain, type, mask, missing=None): - """ #------------------------------------------------------------------- - # - # purpose: set up the input mask including missing from ain - # - # usage: - # - # passed : - # - # returned: - # - # - #------------------------------------------------------------------------""" - if type != 'h' and type != 'v': - raise ValueError('Mask type must be h or v') - return - - if missing is None: - try: - omit = ain.missing_value - except AttributeError: - omit = 1.0e20 - else: - omit = missing - - # ----- insert 0.0 in mask where array has missing data ------- - - mask_size = len(mask.shape) - data_size = len(ain.shape) - - if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a - - if data_size == 3: # caution: assuming standard order lat-lon varying the fastest - if type == 'h': - reduced = ain[0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[:, :, 0] - elif data_size == 4: - if type == 'h': - reduced = ain[0, 0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[0, :, :, 0] - else: - raise IndexError('Data size is out of range') - return - - amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - else: # 0.0 -> missing in passed mask - - amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - return omit, amskin diff --git a/regrid2/Lib/Lib/mvESMFRegrid.py b/regrid2/Lib/Lib/mvESMFRegrid.py deleted file mode 100644 index 235e1fd5..00000000 --- a/regrid2/Lib/Lib/mvESMFRegrid.py +++ /dev/null @@ -1,483 +0,0 @@ -""" -ESMF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import re -import numpy - -import ESMF -from . import esmf -from . import RegridError -from .mvGenericRegrid import GenericRegrid - -ESMF.Manager(debug=False) -HAVE_MPI = False -try: - from mpi4py import MPI - HAVE_MPI = True -except BaseException: - pass - -# constants -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class ESMFRegrid(GenericRegrid): - """ - Regrid class for ESMF - """ - - def __init__(self, srcGridshape, dstGridshape, dtype, - regridMethod, staggerLoc, periodicity, coordSys, - srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, - dstGridMask=None, hasDstBounds=False, dstGridAreas=None, - ignoreDegenerate=False, - **args): - """ - Constructor - @param srcGridShape tuple source grid shape - @param dstGridShape tuple destination grid shape - @param dtype a valid numpy data type for the src/dst data - @param regridMethod 'linear', 'conserve', or 'patch' - @param staggerLoc the staggering of the field, 'center' or 'corner' - @param periodicity 0 (no periodicity), - 1 (last coordinate is periodic, - 2 (both coordinates are periodic) - @param coordSys 'deg', 'cart', or 'rad' - @param hasSrcBounds tuple source bounds shape - @param hasDstBounds tuple destination bounds shape - @param ignoreDegenerate Ignore degenerate celss when checking inputs - """ - - # esmf grid objects (tobe constructed) - self.srcGrid = None - self.dstGrid = None - self.dtype = dtype - - self.srcGridShape = srcGridshape - self.dstGridShape = dstGridshape - self.ignoreDegenerate = ignoreDegenerate - self.ndims = len(self.srcGridShape) - - self.hasSrcBounds = hasSrcBounds - self.hasDstBounds = hasDstBounds - - self.regridMethod = BILINEAR - self.regridMethodStr = 'linear' - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.regridMethod = CONSERVE - self.regridMethodStr = 'conserve' - elif re.search('patch', regridMethod.lower()): - self.regridMethod = PATCH - self.regridMethodStr = 'patch' - - # data stagger - self.staggerloc = CENTER - self.staggerlocStr = 'center' - if isinstance(staggerLoc, str): - if re.search('vface', staggerLoc.lower(), re.I): - self.staggerloc = VFACE - self.staggerlocStr = 'vcorner' - # there are other staggers we could test here - elif re.search('corner', staggerLoc.lower(), re.I) or \ - re.search('node', staggerLoc.lower(), re.I): - self.staggerloc = CORNER - self.staggerlocStr = 'corner' - # there are other staggers we could test here - - # good for now - unMappedAction = args.get('unmappedaction', 'ignore') - self.unMappedAction = ESMF.UnmappedAction.IGNORE - if re.search('error', unMappedAction.lower()): - self.unMappedAction = ESMF.UnmappedAction.ERROR - - self.coordSys = ESMF.CoordSys.SPH_DEG - self.coordSysStr = 'deg' - if re.search('cart', coordSys.lower()): - self.coordSys = ESMF.CoordSys.CART - self.coordSysStr = 'cart' - elif re.search('rad', coordSys.lower()): - self.coordSys = ESMF.CoordSys.SPH_RAD - self.coordSysStr = 'rad' - - self.periodicity = periodicity - - # masks can take several values in ESMF, we'll have just one - # value (1) which means invalid -# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) -# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) - - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.srcMaskValues = numpy.array([1], dtype=numpy.int32) - self.dstMaskValues = numpy.array([1], dtype=numpy.int32) - else: - self.srcMaskValues = srcGridMask - self.dstMaskValues = dstGridMask - - # provided by user or None - self.srcGridAreas = srcGridAreas - self.dstGridAreas = dstGridAreas - self.maskPtr = None - - # MPI stuff - self.pe = 0 - self.nprocs = 1 - self.comm = None - if HAVE_MPI: - self.comm = MPI.COMM_WORLD - self.pe = self.comm.Get_rank() - self.nprocs = self.comm.Get_size() - - # checks - if self.ndims != len(self.dstGridShape): - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological -dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ - (self.ndims, len(self.dstGridShape)) - raise RegridError(msg) - - # Initialize the grids without data. - self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasSrcBounds) - self.dstGrid = esmf.EsmfStructGrid(dstGridshape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasDstBounds) - - # Initialize the fields with data. - self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.srcFld.field.data[:] = -1 - self.dstFld.field.data[:] = -1 - self.srcAreaField.field.data[:] = 0.0 - self.dstAreaField.field.data[:] = 0.0 - self.srcFracField.field.data[:] = 1.0 - self.dstFracField.field.data[:] = 1.0 - - def setCoords(self, srcGrid, dstGrid, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - globalIndexing=False, **args): - """ - Populator of grids, bounds and masks - @param srcGrid list [[z], y, x] of source grid arrays - @param dstGrid list [[z], y, x] of dstination grid arrays - @param srcGridMask list [[z], y, x] of arrays - @param srcBounds list [[z], y, x] of arrays - @param srcGridAreas list [[z], y, x] of arrays - @param dstGridMask list [[z], y, x] of arrays - @param dstBounds list [[z], y, x] of arrays - @param dstGridAreas list [[z], y, x] of arrays - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - """ - - # create esmf source Grid - self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - - if srcGridMask is not None: - self.srcGrid.setMask(srcGridMask, self.staggerloc) - - if srcBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - # VCORNER for 3D - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - # create destination Grid - self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - if dstGridMask is not None: - self.dstGrid.setMask(dstGridMask) - - if dstBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args (not used) - """ - self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, - dstfield=self.dstFld.field, - src_mask_values=self.srcMaskValues, - dst_mask_values=self.dstMaskValues, - regrid_method=self.regridMethod, - unmapped_action=self.unMappedAction, - ignore_degenerate=True) - - def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): - """ - Regrid source to destination. - When used in parallel, if the processor is not the root processor, - the dstData returns None. - - Source data mask: - - . If you provide srcDataMask in args the source grid will - be masked and weights will be recomputed. - - . Subsequently, if you do not provide a srcDataMask the last - weights will be used to regrid the source data array. - - . By default, only the data are masked, but not the grid. - - @param srcData array source data, shape should - cover entire global index space - @param dstData array destination data, shape should - cover entire global index space - @param rootPe if other than None, then data will be MPI gathered - on the specified rootPe processor - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - @param **args - """ - -# if args.has_key('srcDataMask'): -# srcDataMask=args.get('srcDataMask') - # Make sure with have a mask intialized for this grid. - -# if(self.maskPtr is None): -# if(self.srcFld.field.grid.mask[self.staggerloc] is None): -# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) -# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, -# staggerloc=self.staggerloc) - # Recompute weights only if masks are different. -# if(not numpy.array_equal(self.maskPtr, srcDataMask)): -# self.maskPtr[:] = srcDataMask[:] -# self.computeWeights(**args) - - zero_region = ESMF.Region.SELECT - if 'zero_region' in args.keys(): - zero_region=args.get('zero_region') - - self.srcFld.field.data[:] = srcData.T - self.dstFld.field.data[:] = dstData.T - # regrid - - self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) - - # fill in dstData - if rootPe is None and globalIndexing: - # only fill in the relevant portion of the data - slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) - dstData[slab] = self.dstFld.getData(rootPe=rootPe) - else: - tmp = self.dstFld.field.data.T - if tmp is None: - dstData = None - else: - dstData[:] = tmp - - def getDstGrid(self): - """ - Get the destination grid on this processor - @return grid - """ - return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) - for i in range(self.ndims)] - - def getSrcAreas(self, rootPe): - """ - Get the source grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.srcAreaField.field.get_area() - return self.srcAreaField.field.data - else: - return None - - def getDstAreas(self, rootPe): - """ - Get the destination grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.dstAreaField.field.get_area() - return self.dstAreaField.field.data - else: - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.srcFracField.field.data - else: - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.dstFracField.field.data - else: - return - - def getSrcLocalShape(self, staggerLoc): - """ - Get the local source coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getCoordShape(stgloc) - - def getDstLocalShape(self, staggerLoc): - """ - Get the local destination coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getCoordShape(stgloc) - - def getSrcLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center'): - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getLocalSlab(stgloc) - - def getDstLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center') - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getLocalSlab(stgloc) - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'srcAreaFractions', 'dstAreaFractions', - 'srcAreas', 'dstAreas' - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - oldMethods = {} - oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' - oldMethods['dstAreaFractions'] = 'getDstAreaFractions' - oldMethods['srcAreas'] = 'getSrcAreas' - oldMethods['dstAreas'] = 'getDstAreas' - for entry in 'srcAreaFractions', 'dstAreaFractions', \ - 'srcAreas', 'dstAreas': - if entry in diag: - diag[entry] = eval( - 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T - diag['regridTool'] = 'esmf' - diag['regridMethod'] = self.regridMethodStr - diag['periodicity'] = self.periodicity - diag['coordSys'] = self.coordSysStr - diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/Lib/mvGenericRegrid.py b/regrid2/Lib/Lib/mvGenericRegrid.py deleted file mode 100644 index 2452e9c4..00000000 --- a/regrid2/Lib/Lib/mvGenericRegrid.py +++ /dev/null @@ -1,313 +0,0 @@ -""" -Generic interface to multiple regrid classes. No dependence on cdms2 variables. - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import operator -import numpy - -import regrid2 -import re -from distarray import MultiArrayIter -from functools import reduce - -# used to locate fully masked cells -EPS = 10 * 1.19209e-07 - - -def guessPeriodicity(srcBounds): - """ - Guess if a src grid is periodic - @param srcBounds the nodal src set of coordinates - @return 1 if periodic, warp around, 0 otherwise - """ - res = 0 - if srcBounds is not None: - res = 1 - # assume longitude to be the last coordinate - lonsb = srcBounds[-1] - nlon = lonsb.shape[-1] - dlon = (lonsb.max() - lonsb.min()) / float(nlon) - tol = 1.e-2 * dlon - if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] - ).sum() / float(lonsb.size)) > tol: - # looks like a regional model - res = 0 - return res - - -class GenericRegrid: - """ - Generic Regrid class. - """ - - def __init__(self, srcGrid, dstGrid, - dtype, - regridMethod, - regridTool, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - **args): - """ - Constructor. - @param srcGrid list of numpy arrays, source horizontal coordinates - @param dstGrid list of numpy arrays, destination horizontal coordinate - @param dtype numpy data type for src/dst data - @param regridMethod linear (bi, tri,...) default or conservative - @param regridTool currently either 'libcf' or 'esmf' - @param srcGridMask array of same shape as srcGrid - @param srcBounds list of numpy arrays of same shape as srcGrid - @param srcGridAreas array of same shape as srcGrid - @param dstGridMask array of same shape as dstGrid - @param dstBounds list of numpy arrays of same shape as dstGrid - @param dstGridAreas array of same shape as dstGrid - @param **args additional arguments to be passed to the - specific tool - 'libcf': mkCyclic={True, False}, handleCut={True,False} - 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... - """ - - self.nGridDims = len(srcGrid) - self.regridMethod = regridMethod - - if len(srcGrid) != len(dstGrid): - msg = 'mvGenericRegrid.__init__: mismatch in number of dims' - msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ - (self.nGridDims, len(dstGrid)) - raise regrid2.RegridError(msg) - - # parse the options - if re.search('libcf', regridTool.lower()) or \ - re.search('gsreg', regridTool.lower()): - # LibCF - self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - **args) - elif re.search('esm', regridTool.lower()): - # ESMF - staggerLoc = args.get('staggerLoc', 'center') - if 'staggerLoc' in args: - del args['staggerLoc'] - periodicity = args.get('periodicity', - guessPeriodicity(srcBounds)) - if 'periodicity' in args: - del args['periodicity'] - coordSys = args.get('coordSys', 'deg') - if 'coordSys' in args: - del args['coordSys'] - - # Get the shapes - self.srcGridShape = srcGrid[0].shape - self.dstGridShape = dstGrid[0].shape - self.hasSrcBounds = False - self.hasDstBounds = False - - if srcBounds is not None: - self.hasSrcBounds = True - - if dstBounds is not None: - self.hasDstBounds = True - - self.srcGridAreasShape = None - self.dstGridAreasShape = None - - if srcGridAreas is not None: - self.srcGridAreasShape = srcGridAreas[0].shape - - if dstGridAreas is not None: - self.dstGridAreasShape = dstGridAreas[0].shape - - # Initialize - self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, - dtype=dtype, - regridMethod=regridMethod, - staggerLoc=staggerLoc, - periodicity=periodicity, - coordSys=coordSys, - hasSrcBounds=self.hasSrcBounds, - hasDstBounds=self.hasDstBounds, - srcGridAreasShape=self.srcGridAreasShape, - dstGridAreasShape=self.dstGridAreasShape, - **args) - - self.tool.setCoords(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - srcGridAreas=srcGridAreas, - dstGridMask=dstGridMask, - dstBounds=dstBounds, - dstGridAreas=dstGridAreas, - globalIndexing=True, - **args) - else: - msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, -valid choices are: 'libcf', 'esmf'""" % regridTool - raise regrid2.RegridError(msg) - - def computeWeights(self, **args): - """ - Compute Weights - """ - self.tool.computeWeights(**args) - - def apply(self, srcData, dstData, - rootPe=None, - missingValue=None, - **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param rootPe if other than None, then results will be MPI - gathered - @param missingValue if not None, then data mask will be interpolated - and data value set to missingValue when masked - """ - - # assuming the axes are the slowly varying indices - srcHorizShape = srcData.shape[-self.nGridDims:] - dstHorizShape = dstData.shape[-self.nGridDims:] - - srcDataMaskFloat = None - dstDataMaskFloat = None - dstMask = None - if missingValue is not None: - srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) - dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) - - nonHorizShape = srcData.shape[: -self.nGridDims] - - if len(nonHorizShape) == 0: - - # - # no axis... just call apply - # - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (srcData == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later - indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), - dtype=srcData.dtype) - - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, **args) - if re.search('conserv', self.regridMethod.lower(), re.I): - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) - - # Initialize output to missin_value - dstData[:] = missingValue - # interpolate the data - self.tool.apply(indata, dstData, rootPe=rootPe, - globalIndexing=True, **args) - - # add missing values - dstData *= (1 - dstMask) - dstData += dstMask * missingValue - - else: - # no masking, just interpolate the data - self.tool.apply(srcData, dstData, rootPe=rootPe, - globalIndexing=True, **args) - else: - - nonHorizShape2 = dstData.shape[: -self.nGridDims] - if not numpy.all(nonHorizShape2 == nonHorizShape): - msg = 'mvGenericRegrid.apply: axes detected ' - msg += 'but %s != %s ' % (str(nonHorizShape2), - str(nonHorizShape)) - raise regrid2.RegridError(msg) - - # - # iterate over all axes - # - - # create containers to hold input/output values - # (a copy is essential here) - zros = '[' + ('0,' * len(nonHorizShape)) + '...]' - indata = numpy.array(eval('srcData' + zros)) - outdata = numpy.array(eval('dstData' + zros)) - - # now iterate over all non lat/lon coordinates - for it in MultiArrayIter(nonHorizShape): - - indices = it.getIndices() - slce = '[' - slce += reduce(operator.add, ['%d,' % i for i in indices]) - slce += '...]' - indata = eval('srcData' + slce) - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (indata == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later -# indata *= (1 - (srcDataMaskFloat == 1)) - -# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, - srcDataMask=(1 - srcDataMaskFloat), **args) - - if re.search('conserv', self.regridMethod.lower(), re.I): - # cell interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - # nodal interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 0), numpy.int32) - - # interpolate the data, using the appropriate tool - self.tool.apply(indata, outdata, rootPe=rootPe, - globalIndexing=True, - srcDataMask=srcDataMaskFloat, **args) - -# import vcs -# pp = vcs.init() -# pp.plot(indata) -# pp.interact() -# pp.clear() -# pp.plot(outdata) -# pp.interact() -# pp.clear() - # apply missing value contribution - if missingValue is not None: - # add mask contribution - outdata *= (1 - dstMask) - outdata += dstMask * missingValue - - # fill in dstData - exec('dstData' + slce + ' = outdata') - - def getDstGrid(self): - """ - Return the destination grid, may be different from the dst grid provided - to the constructor due to domain decomposition - @return local grid on this processor - """ - return self.tool.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe=None): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - entries are tool dependent - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/Lib/mvLibCFRegrid.py b/regrid2/Lib/Lib/mvLibCFRegrid.py deleted file mode 100644 index 30c5f4bf..00000000 --- a/regrid2/Lib/Lib/mvLibCFRegrid.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -LibCF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" - -from regrid2 import gsRegrid -from regrid2 import GenericRegrid - - -class LibCFRegrid(GenericRegrid): - """ - """ - - def __init__(self, srcGrid, dstGrid, srcGridMask=None, - srcBounds=None, **args): - """ - Constructor - @param srcGrid array - @param dstGrid array - @param srcBounds cell boundaries - @param **args keyword arguments, eg mkCyclic, handleCut, ... - to be passed to gsRegrid - """ - self.regridMethodStr = 'linear' - self.mkCyclic = args.get('mkCyclic', False) - self.handleCut = args.get('handleCut', False) - self.verbose = args.get('verbose', False) - self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, - src_bounds=srcBounds, - mkCyclic=self.mkCyclic, - handleCut=self.handleCut) - if srcGridMask is not None: - self.regridObj.setMask(srcGridMask) - - # min resolution, required in order to set the tolerance (tolpos) - self.delta = float('inf') - for i in range(len(dstGrid)): - coordMin = dstGrid[i].min() - coordMax = dstGrid[i].max() - n = max(dstGrid[i].shape) - self.delta = min(self.delta, (coordMax - coordMin) / float(n)) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args arguments to be passed to gsRegrid, e.g. - nitermax, tolpos, ... - """ - nitermax = args.get('nitermax', 20) - # make tolpos relative to the min cell size - tolpos = args.get('tolpos', 0.01) * self.delta - self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) - - def apply(self, srcData, dstData, missingValue=None, **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param missingValue value that should be set for points falling outside - the src domain, pass None if these should not be - touched. - """ - - self.regridObj.apply(srcData, dstData, missingValue) - - def getSrcGrid(self): - """ - Get the grid of the src data (maybe larger than the - dst grid passed to the constructor due to column/row - padding) - @return grid - """ - return self.regridObj.getSrcGrid() - - def getDstGrid(self): - """ - Get the grid of the dst data - @return grid - """ - return self.regridObj.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'numDstPoints' and 'numValid' - @param rootPe not used - """ - for entry in 'numDstPoints', 'numValid': - if entry in diag: - meth = 'get' + entry[0].upper() + entry[1:] - diag[entry] = eval('self.regridObj.' + meth + '()') - diag['regridTool'] = 'libcf' - diag['regridMethod'] = self.regridMethodStr - diag['handleCut'] = self.handleCut - diag['mkCyclic'] = self.mkCyclic - diag['verbose'] = self.verbose diff --git a/regrid2/Lib/Lib/mytest.py b/regrid2/Lib/Lib/mytest.py deleted file mode 100644 index e91d1361..00000000 --- a/regrid2/Lib/Lib/mytest.py +++ /dev/null @@ -1,2 +0,0 @@ -import ESMF # noqa -from .mvESMFRegrid import ESMFRegrid # noqa diff --git a/regrid2/Lib/Lib/pressure.py b/regrid2/Lib/Lib/pressure.py deleted file mode 100644 index fb79a9e2..00000000 --- a/regrid2/Lib/Lib/pressure.py +++ /dev/null @@ -1,490 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by -import cdms2 -import numpy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import copy - - -class PressureRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along - # the pressure dimension only. - # - # PROCEDURE: Step One: - # Make an instance of class PressureRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, axisIn, axisOut): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, levIn, levOut): - # - # PROCEDURE: - # - # The user must assemble two pieces of information: - # - # axisIn - the input level axis - # - # axisOut - the output level axis - # - # USAGE: - # - # To make an instance preparing for a regrid along the level dimension pnly, type - # - # r = PressureRegridder(levIn, levOut) - # - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.axisIn = axisIn - self.axisOut = axisOut - self.nlevi = len(axisIn) - self.nlevo = len(axisOut) - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the pressure regridder function. - ar is the input array, a variable, masked array, or numpy array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = ar.getAxisList() - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # Set missing value - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 3: - order = "zyx" - elif rank == 4: - order = "tzyx" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to positionIn - positionIn = [None] * 4 - for i in range(len(order)): - if order[i] == 'x': - positionIn[0] = i - elif order[i] == 'y': - positionIn[1] = i - elif order[i] == 'z': - positionIn[2] = i - if inputIsVariable: - axislist[i] = self.axisOut - else: - positionIn[3] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - if inputIsVariable == 1: - result = cdms2.createVariable(outar, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, - logYes='yes', positionIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, - # dataout along the level dimension only. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using - # the value passed in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence longitude, - # latitude, level and time. Longitude, latitude and level are - # required. If time is missing submit None in its slot in the - # tuple. Notice that the length of the tuple is always four. - # - # Explicitly, in terms of the shape of dataIn as returned by Python's shape function - # - # positionIn[0] contains the position of longitude in dataIn - # positionIn[1] contains the position of latitude in dataIn - # positionIn[2] contains the position of level in dataIn or None - # positionIn[3] contains the position of time in dataIn or None - # - # As examples: - # If the C order shape of 4D data is - # (number of longitudes, number of times, number of levels, - # number of latitudes) - # submit - # (0, 3, 2, 1) - # - # If the C order shape of 3D data is - # (number of longitudes, number of times, number oflatitudes) - # submit - # (0, 2, 1, None) - # - # Send in None if the shape is a subset of (time, level, - # latitude, longitude) which is evaluated as follows: - # 3D -- code assumes (2,1,0,None) - # 4D -- code assumes (3,2,1,0) - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last - # resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # ----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - # --- evaluate positionIn ---- - - # --- make standard positionIn as a check---- - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - for n in range(numberDim, 4): # fill end of list with Nones - positionList.append(None) - - positionCheck = tuple(positionList) - - standardPosition = 0 # transpose required - - if positionIn is None: # construct the default positionIn tuple - positionIn = positionCheck - standardPosition = 1 # no need for a transpose with this data - else: - if positionIn == positionCheck: # compare to the standard - standardPosition = 1 # no need for a transpose with this data - - if len(positionIn) != 4: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' - sendmsg(msg) - raise TypeError - - # transpose data to the standard order (t,z,y,x) - if standardPosition == 0: - - newOrder, inverseOrder = checkorder(positionIn) - - # transpose data to standard order (t,z,y,x) - dataIn = numpy.transpose(dataIn, newOrder) - dataIn = numpy.array( - dataIn.astype( - numpy.float32), - numpy.float32) # make contiguous - - # set dimension sizes and check for consistency - - if positionIn[0] is not None: - self.nlon = (dataShape[positionIn[0]]) - else: - self.nlon = 0 - if positionIn[1] is not None: - self.nlat = (dataShape[positionIn[1]]) - else: - self.nlat = 0 - if positionIn[2] is not None: - if self.nlevi != (dataShape[positionIn[2]]): - msg = 'Level size is inconsistent with input data' - sendmsg(msg) - raise ValueError - if positionIn[3] is not None: - self.ntime = (dataShape[positionIn[3]]) - else: - self.ntime = 0 - - # allocate memory for dataOut -- the array with new number of levels - - outList = list(dataIn.shape) - - for i in range(len(outList)): - if outList[i] == self.nlevi: - outList[i] = self.nlevo - break - - dataOut = numpy.zeros( - tuple(outList), - numpy.float32) # memory for aout - - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.axisIn[:].astype(numpy.float64) - levOut = self.axisOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlat, - self.nlon, - self.ntime, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - dataIn, - dataOut) - - # if no missing do not pass None - if missingMatch == 'none': - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - if standardPosition == 0: - # transpose data to original order - dataOut = numpy.transpose(dataOut, inverseOrder) - dataOut = numpy.array( - dataOut.astype( - numpy.float32), - numpy.float32) # make contiguous - - if missingValueOut is not None: # set the missing value in data to missingValueOut - - if missingMatch == 'greater': - if missingValueIn > 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.greater( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'equal': - missing = missingValueIn - dataOut = numpy.where( - numpy.equal( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'less': - if missingValueIn < 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.less( - dataOut, - missing), - missingValueOut, - dataOut) - - return dataOut - - -def checkorder(positionIn): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the tuples for transposing the data to standard dimension order and the - # inverse for transposing it back to the original dimension order - # - # usage: newOrder, inverseOrder = checkorder(positionIn) - # - # passed: positionIn -- array with location of longitude, latitude. level and time respectively - # in the sense of the python shape of the data - # - # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) - # inverseOrder -- tuple to transpose data to back to the original order - # - #----------------------------------------------------------------------------------------------""" - - # remove the None values from positionIn and reverse the order - - reducedPosition = [] - for item in positionIn: - if item is not None: - reducedPosition.append(item) - reducedPosition.reverse() - - # make the newOrder tuple - - newOrder = tuple(reducedPosition) - - # ----- Determine the inverse to this new order for use in mathtogeo ----- - - xform = [] - for i in range(len(newOrder)): - xform.append([newOrder[i], i]) - xform.sort() - - inverse_shapelist = [] - for item in xform: - inverse_shapelist.append(item[1]) - inverseOrder = tuple(inverse_shapelist) - - return newOrder, inverseOrder - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None diff --git a/regrid2/Lib/Lib/scrip.py b/regrid2/Lib/Lib/scrip.py deleted file mode 100644 index 5a052700..00000000 --- a/regrid2/Lib/Lib/scrip.py +++ /dev/null @@ -1,447 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -#from . import _scrip -import regrid2._scrip as _scrip -from .error import RegridError -import numpy -from functools import reduce - -"""Regrid support for nonrectangular grids, based on the SCRIP package.""" - - -class ScripRegridder: - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - self.outputGrid = outputGrid - self.remapMatrix = remapMatrix - self.sourceAddress = sourceAddress - self.destAddress = destAddress - self.inputGrid = inputGrid - self.sourceFrac = sourceFrac - self.destFrac = destFrac - - def __call__(self, input): - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - # this expects contiguous arrays - if input.iscontiguous() is False: - input = input.ascontiguous() - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - - # Regrid - output = self.regrid(input) - - # Reshape output and restore input shape - input.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - def getOutputGrid(self): - return self.outputGrid - - def getInputGrid(self): - return self.inputGrid - - def getSourceFraction(self): - return self.sourceFrac - - def getDestinationFraction(self): - return self.destFrac - - -class ConservativeRegridder(ScripRegridder): - """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' - is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length - as the output grid size, with values: - 1.0 for normalize="fracarea", - grid_frac for normalize="destarea", or - grid_frac*grid_area for normalize="none". - sourceArea is the area of the source grid cells - destArea is the area of the destination grid cells - """ - - def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, - sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): - if normalize not in ["fracarea", "destarea", "none"]: - raise RegridError("Invalid normalization option: %s" % normalize) - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - self.normalize = normalize - self.normal = None - self.sourceArea = sourceArea - self.destArea = destArea - - def getSourceArea(self): - return self.sourceArea - - def getDestinationArea(self): - return self.destArea - - def regrid(self, input): - if self.normal is None: - # print "On input, num_links = %d"%(len(self.sourceAddress)) - # print "On input, nextra = %d"%(input.shape[0]) - # print "On input, ninput = %d"%(input.shape[1]) - # print "On input, noutput = %d"%(self.outputGrid.size()) - # print "On input, shape(input) = %s"%`input.shape` - # print "On input, shape(output) = %s"%`self.outputGrid.shape` - # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` - # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` - # print "On input, shape(dst_address) = - # %s"%`self.destAddress.shape` - result = _scrip.conserv_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - else: - result = _scrip.conserv_regrid_normal( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - self.normal) - return result - - -class BilinearRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.bilinear_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -class BicubicRegridder(ScripRegridder): - """Bicubic regrid.""" - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def __call__(self, input, gradLat, gradLon, gradLatlon): - """gradLat = df/di - gradLon = df/dj - gradLatlon = d(df)/(di)(dj) - """ - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - if (gradLat.shape != input.shape or - gradLon.shape != input.shape or - gradLatlon.shape != input.shape): - raise RegridError( - "All input arrays must have shape %s" % - repr( - input.shape)) - - if (not isinstance(gradLat, type(input)) or - not isinstance(gradLon, type(input)) or - not isinstance(gradLatlon, type(input))): - raise RegridError( - "All input arrays must have type %s" % - repr( - type(input))) - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - gradLat = gradLat.subSlice() - gradLon = gradLon.subSlice() - gradLatlon = gradLatlon.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - gradLat = gradLat.filled() - gradLon = gradLon.filled() - gradLatlon = gradLatlon.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - gradLat.shape = newshape - gradLon.shape = newshape - gradLatlon.shape = newshape - - # Regrid - output = _scrip.bicubic_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - gradLat, - gradLon, - gradLatlon) - - # Reshape output and restore input shape - input.shape = oldshape - gradLat.shape = oldshape - gradLon.shape = oldshape - gradLatlon.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - -class DistwgtRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.distwgt_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -def readRegridder(fileobj, mapMethod=None, checkGrid=1): - """Read a regridder from an open fileobj. - mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method - defined in the file. - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. - """ - - if isinstance(fileobj, str): - fileobj = cdms2.open(fileobj) - elif not isinstance(fileobj, cdms2.dataset.CdmsFile): - raise RegridError( - "fileobj arguments must be a cdms2 file or a string pointing to a file") - - if mapMethod is None: - mapString = fileobj.map_method.strip().lower() - if mapString[0:12] == "conservative": - mapMethod = "conservative" - elif mapString[0:8] == "bilinear": - mapMethod = "bilinear" - elif mapString[0:7] == "bicubic": - mapMethod = "bicubic" - elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": - mapMethod = "distwgt" - else: - raise RegridError("Unrecognized map method: %s" % mapString) - - convention = 'SCRIP' - if list(fileobj.variables.keys()).count('S'): - convention = 'NCAR' - if convention == 'SCRIP': - remapMatrix = fileobj('remap_matrix').filled() - srcAddress = fileobj('src_address').filled() - dstAddress = fileobj('dst_address').filled() - srcfrac = fileobj('src_grid_frac') - dstfrac = fileobj('dst_grid_frac') - else: - remapMatrix = fileobj('S').filled() - srcAddress = fileobj('col').filled() - dstAddress = fileobj('row').filled() - srcfrac = fileobj('frac_a') - dstfrac = fileobj('frac_b') - ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) - outgrid = fileobj.readScripGrid( - whichGrid="destination", - checkGrid=checkGrid) - - if mapMethod == "conservative": - if convention == 'SCRIP': - srcarea = fileobj('src_grid_area') - dstarea = fileobj('dst_grid_area') - else: # NCAR stuff - if "S2" in list(fileobj.variables.keys()): - remapMatrix = fileobj("S2") - sh = list(remapMatrix.shape) - if len(sh) == 2 and sh[-1] == 2: - sh[-1] = 1 - S = fileobj("S").filled() - S.shape = sh - remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) - srcarea = fileobj('area_a') - dstarea = fileobj('area_b') - regridder = ConservativeRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac, - sourceArea=srcarea, - destArea=dstarea) - elif mapMethod == "bilinear": - regridder = BilinearRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "bicubic": - regridder = BicubicRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "distwgt": - regridder = DistwgtRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - else: - raise RegridError("Unrecognized map method: %s" % mapMethod) - - return regridder diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index cf23b45d..23cadb08 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -3,7 +3,7 @@ import cdms2 import numpy import copy -#from . import _regrid +# from . import _regrid import regrid2._regrid as _regrid from .error import RegridError diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 39b8044f..b2efb312 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -94,6 +94,8 @@ def setCells(self, cellIndices, cellTypes, connectivity, .. figure:: /images/ESMF.jpg :scale: 55% :alt: + + :: 3 4-------------3 /\ | | / \ | | diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 685f7a5f..53c42ff8 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -1,7 +1,7 @@ -#!/usr/bin/env python -#Alex Pletzer and Dave Kindig, Tech-X (2011) -#This code is provided with the hope that it will be useful. -#No guarantee is provided whatsoever. Use at your own risk. +# !/usr/bin/env python +# Alex Pletzer and Dave Kindig, Tech-X (2011) +# This code is provided with the hope that it will be useful. +# No guarantee is provided whatsoever. Use at your own risk. """ Regridding of curvilinear structured grids diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index baae5831..910ad9bf 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -2,7 +2,7 @@ import numpy import copy -#from . import _regrid +# from . import _regrid import regrid2._regrid as _regrid from .error import RegridError import warnings @@ -104,7 +104,7 @@ def __call__(self, ar, missing=None, order=None, missing is the missing data value, if any. - + mask is either 2-D or the same shape as ar. diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 908034e2..18c86989 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -1,7 +1,7 @@ -#This code is provided with the hope that it will be useful. -#No guarantee is provided whatsoever. Use at your own risk. +# This code is provided with the hope that it will be useful. +# No guarantee is provided whatsoever. Use at your own risk. # -#David Kindig and Alex Pletzer, Tech-X Corp. (2012) +# David Kindig and Alex Pletzer, Tech-X Corp. (2012) """ diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 0ae24e53..22c36127 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -1,7 +1,7 @@ -#This code is provided with the hope that it will be useful. -#No guarantee is provided whatsoever. Use at your own risk. +# This code is provided with the hope that it will be useful. +# No guarantee is provided whatsoever. Use at your own risk. # -#David Kindig and Alex Pletzer, Tech-X Corp. (2012) +# David Kindig and Alex Pletzer, Tech-X Corp. (2012) """ Generic interface to multiple regrid classes. No dependence on cdms2 variables. diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py index 563cc193..c0e88b39 100644 --- a/regrid2/Lib/mvLibCFRegrid.py +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -1,7 +1,7 @@ -#This code is provided with the hope that it will be useful. -#No guarantee is provided whatsoever. Use at your own risk. +# This code is provided with the hope that it will be useful. +# No guarantee is provided whatsoever. Use at your own risk. # -#David Kindig and Alex Pletzer, Tech-X Corp. (2012) +# David Kindig and Alex Pletzer, Tech-X Corp. (2012) """ diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py index fb79a9e2..a94fa3a7 100644 --- a/regrid2/Lib/pressure.py +++ b/regrid2/Lib/pressure.py @@ -1,7 +1,7 @@ # Automatically adapted for numpy.oldnumeric Aug 02, 2007 by import cdms2 import numpy -#from . import _regrid +# from . import _regrid import regrid2._regrid as _regrid from .error import RegridError import copy diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 6f451be2..56c9b0a6 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -1,7 +1,7 @@ # Automatically adapted for numpy.oldnumeric Aug 02, 2007 by import cdms2 -#from . import _scrip +# from . import _scrip import regrid2._scrip as _scrip from .error import RegridError import numpy @@ -376,7 +376,7 @@ def readRegridder(fileobj, mapMethod=None, checkGrid=1): is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method defined in the file. - + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. From cdff13969e44e351799547aa81b0d4d838b4ed58 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 27 Jun 2018 14:17:08 -0700 Subject: [PATCH 193/239] Changes made to all --- docs/source/manual/cdms_5.rst | 6 +- docs/source/manual/cdms_appendix.rst | 97 ++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 1c6db95a..f30e6bbe 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -152,8 +152,8 @@ where: - For example, if array is three-dimensional, the axes are (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x). - - (Note that the t dimension need have no connection with time; any - spatial axis can be mapped to any plot dimension.) + **Note:** that the t dimension need have no connection with time; any + spatial axis can be mapped to any plot dimension.) - For a graphics method which is two-dimensional, such as boxfill, the y-axis is plotted on the horizontal, and the x-axis on the vertical. @@ -163,7 +163,7 @@ where: - If it is non-rectangular, the meshfill graphics method is used. - - Note that some plot keywords apply only to rectangular grids only. + **Note:** that some plot keywords apply only to rectangular grids only. - args are optional positional arguments: diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index d74a905e..235ca150 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -67,13 +67,28 @@ Release 4.0 CDMS version 4.0 adds support for nonrectangular grids: -- The following grid classes were added: AbstractHorizontalGrid, - AbstractCurve-Grid, AbstractGenericGrid, DatasetCurveGrid, - FileCurveGrid, TransientCurve-Grid, DatasetGenericGrid, - FileGenericGrid, and TransientGenericGrid. -- The following axis classes were added: AbstractCoordinateAxis, - AbstractAuxAxis1D, AbstractAxis2D, DatasetAuxAxis1D, FileAuxAxis1D, - TransientAuxAxis1D, DatasetAxis2D, FileAxis2D, and TransientAxis2D. +- The following grid classes were added: + * AbstractHorizontalGrid + * AbstractCurve-Grid + * AbstractGenericGrid + * DatasetCurveGrid + * FileCurveGrid + * TransientCurve-Grid + * DatasetGenericGrid + * FileGenericGrid + * TransientGenericGrid. + +- The following axis classes were added: + * AbstractCoordinateAxis + * AbstractAuxAxis1D + * AbstractAxis2D + * DatasetAuxAxis1D + * FileAuxAxis1D, + * TransientAuxAxis1D + * DatasetAxis2D + * FileAxis2D + * TransientAxis2D. + - The getMesh and clone methods were added for grids. - An interface to the SCRIP package was added. @@ -112,8 +127,16 @@ Details AbstractVariable '''''''''''''''' -- Functions getDomain, getSlice, rank, regrid, setMissing, size, - subRegion, and subSlice were added. +- The following functions were added: + * getDomain + * getSlice + * rank + * regrid + * setMissing + * size + * subRegion + * subSlice + - The functions getRegion, getSlice, getValue, and the slice operators all return an instance of MV, a masked array. Singleton dimensions are squeezed. @@ -123,17 +146,28 @@ AbstractVariable latitude, and longitude. - The input functions have the keyword squeeze. - AbstractVariable inherits from class Slab. The following functions - previously available in module cu are Slab methods: getattribute, - setattribute, listdimattributes, getdimattribute, listall, and info. + previously available in module cu are Slab methods: + * getattribute + * setattribute + * listdimattributes + * getdimattribute + * listall, and info - AbstractVariable implements arithmetic functions, astype. - The write function was added. AbstractAxis '''''''''''' -- The functions asComponentTime, asRelativeTime, clone, getAxisIds, - getAxis-Index, getAxisList, getAxisListIndex, mapIntervalExt were - added. +- The following functions were added: + * asComponentTime + * asRelativeTime + * clone + * getAxisIds + * getAxis-Index + * getAxisList + * getAxisListIndex + * mapIntervalExt + - subaxis was renamed subAxis for consistency. - Generalized wraparound was implemented, to handle multiple cycles, reversing, and negative strides. By default, coordinate intervals are @@ -153,7 +187,10 @@ Dataset cdms module ''''''''''' -- The functions asVariable, isVariable, and createVariable were added. +- The following functions were added: + * asVariable + * isVariable + * createVariable - The function setAutoReshapeMode was removed. It is replaced by the squeeze option for all I/O functions. @@ -224,10 +261,11 @@ Slab Methods * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." "Various", "``getattribute(name)``", "Get the value of an attribute. * ``name`` is the string name of the attribute. - The following special names can always be used: - ``filename``, ``comments``, ``grid_name``, ``grid_type``. ``time_statistic``, ``long_name``, ``units``." + * The following special names can always be used: + ``filename``, ``comments``, ``grid_name``, ``grid_type``. ``time_statistic``, ``long_name``, ``units``." "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. - * If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." + * If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. + * Output is sent to ``device``." "List", "``listall(all=None)``", "Print slab information. * If ``all`` is nonzero, dimension values, weights, and bounds are also printed." "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. @@ -261,17 +299,21 @@ cuDataset Methods "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. * ``dname`` is the string name of an axis. ``vname`` is a string variable name. * The default is the variable name set by ``default_variable.``" - "Various", "``getattribute (vname, attribute``)", "Get an attribute value. ``vname`` is a string variable name. attribute is the string attribute name." + "Various", "``getattribute (vname, attribute``)", "Get an attribute value. + * ``vname`` is a string variable name. + * attribute is the string attribute name." "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. * ``dname`` is the string name of an axis. * ``vname`` is a string variable name. * The default is the variable name set by ``default_variable``." - "Various", "``getglobal (attribute)``", "Get the value of the global attribute. attribute is the string attribute name." + "Various", "``getglobal (attribute)``", "Get the value of the global attribute. + * attribute is the string attribute name." "Variable", "``getslab (vname, \*args)``", "Read data for a variable. * ``vname`` is the string name of the variable. - * ``args`` is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be: - * ':' or None -- select the entire dimension - * Ellipsis -- select entire dimensions between the ones given. + * ``args`` is an argument list corresponding to the dimensions of the variable. + * Arguments for each dimension can be: + * ':' or None -- select the entire dimension + * Ellipsis -- select entire dimensions between the ones given. * a pair of successive arguments giving an interval in world coordinates. * a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" "List", "``listall (vname=None, all=None)``", "Get info about data from the file. @@ -287,11 +329,14 @@ cuDataset Methods "List", "``listvariable ()``", "Return a list of the variables in the file." "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. * ``vname`` is the string name of the variable. - * If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + * If all is non-zero, dimension values, weights, and bounds are returned as well. + * Output is sent to device." "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. - * ``vname`` is the string name of the variable. Output is sent to device." + * ``vname`` is the string name of the variable. + * Output is sent to device." "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. - * ``vname`` is the string name of the variable. Output is sent to device." + * ``vname`` is the string name of the variable. + * Output is sent to device." "None", "``showglobal (device=sys.stdout)``", "Print the global file attributes. Output is sent to device." "None", "``showvariable (device=sys.stdout)``", "Print the list of variables in the file." From 7dfb910760dafaa6c0b6e9d4ae03e4432f64268c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 28 Jun 2018 15:19:16 -0700 Subject: [PATCH 194/239] Changes made to Sections 2, 6 and Appendix --- docs/source/manual/cdms_2.rst | 166 ++++++++++++++++++--------- docs/source/manual/cdms_6.rst | 5 +- docs/source/manual/cdms_appendix.rst | 15 ++- 3 files changed, 120 insertions(+), 66 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 71f3731b..4b16016e 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -158,11 +158,13 @@ Cdms Module Functions * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``: - Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + Create an equal-area latitude axis. + * The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: - Create a Gaussian latitude axis. Axis values range from north to south. + Create a Gaussian latitude axis.\ + * Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: @@ -189,7 +191,9 @@ Cdms Module Functions * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: - Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + Create a uniform rectilinear grid. + * The grid is not associated with a file or dataset. + * The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. * ``deltaLat`` is the increment between latitudes. @@ -199,15 +203,21 @@ Cdms Module Functions * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: - Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + Create a uniform latitude axis. + * The axis boundaries are at the midpoints of the axis values. + * The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``: - Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + Create a zonal grid. + * The output grid has the same latitude as the input grid, and a single longitude. + * This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: - Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + Create a uniform longitude axis. + * The axis boundaries are at the midpoints of the axis values. + * The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes * ``deltaLon`` is the increment between longitudes." @@ -299,7 +309,7 @@ external attributes are written, but not the internal attributes. Attributes Common to All CDMS Objects ------------------------------------- -.. csv-table:: Attributes common to all CDMS objects +.. csv-table:: :header: "Type", "Name", "Definition" :widths: 20, 20, 50 @@ -318,7 +328,7 @@ Getting and Setting Attributes * If the attribute is not already in the database, it is created as an external attribute. * Internal attributes cannot be created, only referenced." "various", "``obj.attname = value`` - St an internal or external attribute value. + Set an internal or external attribute value. * If the attribute is external, it is written to the database." @@ -382,7 +392,9 @@ CoordinateAxis Constructors "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. * ``name`` is the string ``name`` of the ``Axis``. - * ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. + * ``ar`` is a 1-D data array which defines the ``Axis`` values. + * It may have the value ``None`` if an unlimited axis is being defined. + * At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either: * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or @@ -413,15 +425,19 @@ CoordinateAxis Methods "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. * If ``copyData`` is 1 (the default) the data itself is copied." "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. - * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If persistent is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. - * If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If persistent is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. * ``modulo`` is the modulus value. Any given axis value * ``x`` is treated as equivalent to ``x + modulus``. - * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If ``persistent`` is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. - * If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. + * If ``persistent`` is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary. * ``calendar`` is defined as in ``getCalendar()``." "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: * ``Axis``: ``(n,2)`` @@ -438,7 +454,6 @@ CoordinateAxis Methods * ``cdtime.Calendar360``: a year is 360 days * ``None``: no calendar can be identified **Note** If the axis is not a time axis, the global, file-related calendar is returned." - "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true if the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true if the axis is a level axis." @@ -461,11 +476,13 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. - **Note:** If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." + * If ``persistent`` is ``True``, the external file or dataset (if any) is modified. + * By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: * ``axis.topology == 'circular'``, or - * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + * ``axis.topology`` is undefined, and the axis is a longitude. + * The default cycle for circular axes is 360.0" "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms: @@ -488,7 +505,9 @@ CoordinateAxis Methods, Additional to CoordinateAxis * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. * otherwise the interval wraps around the axis endpoint. * see also: ``mapinterval``, ``variable.subregion()``" - "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." + "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. + * the stride ``k`` can be positive or negative. + * wraparound is supported for longitude dimensions or those with a modulus attribute." CoordinateAxis Slice Operators ------------------------------ @@ -610,11 +629,13 @@ CdmsFile Methods Copy Axis, Grid :widths: 10, 30, 80 :align: left - "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. + * The returned object is persistent: it can be used to write axis data to or read axis data from the file. * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. * ``axis`` is the axis object to be copied. * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." - "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. + "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. + * The returned grid is persistent. * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. * ``grid`` is the grid object to be copied. * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." @@ -627,24 +648,28 @@ CdmsFile Methods Create Axis, RectGrid and Variable :widths: 10, 30, 80 :align: left - "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. - * ``id`` is an alphanumeric string identifier, containing no blanks. - * ``ar`` is the one-dimensional axis array. - * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. + * This is a persistent object which can be used to read or write axis data to the file. + * ``id`` is an alphanumeric string identifier, containing no blanks. + * ``ar`` is the one-dimensional axis array. + * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. + * This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. * ``lat`` is a latitude axis in the file. * ``lon`` is a longitude axis in the file. * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). * ``type`` is one of ``'gaussian'``,\ ``'uniform'``,\ ``'equalarea'`` , or ``'generic'``. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. - * ``id`` is a String name which is unique with respect to all other objects in the file. - * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. - * ``axes`` is a list of Axis and/or Grid objects. - * ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. - * ``var`` is the ``Variable`` to be copied. - * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. + "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. + * This is a persistent object which can be used to read or write variable data to the file. + * ``id`` is a String name which is unique with respect to all other objects in the file. + * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. + * ``axes`` is a list of Axis and/or Grid objects. + * ``fill_value`` is the missing value (optional)." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. + * An error is raised if a variable of the same name exists in the file. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." @@ -657,9 +682,10 @@ CdmsFile Methods Read CurveGrid, Generic-Grid :widths: 10, 30, 80 :align: left - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid (self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. - * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. - * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid (self,whichGrid='destination', check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. + * The file can be a SCRIP grid file or remapping file. + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." @@ -673,7 +699,8 @@ CdmsFile Methods Write Variable :align: left - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable. + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. + * The return value is the associated file variable. * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. @@ -1143,7 +1170,10 @@ Dataset Constructors :widths: 50, 80 :align: left - "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#id3>`__ . ``openDataset`` is a synonym for ``open``" + "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. + * Returns a Dataset object. + * mode is one of the indicators listed in `Open Modes <#id3>`__ . + * ``openDataset`` is a synonym for ``open``" Open Modes @@ -1189,7 +1219,8 @@ Dataset Methods * gets the axis named time, equivalent to ``t=f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. + "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. + * This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. * ``lat`` is a latitude axis in the dataset. * ``lon`` is a longitude axis in the dataset. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). @@ -1202,11 +1233,12 @@ Dataset Methods "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset. * ``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile. - + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. + * The dataset can be a SCRIP grid file or remappingfile. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. - - * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. + * Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1407,7 +1439,8 @@ HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." "Tuple", "``getBounds()``", "Get the grid boundary arrays. - * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + * Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray. + The shape of latitudeArray and longitudeArray depend on the type of grid: * For rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). * For curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). @@ -1418,8 +1451,11 @@ HorizontalGrid Methods * By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." "Axis", "``getLongitude()``", "Get the latitude axis of this grid." - "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." - "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." + "Axis", "``getMask()``", "Get the mask array of this grid, if any. + * Returns a 2-D Numpy array, having the same shape as the grid. + * If the mask is not explicitly defined, the return value is ``None``." + "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method. + * If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. * ``lonBounds`` is defined similarly for the longitude array. @@ -1483,7 +1519,8 @@ RectGrid Methods, Additional to HorizontalGrid Methods * Also see the function ``area_weights`` in module ``pcmdi.weighting``." "None", "``setType(gridtype)``", "Set the grid type. * ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range ``latStart : latStop]`` and longitude index range ``[lonStart : lonStop]``. + * Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. **Example:** @@ -1492,8 +1529,9 @@ RectGrid Methods, Additional to HorizontalGrid Methods * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. **Note:** The result grid is not associated with any file or dataset." - "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. - **Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. + * The grid mask is also transposed. + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1576,15 +1614,22 @@ Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#id12>`_ " - "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. + * Singleton dimensions are 'squeezed' out. + * Data is returned in the physical ordering defined in the dataset. + * The forms of the slice operator are listed in `Variable Slice Operators <#id12>`_ " + "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. + * The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. + * The result is a transient variable, unless raw=1 keyword is specified. See `Selectors <#id14>`_." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." - "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." + "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. + * Typecodes are as for MV, MV2, and Numpy modules." "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. * If copyData is 1 (the default) the variable data is copied as well. * If copyData is 0, the result transient variable shares the original transient variables data array." - "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time. + "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. + * The variable should be a function of latitude, level, and (optionally) time. * ``newLevel`` is an axis of the result pressure levels. * ``newLatitude`` is an axis of the result latitudes. * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. @@ -1608,7 +1653,8 @@ Variable Methods * ``order`` can be a string containing the characters t,x,y,z, or * . * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for ``getAxisList``." - "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, + "List", "``getDomain()``", "Get the domain. + * Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, * ``start`` is the start index of the domain relative to the axis object, * ``length`` is the length of the axis, and * ``true\_length`` is the actual number of (defined) points in the domain. @@ -1618,7 +1664,11 @@ Variable Methods "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found. - String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of: + * String ``getOrder()`` + * Get the order string of a spatio-temporal variable. + * The order string specifies the physical ordering of the data. + * It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. + Each character is one of: * 't': time * 'z': vertical level * 'y': latitude @@ -1635,9 +1685,11 @@ Variable Methods **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." - "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. + "Integer", "``len(var)``", "The length of the first dimension of the variable. + * If the variable is zero-dimensional (scalar), a length of 0 is returned. **Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time. + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. + * The variable must be a function of latitude, longitude, pressure level, and (optionally) time. * ``newLevel`` is an axis of the result pressure levels. * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. * ``missing`` is a missing data value. The default is ``var.getMissing()`` diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index b13ff9ed..8437b1e6 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -44,9 +44,8 @@ where - ``element-content`` depends on the type of element. It is either a list of elements, or text which defines the element values. For example, the content of an axis element either is a list of axis - values, or is a linear element. For datasets, the content is the - blank-separated list of elements corresponding to the axes, grids, - and variables contained in the dataset. + values, or is a linear element. +- For datasets, the content is the blank-separated list of elements corresponding to the axes, grids, and variables contained in the dataset. The CDML elements are: diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 235ca150..33fa3eef 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -4,7 +4,7 @@ APPENDIX A CDMS Classes ~~~~~~~~~~~~ -Figure 1, "CDMS Classes", on page 175 illustrates the class inheritance +Figure 1, "CDMS Classes", illustrates the class inheritance structure of CDMS. The classes may be categorized as abstract or concrete. Only concrete classes are meant to be used directly. In contrast an abstract class defines the common interface of its @@ -197,8 +197,8 @@ cdms module CdmsFile '''''''' -- The function createVariable has a keyword fill\_value. The datatype - may be a Numpy/MV typecode. +- The function createVariable has a keyword fill\_value. +- The datatype may be a Numpy/MV typecode. - The function write was added. CDMSError @@ -214,9 +214,12 @@ AbstractRectGrid InternalAttributes '''''''''''''''''' -- The class InternalAttributes was added. It has methods - add\_internal\_attribute, is\_internal\_attribute, and - replace\_external\_attributes. +- The class InternalAttributes was added. +- It has methods: + + * add\_internal\_attribute + * is\_internal\_attribute + * replace\_external\_attributes TransientVariable ''''''''''''''''' From 3e67e5766a1a5cffa50fcfdc73b5be6da2bc3e9f Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 2 Jul 2018 15:36:15 -0700 Subject: [PATCH 195/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 4b16016e..8410a731 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -475,7 +475,8 @@ CoordinateAxis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. - * ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. + * ``modulo`` is the modulus value. + * Any given axis value ``x`` is treated as equivalent to ``x + modulus``. * If ``persistent`` is ``True``, the external file or dataset (if any) is modified. * By default, the designation is temporary." "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if: @@ -1588,7 +1589,8 @@ Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. - * ``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. + * ``id`` is the name of the variable. + * ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. * ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. **Note:** this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. From 01fb4169faa2bde4e8a01da1098ddfd84c1ebaf9 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 9 Jul 2018 15:43:25 -0700 Subject: [PATCH 196/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 8410a731..f0ee8c00 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -56,7 +56,7 @@ PythonTypes used in CDMS "Array", "Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules." "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" - "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" + "Dictionary","An unordered 2,3 collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" "Float", "Floating-point value." "Integer", "Integer value." "List", "An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']``" @@ -100,15 +100,30 @@ latitude, longitude). :header: "Line", "Notes" :widths: 10, 80 - "2,3", "Makes the CDMS and MV modules available. MV defines arithmetic functions." - "4", "Opens a netCDF file read-only. The result jones is a dataset object." - "5", "Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data." - "6", "Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array." + "2,3", "Makes the CDMS and MV modules available. + * MV defines arithmetic functions." + "4", "Opens a netCDF file read-only. + * The result jones is a dataset object." + "5", "Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. + * This does not actually read the data." + "6", "Read all January monthly mean data into a variable jans. + * Variables can be sliced like arrays. + * The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. + * If the stride 12 were omitted, it would default to 1. + **Note:** that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. + + **Also note:** that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array." "7", "Reads all July data into a masked array julys." - "8", "Calculate the average January value for each grid zone. Any missing data is handled automatically." - "9,10", "Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file." + "8", "Calculate the average January value for each grid zone. + * Any missing data is handled automatically." + "9,10", "Set the variable id and long\_name attributes. + * The id is used as the name of the variable when plotted or written to a file." "14", "Create a new netCDF output file named ‘janjuly.nc’ to hold the results." - "15", "Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." + "15", "Write the January average values to the output file. + * The variable will have id “tas\_jan” in the file. + * ``write`` is a utility function which creates the variable in the file, then writes data to the variable. + * A more general method of data output is first to create a variable, then set a slice of the variable. + **Note:** that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." "17", "Set the global attribute ‘comment’." "18", "Close the output file." From bac2fa43d78ed8167c9501013ffb3cdfbbdbdec7 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 11 Jul 2018 14:50:55 -0700 Subject: [PATCH 197/239] Changes made to Section 2 and 5 --- Lib/cache.py | 2 +- docs/source/manual/cdms_6.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index 33253236..0c4ae8d6 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -33,7 +33,7 @@ def lock(filename): If the function returns, the lock was acquired successfully. - Note: This function is UNIX-specific. + **Note:** This function is UNIX-specific. Note: It is important to delete the lock via unlock() if the process is interrupted, otherwise subsequent locks will fail. diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 8437b1e6..85b994f4 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -163,7 +163,7 @@ Dataset Attributes "appendices", "N", "N", "Y", "Version number" "calendar", "N", "N", "Y", "Calendar used for encoding time axes. * ``gregorian`` \| ``julian`` \| ``noleap`` \|\ ``360_day`` \| ``proleptic_gregorian`` \| ``standard`` - * Note: for the CF convention, the calendar attribute is placed on the time axis." + **Note:** for the CF convention, the calendar attribute is placed on the time axis." "comment", "N", "Y", "Y", "Additional dataset information" "conventions", "Y", "Y", "Y", "The netCDF metadata standard. Example: 'CF-1.0'" "cdms_filemap", "Y", "N", "N", "Map of partitioned axes to files. See note below." From 66eaa55a91439c2869cce18482527e8e070a442c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 12 Jul 2018 14:13:24 -0700 Subject: [PATCH 198/239] Changes to Sections 2, 6 and 7 --- Lib/cache.py | 2 +- docs/source/manual/cdms_7.rst | 77 ++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index 0c4ae8d6..33253236 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -33,7 +33,7 @@ def lock(filename): If the function returns, the lock was acquired successfully. - **Note:** This function is UNIX-specific. + Note: This function is UNIX-specific. Note: It is important to delete the lock via unlock() if the process is interrupted, otherwise subsequent locks will fail. diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index c7ea0283..3868da7e 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -67,54 +67,73 @@ CDScan Command Options :header: "Option:, "Description" :widths: 20, 80 - "``-a alias_file``", "Change variable names to the aliases defined in an alias file. Each line of the alias file consists of two blank separated fields: ``variable_id alias``. + "``-a alias_file``", "Change variable names to the aliases defined in an alias file. + - Each line of the alias file consists of two blank separated fields: + * ``variable_id alias``. * ``variable_id`` is the ID of the variable in the file, and * ``alias`` is the name that will be substituted for it in the output dataset. * Only variables with entries in the ``alias_file`` are renamed." - "``-c calendar``", "Specify the dataset calendar attribute. One of: + "``-c calendar``", "Specify the dataset calendar attribute. + - One of: * gregorian (default) * julian * noleap * proleptic_gregorian * standard * 360_day" - "``-d dataset_id``", "String identifier of the dataset. Should not contain blanks or non-printing characters. Default: 'None'" - "``-e newattr``", "Add or modify attributes of a file, variable, or axis. The form of ``newattr`` is either: - * ``var.attr = value`` to modify a variable or attribute, or - * ``.attr = value`` to modify a global (file) attribute. - * In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. - * If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." - "``--exclude var,var,...``", "Exclude specified variables. The argument is a comma-separated list of variables containing no blanks. Also see ``--include``." + "``-d dataset_id``", "String identifier of the dataset. + * Should not contain blanks or non-printing characters. + * Default: 'None'" + "``-e newattr``", "Add or modify attributes of a file, variable, or axis. + - The form of ``newattr`` is either: + * ``var.attr = value`` to modify a variable or attribute, or + * ``.attr = value`` to modify a global (file) attribute. + * In either case, value may be quoted to preserve spaces or force the attribute to be treated as a string. + * If value is not quoted and the first character is a digit, it is converted to integer or floating-point. This option does not modify the input datafiles. See notes and examples below." + "``--exclude var,var,...``", "Exclude specified variables. + * The argument is a comma-separated list of variables containing no blanks. + * Also see ``--include``." "``-f file_list``", "File containing a list of absolute data file names, one per line." "``-h``", "Print a help message." - "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. This is useful if the time dimension is very long. + "``-i time_delta``", "Causes the time dimension to be represented as linear, producing a more compact representation. + - This is useful if the time dimension is very long. * ``time_delta`` is a float or integer. * For example, if the time delta is 6 hours, and the reference units are ``hours since xxxx`` , set the time delta to 6. See the ``-r`` option. See Note 2." - "``--include var,var,...``", "Only include specified variables in the output. The argument is a comma-separated list of variables containing no blanks. Also see ``--exclude``." - "``-j``", "Scan time as a vector dimension. Time values are listed individually. + "``--include var,var,...``", "Only include specified variables in the output. + * The argument is a comma-separated list of variables containing no blanks. + * Also see ``--exclude``." + "``-j``", "Scan time as a vector dimension. + * Time values are listed individually. **Note:** Turns off the -i option." "``-l levels``", "Specify that the files are partitioned by vertical level. That is, data for different vertical levels may appear in different files. - * ``levels`` is a comma-separated list of levels containing no blanks. See Note 3." - "``-m levelid``", "Name of the vertical level dimension. The default is the vertical dimension as determined by CDMS. See Note 3." + * ``levels`` is a comma-separated list of levels containing no blanks. + * See Note 3." + "``-m levelid``", "Name of the vertical level dimension. + * The default is the vertical dimension as determined by CDMS. + * See Note 3." "``-p template``", "Add a file template string, for compatibility with pre-V3.0 datasets. * ``cdimport -h`` describes template strings." "``-q``", "Quiet mode." - "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where + "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where: * ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." - "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. This can be used to distinguish variables having the same name but generated by different models or ensemble runs. - * ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. - * Each line consists of two blank-separated fields: ``directory suffix``. - * Each file path is compared to the directories in the suffix file. - * If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. - * If more than one such directory is found, the first directory found is used. - * If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." - "``-t timeid``", "ID of the partitioned time dimension. The default is the name of the time dimension as determined by CDMS. See Note 1." - "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. The arguments are comma-separated list: - * zero is the initial time point, a floating-point value. - * delta is the time delta, floating-point. - * units are time units as specified in the [-r] option. - * calendar is optional, and is specified as in the [-c] option. - * If omitted, it defaults to the value specified by [-c], otherwise as specified in the file. + "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. + - This can be used to distinguish variables having the same name but generated by different models or ensemble runs. + * ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. + * Each line consists of two blank-separated fields: ``directory suffix``. + * Each file path is compared to the directories in the suffix file. + * If the file path is in that directory or a subdirectory, the corresponding suffix is appended to the variable IDs in the file. + * If more than one such directory is found, the first directory found is used. + * If no match is made, the variable ids are not altered. Regular expressions can be used: see the example in the Notes section." + "``-t timeid``", "ID of the partitioned time dimension. + * The default is the name of the time dimension as determined by CDMS. + * See Note 1." + "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. + - The arguments are comma-separated list: + * zero is the initial time point, a floating-point value. + * delta is the time delta, floating-point. + * units are time units as specified in the [-r] option. + * calendar is optional, and is specified as in the [-c] option. + * If omitted, it defaults to the value specified by [-c], otherwise as specified in the file. **Example:** ``--time-linear '0,1,months since 1980,noleap'``" "``-x xmlfile``", "Output file name. By default, output is written to standard output." From 46ea27dee3b9bcf19c999c92f81e494766118bec Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 25 Jul 2018 08:31:06 -0700 Subject: [PATCH 199/239] Changes to API --- Lib/cache.py | 2 +- docs/source/cache.rst | 20 +++- docs/source/coord.rst | 36 ++++++ docs/source/cudsinterface.rst | 25 ++++- docs/source/database.rst | 42 +++++++ docs/source/esmf.rst | 29 +++++ docs/source/forecast.rst | 19 +++- docs/source/gengrid.rst | 32 ++++++ docs/source/grid.rst | 189 +++++++++++++++++++++++++++++++- docs/source/gsRegrid.rst | 33 +++++- docs/source/hgrid.rst | 60 +++++++++- docs/source/manual/cdms_1.rst | 2 +- docs/source/manual/cdms_2.rst | 2 +- docs/source/mvBaseWriter.rst | 2 + docs/source/mvCdmsRegrid.rst | 11 ++ docs/source/mvESMFRegrid.rst | 15 +++ docs/source/mvGenericRegrid.rst | 8 +- docs/source/mvSphereMesh.rst | 7 ++ docs/source/mvVTKSGWriter.rst | 4 + docs/source/mvVTKUGWriter.rst | 5 +- docs/source/mvVsWriter.rst | 5 +- docs/source/restApi.rst | 41 +++++++ docs/source/scrip.rst | 22 ++++ docs/source/selectors.rst | 40 +++++++ docs/source/slabinterface.rst | 16 ++- regrid2/Lib/esmf.py | 2 +- 26 files changed, 648 insertions(+), 21 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index 33253236..cd1ba0cd 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -36,7 +36,7 @@ def lock(filename): Note: This function is UNIX-specific. Note: It is important to delete the lock via unlock() if the process is - interrupted, otherwise subsequent locks will fail. + interrupted, otherwise subsequent locks will fail. """ path = lockpath(filename) diff --git a/docs/source/cache.rst b/docs/source/cache.rst index 84e95ed5..fd528839 100644 --- a/docs/source/cache.rst +++ b/docs/source/cache.rst @@ -5,5 +5,21 @@ cache .. automodule:: cdms2.cache :members: - - + + Cache + get + put + deleteEntry + copyFile + getFile + delete + clean + lock + unlock + lockpath + useWindow + useTTY + useGlobusTransfer + usePythonTransfer + useRequestManagerTransfer + diff --git a/docs/source/coord.rst b/docs/source/coord.rst index a8ccc3d3..7bab223f 100644 --- a/docs/source/coord.rst +++ b/docs/source/coord.rst @@ -6,4 +6,40 @@ coord .. automodule:: cdms2.coord :members: + AbstractCoordinateAxis + createCoordinateAxis + isAbstractCoordinate + clone + designateLatitude + designateLevel + designateLongitude + designateTime + getCalendar + getData + getExplicitBounds + info + isLatitude + isLevel + isLongitude + isTime + isForecast + listall + getBounds + setBounds + setCalendar + size + writeToFile + + AbstractAxis2D + clone + setBounds + subSlice + + DatasetAxis2D + rpr + + FileAxis2D + rpr + + TransientAxis2D diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst index 10268c59..06bf14ae 100644 --- a/docs/source/cudsinterface.rst +++ b/docs/source/cudsinterface.rst @@ -6,4 +6,27 @@ cudsinterface .. automodule:: cdms2.cudsinterface :members: - + cuDataSet + call + getitem + v + defaultvariable + cleardefault + listall + listattribute + listdimension + listglobal + listvariable + showglobal + showvariable + showattribute + showdimension + showall + dimensionobject + dimensionarray + getdimensionunits + getglobal + getattribute + getslab + readScripGrid + diff --git a/docs/source/database.rst b/docs/source/database.rst index 1c450df0..5a4872a7 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -6,4 +6,46 @@ database .. automodule:: cdms2.database :members: + AbstractDatabase + connect + loadString + close + cachecdml + getDataset + getObjFromDataset + openDataset + searchFilter + enableCache + disableCache + useRequestManager + usingRequestManager + repr + + LDAPDatabase + close + del + normalizedn + cachecdml + getDataset + getObjFromDataset + openDataset + setExternalDict + searchFilter + listDatasets + + AbstractSearchResult + getitem + len + searchPredicate + LDAPSearchResult + getitem + searchPredicate + len + getObject + + AbstractResultEntry + getObject + + LDAPResultEntry + diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst index 2efb436a..f45da483 100644 --- a/docs/source/esmf.rst +++ b/docs/source/esmf.rst @@ -7,4 +7,33 @@ regrid2- esmf .. automodule:: regrid2.esmf :members: + EsmfUnstructGrid + setCells + setNodes + toVTK + del + EsmfStructGrid + getLocalSlab + getLoHiBounds + getCoordShape + setCoords + getCoords + setCellAreas + getCellAreas + getMask + setMask + del + + EsmfStructField + getPointer + getData + setLocalData + + EsmfRegrid + getSrcAreas + getDstAreas + getSrcAreaFractions + getDstAreaFractions + call + del diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index a3941cb2..cc321fb6 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -6,4 +6,21 @@ forecast .. automodule:: cdms2.forecast :members: - + forecast + two_times_from_one + comptime + close + call + getitem + rpr + available_forecasts + + forecasts + forecast_times_to_list + time_interval_to_list + reduce_inplace + close + call + forecast_axis + getitem + rpr diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst index 6f81c80c..711ac391 100644 --- a/docs/source/gengrid.rst +++ b/docs/source/gengrid.rst @@ -6,4 +6,36 @@ gengrid .. automodule:: cdms2.gengrid :members: + AbstractGenericGrid + clone + getMesh + getShape + getAxis + genBounds + getMask + size + writeScrip + writeToFile + subSlice + getGridSlices + getIndex + intersect + getAxisList + isClose + checkAxes + reconcile + flatAxes + toGenericGrid + DatasetGenericGrid + rpr + + FileGenericGrid + rpr + + TransientGenericGrid + rpr + toGenericGrid + readScripGenericGrid + + diff --git a/docs/source/grid.rst b/docs/source/grid.rst index 1b51b75e..da8cf5d2 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -1,9 +1,192 @@ .. _grid: -grid +grid ==== -.. automodule:: cdms2.grid - :members: +.. currentmodule:: cdms2.grid +.. autosummary:: + :toctree: ./generated + AbstractGrid.hasCoordType + isGrid + setClassifyGrids + createRectGrid + createUniformGrid + createGlobalmeanGrid + createZonalGrid + createGenericGrid + createGaussianGrid + defaultRegion + setRegionSpecs + + AbstractGrid + listall + str + info + writeToFile + subSlice + hasCoordType + getAxisList + isClose + checkAxes + reconcile + clone + flatAxes + size + writeScrip + + AbstractRectGrid.classify + listall + getshape + getAxis + getBounds + getLatitude + getLongitude + getMask + setMask + GetOrder + getType + setType + getWeights + subGrid + subGridRegion + transpose + classify + classifyInFamily + genBounds + writeToFile + getMesh + glatAxes + size + writeScrip + toCurveGrid + toGenericGrid + initDomain + getMask + getMaskVar + + FileRectGrid + setBounds + getMask + setMask + getMaskVar + + TransientRectGrid + getMask + setMask + setBounds + isGrid + writeScripGrid + + + + + + + + + + getAxis(naxis) + getBounds + getLatitude + getLongitude + getMask + getMesh + Generate a mesh array for the meshfill graphics method. + getOrder + getType + getWeights + setMask(mask, permanent=0) + setType(gridtype) + size + Return number of cells in the grid + subGrid(latinterval, loninterval + subGridRegion(latRegion, lonRegion) + toCurveGrid(gridid=None) + Convert to a curvilinear grid. + Parameters: + gridid – is the string identifier of the resulting curvilinear grid object. + _ (None) – + + toGenericGrid(gridid=None) + transpose + writeScrip(cufile, gridTitle=None) + Write a grid to a SCRIP file. + Parameters: + + cufile – is a Cdunif file, NOT a CDMS file. + gridtitle – is a string identifying the grid. + + writeToFile(file) +class FileRectGrid(parent, gridname, latobj, lonobj, order, gridtype, maskobj=None, tempMask=None) + getMask + getMaskVar + setBounds(latBounds, lonBounds, persistent=0) + setMask(mask, persistent=0) +class RectGrid(parent, rectgridNode=None) + getMask + getMaskVar + initDomain(axisdict, vardict) +class TransientRectGrid(latobj, lonobj, order, gridtype, maskarray=None) + Grids that live in memory only. + getMask + setBounds(latBounds, lonBounds) + setMask(mask, persistent=0) +createGaussianGrid(nlats, xorigin=0.0) + Create a Gaussian grid, with shape (nlats, 2*nlats). + Parameters: + nlats – is the number of latitudes. + xorigin – is the origin of the longitude axis + order – is either “yx” or “xy” +createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None) +createGlobalMeanGrid(grid) +createRectGrid(lat, lon, order='yx', type='generic', mask=None) +createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None) +createZonalGrid(grid) +defaultRegion() + Returns: a specification for a default (full) region. +isGrid(grid) + Is grid a grid? + Parameters: + grid-cdms2 – contruct to be examined + _ (None) – +setClassifyGrids(mode) + setRegionSpecs(grid, coordSpec, coordType, resultSpec) + Modify a list of coordinate specifications, given a coordinate type and a specification for that coordinate. + Parameters: + grid – is the grid object to be associated with the region. + coordSpec – + is a coordinate specification, having one of the forms: + x + (x,y) + (x,y,’co’) + (x,y,’co’,cycle) + ’:’ + None + coordType – is one of CoordinateTypes + resultSpec – is a list of 4-tuples of the form (x,y,’co’,cycle), or None if no spec for the corresponding dimension type. The function sets the appropriate coordinate in resultSpec, in the canonical form (x,y,’co’,cycle). A CDMSError exception is raised if the entry in resultSpec is not None. + Note: that time coordinate types are not permitted. +writeScripGrid(path, grid, gridTitle=None) + Write a grid to a SCRIP grid file. + Parameters: + path – is the path of the SCRIP file to be created. + grid – is a CDMS grid object. + gridTitle – is a string ID for the grid. + +Table Of Contents + + 1. Introduction + 2. CDMS Python Application Programming Interface + 3. Module: CdTime + 4. Regridding Data + 5. Plotting CDMS data in Python + 6. Climate Data Markup Language (CDML) + 7. CDMS Utilities + 8. APPENDIX A + 9. APPENDIX B + 10. APPENDIX C + 11. CDMS Sample Dataset + 12. API + +Search diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst index 07ecedd7..b503d359 100644 --- a/docs/source/gsRegrid.rst +++ b/docs/source/gsRegrid.rst @@ -6,4 +6,35 @@ regrid2-gsRegrid .. automodule:: regrid2.gsRegrid :members: - + Regrid + catchError + getTensorProduct + makeCurvilinear + make CoordsCyclic + checkForCoordCut + handleCoordsCut + getIndices + getPeriodicities + del + find + setValidMask + setMask + computeWeights + apply + call + getNumValid + getNumDstPoints + getSRcGrid + getDstGrid + getIndicesAndWeights + extend + findIndices + testMakeCyclic + testHandleCut + test + funcl + func2 + testMasking + func1 + func2 + diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst index 8fe97cf4..7e60ee85 100644 --- a/docs/source/hgrid.rst +++ b/docs/source/hgrid.rst @@ -5,7 +5,59 @@ hgrid .. automodule:: cdms2.hgrid :members: - - -.. automodule:: cdms2.hgrid.AbstractHorizontalGrid - :members: + + AbstractHorizontalGrid + flatten + genBounds + getAxis + getBounds + getLatitude + getLongitude + getMask + getMesh + getWeightsArray + listall + setMask + subGridRegion + hasCoordType + checkConvex + fixCutCells + + AbstractCurveGrid + clone + rpr + getMesh + getShape + genBounds + getAxis + getMask + size + writeScrip + toGenericGrid + toCurveGrid + writeToFile + writeg + write_gridspec + init_from_gridspec + init_from_gridspec_file + subSlice + getGridSlices + getIndex + intersect + getAxisList + isClose + checkAxes + reconcile + flatAxes + + DatasetCurveGrid + rpr + + FileCurveGrid + rpr + + TransientCurveGrid + rpr + toCurveGrid + readScripCurveGrid + diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index ac6f4f86..905b4e54 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -6,7 +6,7 @@ Overview The Community Data Management System is an object-oriented data management system, specialized for organizing multidimensional, gridded data used -in climate analysis and simulation. +in climate analysis and simulation. CDMS is implemented as part of the Climate Data Analysis Tool (CDAT), which uses the Python language. The examples in diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index f0ee8c00..e337f497 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -422,7 +422,7 @@ CoordinateAxis Constructors CoordinateAxis Methods ----------------------- +----------------------- .. csv-table:: :header: "Type", "Method", "Definition" diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst index 6fd6ecaa..18dd6f64 100644 --- a/docs/source/mvBaseWriter.rst +++ b/docs/source/mvBaseWriter.rst @@ -6,3 +6,5 @@ mvBaseWriter .. automodule:: cdms2.mvBaseWriter :members: + BaseWriter + write diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst index 476abe7a..92035524 100644 --- a/docs/source/mvCdmsRegrid.rst +++ b/docs/source/mvCdmsRegrid.rst @@ -5,3 +5,14 @@ mvCdmsRegrid .. automodule:: cdms2.mvCdmsRegrid :members: + + CdmsRegrid + getboundlist + areCellsOk + projectToSphere + buildBounds + getBoundList + getCoordList + getDstDataShape + getAxisList + call diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst index 72170a0c..aceb02ff 100644 --- a/docs/source/mvESMFRegrid.rst +++ b/docs/source/mvESMFRegrid.rst @@ -6,4 +6,19 @@ regrid2-mvESMFRegrid .. automodule:: regrid2.mvESMFRegrid :members: + ESMFRegrid + setCoords + computeWeights + apply + getDstGrid + getSrcAreas + getDstAreas + getSrcAreaFractions + getDstAreaFractions + getSrcLocalShape + getDstLocalShape + getSrcLocalSlab + getDstLocalSlab + fillInDiagnosticData + diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst index e5c55212..2f216bb0 100644 --- a/docs/source/mvGenericRegrid.rst +++ b/docs/source/mvGenericRegrid.rst @@ -6,4 +6,10 @@ regrid2-mvGenericRegrid .. automodule:: regrid2.mvGenericRegrid :members: - + GenericRegrid + guessPeriodicity + computeWeights + apply + getDstGrid + fillInDiagnosticData + diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst index 401ba3ea..0b77b686 100644 --- a/docs/source/mvSphereMesh.rst +++ b/docs/source/mvSphereMesh.rst @@ -6,3 +6,10 @@ mvSphereMesh .. automodule:: cdms2.mvSphereMesh :members: + SphereMesh + getXYZCoords + test2DRect + test2D + test3DRect + test3DposDown + diff --git a/docs/source/mvVTKSGWriter.rst b/docs/source/mvVTKSGWriter.rst index fc41b0c7..8ca9ecb5 100644 --- a/docs/source/mvVTKSGWriter.rst +++ b/docs/source/mvVTKSGWriter.rst @@ -6,5 +6,9 @@ mvVTKSGWriter .. automodule:: cdms2.mvVTKSGWriter :members: + VTKSGWriter + write + test2DRect + test3D diff --git a/docs/source/mvVTKUGWriter.rst b/docs/source/mvVTKUGWriter.rst index 6952831a..c50ee754 100644 --- a/docs/source/mvVTKUGWriter.rst +++ b/docs/source/mvVTKUGWriter.rst @@ -6,6 +6,9 @@ mvVTKUGWriter .. automodule:: cdms2.mvVTKUGWriter :members: - + VTKUGWriter + write + test2DRect + test3D diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst index 442800a8..cf50820f 100644 --- a/docs/source/mvVsWriter.rst +++ b/docs/source/mvVsWriter.rst @@ -6,4 +6,7 @@ mvVsWriter .. automodule:: cdms2.mvVsWriter :members: - + VsWriter + write + test2DRect + test3D diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst index 54a44536..cd6e8b4b 100644 --- a/docs/source/restApi.rst +++ b/docs/source/restApi.rst @@ -6,6 +6,47 @@ restApi .. automodule:: cdms2.restApi :members: + esgfConnectionException + esgfDatasetException + esgfFilesException + FacetConnection + get_xmlelement + make_facet_dict + get_xmlelement + make_facet_dict_count + + esgfConnection + getitem + setitem + search + generateRequest + request + extractTag + searchDatasets + + esgfDataset + extractFiles + info + str + clearWebCache + saveCache + loadCache + clearOriginalQueryCache + clear + search + esgfFiles + getitem + setitem + len + getMapping + getMappingKeys + setMapping + remap + esgfFile + getitem + setitem + str + diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst index 1e509a60..c8039991 100644 --- a/docs/source/scrip.rst +++ b/docs/source/scrip.rst @@ -6,4 +6,26 @@ regrid2-scrip .. automodule:: regrid2.scrip :members: + ScripRegridder + call + getOutputGrid + getInputGrid + getSourceFraction + getDestinationFraction + + ConservativeRegridder + getSourceArea + getDestinationArea + regrid + + BilinearRegridder + regrid + + BicubicRegridder + call + + DistwgtRegridder + regrid + readRegridder + diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst index df088133..02a866f8 100644 --- a/docs/source/selectors.rst +++ b/docs/source/selectors.rst @@ -5,3 +5,43 @@ selectors .. automodule:: cdms2.selectors :members: + + Selector + components + refine + and + clone + call + select + unmodifiedselect + + SelectorComponent + specify + specifyGrid + post + + axisComponent + specify + + coordinateComponent + specifyGrid + + requiredComponent + specify + + indexComponent + specify + + positionalComponent + specify + longitude + latitude + time + level + required + kwselect + timeslice + latitudeslice + longitudeslice + levelslice + setslice diff --git a/docs/source/slabinterface.rst b/docs/source/slabinterface.rst index 40865db7..938e2f78 100644 --- a/docs/source/slabinterface.rst +++ b/docs/source/slabinterface.rst @@ -6,6 +6,18 @@ slabinterface .. automodule:: cdms2.slabinterface :members: - - + Slab + getattribute + setattribute + createattribute + deleteattribute + listattributes + listdimattributes + getdimattribute + showdim + listdimnames + listall + info + cdms_bounds2cu_bounds + diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index cf4b916a..fc73f8ed 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -622,7 +622,7 @@ class EsmfRegrid: ---------- srcField - the source field object of type EsmfStructField + the source field object of type EsmfStructFields dstField the destination field object of type EsmfStructField From 28dbb4f4ce9c2752efb46cfbacc0753475dc96d8 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 25 Jul 2018 08:53:12 -0700 Subject: [PATCH 200/239] Changes made to API --- docs/source/CDML.rst | 4 +++ docs/source/cdurllib.rst | 7 ++++- docs/source/cdurlparse.rst | 8 +++++- docs/source/cdxmllib.rst | 54 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 2 deletions(-) diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst index 8a6c880f..4cf04081 100644 --- a/docs/source/CDML.rst +++ b/docs/source/CDML.rst @@ -6,4 +6,8 @@ CDML .. automodule:: cdms2.CDML :members: + CDML + buildDTD + buildExtra + diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst index 4ac7dd53..947261d9 100644 --- a/docs/source/cdurllib.rst +++ b/docs/source/cdurllib.rst @@ -6,4 +6,9 @@ cdurllib .. automodule:: cdms2.cdurllib :members: - + CDURLopener + setUserObject + open_tfp + retrieve + sampleReportHook + diff --git a/docs/source/cdurlparse.rst b/docs/source/cdurlparse.rst index 55f07539..71f65019 100644 --- a/docs/source/cdurlparse.rst +++ b/docs/source/cdurlparse.rst @@ -6,4 +6,10 @@ cdurlparse .. automodule:: cdms2.cdurlparse :members: - + clear_cache + urlparse + urlunparse + urljoin + urldefrag + test + diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index 60d12953..b60b6884 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -6,4 +6,58 @@ cdxmllib .. automodule:: cdms2.cdxmllib :members: + Error + + XMLParser + fixelements + fixclass + fixdict + reset + setnomoretags + setliteral + feed + close + translate_references + getnamespace + goahead + parse_comment + parse_doctype + parse_cdata + parse_proc + parse_attributes + parse_starttag + parse_endtag + finish_starttag + finish_endtag + handle_xml + handle_doctype + handle_starttag + handle_endtag + handle_charref + handle_data + handle_cdata + handle_comment + handle_proc + syntax_error + unknown_starttag + unknown_endtag + unknown_charref + unknown_entityref + + TextXMLParser + handle_xml + handle_data + flush + handle_cdata + handle_proc + handle_comment + syntax_error + unknown_starttag + unknown_endtag + unknown_entityref + unknown_charref + close + test + + From 58193321f86eb5f3d0a0b97e5ee66a3343790ae6 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 25 Jul 2018 14:29:02 -0700 Subject: [PATCH 201/239] Made Changes to API --- docs/source/cdxmllib.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index b60b6884..2e1e81ab 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -44,20 +44,20 @@ cdxmllib unknown_charref unknown_entityref - TextXMLParser - handle_xml - handle_data - flush - handle_cdata - handle_proc - handle_comment - syntax_error - unknown_starttag - unknown_endtag - unknown_entityref - unknown_charref - close - test + TextXMLParser + handle_xml + handle_data + flush + handle_cdata + handle_proc + handle_comment + syntax_error + unknown_starttag + unknown_endtag + unknown_entityref + unknown_charref + close + test From 99dd8f576b84140f3b4151b77651b261125ef0a4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 30 Jul 2018 15:51:35 -0700 Subject: [PATCH 202/239] Changes made to API --- docs/source/cdxmllib.rst | 2 +- docs/source/convention.rst | 28 ++++++++ docs/source/database.rst | 1 - docs/source/grid.rst | 140 ++++++++++++++++++------------------- docs/source/gsRegrid.rst | 2 +- docs/source/selectors.rst | 8 ++- 6 files changed, 107 insertions(+), 74 deletions(-) diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index 2e1e81ab..3377c243 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -6,7 +6,7 @@ cdxmllib .. automodule:: cdms2.cdxmllib :members: - Error + Error(RuntimeError) XMLParser fixelements diff --git a/docs/source/convention.rst b/docs/source/convention.rst index 6f079ae2..096936ee 100644 --- a/docs/source/convention.rst +++ b/docs/source/convention.rst @@ -6,4 +6,32 @@ convention .. automodule:: cdms2.convention :members: + AliasList + setitem + setslice + append + AbstractConvention + getAxisIds + getAxisAuxids + getDsetnodeAuxAxisIds + axisIsLatitude + axisIsLongitude + getVarLatId + getVarLonId + + NUGConvention + getAxisIds + getAxisAuxIds + + COARDSConvention + + CFConvention + getAxisAuxIds + getDsetnodeAuxAxisids + getVarLatId + getVarLonId + axisIsLatitude + axisIsLongitude + getVariableBounds + getDatasetConvention diff --git a/docs/source/database.rst b/docs/source/database.rst index 5a4872a7..908107ec 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -42,7 +42,6 @@ database getitem searchPredicate len - getObject AbstractResultEntry getObject diff --git a/docs/source/grid.rst b/docs/source/grid.rst index da8cf5d2..61e9652a 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -8,76 +8,76 @@ grid .. autosummary:: :toctree: ./generated - AbstractGrid.hasCoordType - isGrid - setClassifyGrids - createRectGrid - createUniformGrid - createGlobalmeanGrid - createZonalGrid - createGenericGrid - createGaussianGrid - defaultRegion - setRegionSpecs - - AbstractGrid - listall - str - info - writeToFile - subSlice - hasCoordType - getAxisList - isClose - checkAxes - reconcile - clone - flatAxes - size - writeScrip - - AbstractRectGrid.classify - listall - getshape - getAxis - getBounds - getLatitude - getLongitude - getMask - setMask - GetOrder - getType - setType - getWeights - subGrid - subGridRegion - transpose - classify - classifyInFamily - genBounds - writeToFile - getMesh - glatAxes - size - writeScrip - toCurveGrid - toGenericGrid - initDomain - getMask - getMaskVar - - FileRectGrid - setBounds - getMask - setMask - getMaskVar - - TransientRectGrid - getMask - setMask - setBounds - isGrid - writeScripGrid + AbstractGrid.hasCoordType + isGrid + setClassifyGrids + createRectGrid + createUniformGrid + createGlobalmeanGrid + createZonalGrid + createGenericGrid + createGaussianGrid + defaultRegion + setRegionSpecs + + AbstractGrid + listall + str + info + writeToFile + subSlice + hasCoordType + getAxisList + isClose + checkAxes + reconcile + clone + flatAxes + size + writeScrip + + AbstractRectGrid.classify + listall + getshape + getAxis + getBounds + getLatitude + getLongitude + getMask + setMask + GetOrder + getType + setType + getWeights + subGrid + subGridRegion + transpose + classify + classifyInFamily + genBounds + writeToFile + getMesh + glatAxes + size + writeScrip + toCurveGrid + toGenericGrid + initDomain + getMask + getMaskVar + + FileRectGrid + setBounds + getMask + setMask + getMaskVar + + TransientRectGrid + getMask + setMask + setBounds + isGrid + writeScripGrid diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst index b503d359..e514db14 100644 --- a/docs/source/gsRegrid.rst +++ b/docs/source/gsRegrid.rst @@ -10,7 +10,7 @@ regrid2-gsRegrid catchError getTensorProduct makeCurvilinear - make CoordsCyclic + makeCoordsCyclic checkForCoordCut handleCoordsCut getIndices diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst index 02a866f8..564e9350 100644 --- a/docs/source/selectors.rst +++ b/docs/source/selectors.rst @@ -6,9 +6,11 @@ selectors .. automodule:: cdms2.selectors :members: + SelectorError Selector components refine + repr and clone call @@ -22,6 +24,7 @@ selectors axisComponent specify + repr coordinateComponent specifyGrid @@ -30,10 +33,13 @@ selectors specify indexComponent - specify + indexedComponent + specify + positionalComponent specify + repr longitude latitude time From 2d71dd9120e9cfb41748cad036b6343b3413f14a Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 31 Jul 2018 15:05:13 -0700 Subject: [PATCH 203/239] Changes made to Section 4 and 7 --- docs/source/convention.rst | 2 +- docs/source/manual/cdms_7.rst | 9 ++++++--- docs/source/restApi.rst | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/source/convention.rst b/docs/source/convention.rst index 096936ee..4f206d82 100644 --- a/docs/source/convention.rst +++ b/docs/source/convention.rst @@ -13,7 +13,7 @@ convention AbstractConvention getAxisIds - getAxisAuxids + getAxisAuxIds getDsetnodeAuxAxisIds axisIsLatitude axisIsLongitude diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 3868da7e..adc277ec 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -23,10 +23,13 @@ CDMS assumes that there is some regularity in how datasets are partitioned: - A variable can be partitioned (split across files) in at most two - dimensions. The partitioned dimension(s) must be either time or + dimensions. +- The partitioned dimension(s) must be either time or vertical level dimensions; variables may not be partitioned across - longitude or latitude. Datasets can be parti-tioned by variable as - well. For example, one set of files might contain heat fluxes, while + longitude or latitude. +- Datasets can be parti-tioned by variable as + well. +- For example, one set of files might contain heat fluxes, while another set contains wind speeds. Otherwise, there is considerable flexibility in how a dataset can be diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst index cd6e8b4b..a0d46d49 100644 --- a/docs/source/restApi.rst +++ b/docs/source/restApi.rst @@ -13,7 +13,7 @@ restApi FacetConnection get_xmlelement make_facet_dict - get_xmlelement + get_xmlelement_count make_facet_dict_count esgfConnection From bdd59682fc7b1aa2343aa9bb6ab82111f965158d Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 7 Aug 2018 15:15:03 -0700 Subject: [PATCH 204/239] Changes made to API --- docs/source/cdxmllib.rst | 100 +++++++++++++++++----------------- docs/source/convention.rst | 45 +++++++-------- docs/source/manual/cdms_2.rst | 2 +- docs/source/manual/cdms_3.rst | 12 ++-- docs/source/manual/cdms_4.rst | 2 +- 5 files changed, 81 insertions(+), 80 deletions(-) diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index 3377c243..bb03be6d 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -2,62 +2,62 @@ cdxmllib ======== +.. currentmodule:: cdms2.cdxmllib -.. automodule:: cdms2.cdxmllib - :members: +.. autosummary:: + :toctree: generated/ - Error(RuntimeError) XMLParser - fixelements - fixclass - fixdict - reset - setnomoretags - setliteral - feed - close - translate_references - getnamespace - goahead - parse_comment - parse_doctype - parse_cdata - parse_proc - parse_attributes - parse_starttag - parse_endtag - finish_starttag - finish_endtag - handle_xml - handle_doctype - handle_starttag - handle_endtag - handle_charref - handle_data - handle_cdata - handle_comment - handle_proc - syntax_error - unknown_starttag - unknown_endtag - unknown_charref - unknown_entityref + XMLParser.fixelements + XMLParser.fixclass + XMLParser.fixdict + XMLParser.reset + XMLParser.setnomoretags + XMLParser.setliteral + XMLParser.feed + XMLParser.close + XMLParser.translate_references + XMLParser.getnamespace + XMLParser.goahead + XMLParser.parse_comment + XMLParser.parse_doctype + XMLParser.parse_cdata + XMLParser.parse_proc + XMLParser.parse_attributes + XMLParser.parse_starttag + XMLParser.parse_endtag + XMLParser.finish_starttag + XMLParser.finish_endtag + XMLParser.handle_xml + XMLParser.handle_doctype + XMLParser.handle_starttag + XMLParser.handle_endtag + XMLParser.handle_charref + XMLParser.handle_data + XMLParser.handle_cdata + XMLParser.handle_comment + XMLParser.handle_proc + XMLParser.syntax_error + XMLParser.unknown_starttag + XMLParser.unknown_endtag + XMLParser.unknown_charref + XMLParser.unknown_entityref TextXMLParser - handle_xml - handle_data - flush - handle_cdata - handle_proc - handle_comment - syntax_error - unknown_starttag - unknown_endtag - unknown_entityref - unknown_charref - close - test + TextXMLParser.handle_xml + TextXMLParser.handle_data + TextXMLParser.flush + TextXMLParser.handle_cdata + TextXMLParser.handle_proc + TextXMLParser.handle_comment + TextXMLParser.syntax_error + TextXMLParser.unknown_starttag + TextXMLParser.unknown_endtag + TextXMLParser.unknown_entityref + TextXMLParser.unknown_charref + TextXMLParser.close + TextXMLParser.test diff --git a/docs/source/convention.rst b/docs/source/convention.rst index 4f206d82..051e1ed1 100644 --- a/docs/source/convention.rst +++ b/docs/source/convention.rst @@ -2,36 +2,37 @@ convention ========== +.. currentmodule:: cdms2.convention -.. automodule:: cdms2.convention - :members: +.. autosummary:: + :toctree: generated/ AliasList - setitem - setslice - append + AliasList.setitem + AliasList.setslice + AliasList.append AbstractConvention - getAxisIds - getAxisAuxIds - getDsetnodeAuxAxisIds - axisIsLatitude - axisIsLongitude - getVarLatId - getVarLonId + AbstractConvention.AbstractConvention.getAxisIds + AbstractConvention.getAxisAuxIds + AbstractConvention.getDsetnodeAuxAxisIds + AbstractConvention.axisIsLatitude + AbstractConvention.axisIsLongitude + AbstractConvention.getVarLatId + AbstractConvention.getVarLonId NUGConvention - getAxisIds - getAxisAuxIds + NUGConvention.getAxisIds + NUGConvention.getAxisAuxIds COARDSConvention CFConvention - getAxisAuxIds - getDsetnodeAuxAxisids - getVarLatId - getVarLonId - axisIsLatitude - axisIsLongitude - getVariableBounds - getDatasetConvention + CFConvention.getAxisAuxIds + CFConvention.getDsetnodeAuxAxisids + CFConvention.getVarLatId + CFConvention.getVarLonId + CFConvention.axisIsLatitude + CFConvention.axisIsLongitude + CFConvention.getVariableBounds + CFConvention.getDatasetConvention diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index e337f497..516c960c 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -525,7 +525,7 @@ CoordinateAxis Methods, Additional to CoordinateAxis * the stride ``k`` can be positive or negative. * wraparound is supported for longitude dimensions or those with a modulus attribute." -CoordinateAxis Slice Operators +CoordinateAxis Slice OperatorsCoordinateAxis Slice Operators ------------------------------ .. csv-table:: diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index e349b047..18141655 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -130,12 +130,12 @@ Component Time Types :header: "Type", "Name", "Summary" :widths: 15, 15, 50 - "Integer", "year", "Year value" - "Integer", "month", "Month, in the range 1..12" - "Integer", "day", "Day of month, in the range 1 .. 31" - "Integer", "hour", "Hour, in the range 0 .. 23" - "Integer", "minute", "Minute, in the range 0 .. 59" - "Float", "second", "Seconds, in the range 0.0 .. 60.0" + * "Integer", "year", "Year value" + * "Integer", "month", "Month, in the range 1..12" + * "Integer", "day", "Day of month, in the range 1 .. 31" + * "Integer", "hour", "Hour, in the range 0 .. 23" + * "Integer", "minute", "Minute, in the range 0 .. 59" + * "Float", "second", "Seconds, in the range 0.0 .. 60.0" Time Methods ^^^^^^^^^^^^ diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index b045f288..8f0a80c2 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -296,7 +296,7 @@ CDMS Horizontal Regridder from regrid2 import Regridder -makes the CDMS Regridder class available within a Python program. An +Makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. From 7c1079846b87fc2385df372e141b5118b3d5e5a7 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 8 Aug 2018 11:02:46 -0700 Subject: [PATCH 205/239] Changes made to API --- docs/source/CDML.rst | 9 +- docs/source/cache.rst | 35 ++--- docs/source/cdurllib.rst | 15 ++- docs/source/cdurlparse.rst | 5 +- docs/source/coord.rst | 59 ++++---- docs/source/cudsinterface.rst | 49 +++---- docs/source/database.rst | 65 ++++----- docs/source/esmf.rst | 52 ++++---- docs/source/forecast.rst | 35 ++--- docs/source/gengrid.rst | 53 ++++---- docs/source/grid.rst | 230 +++++++++----------------------- docs/source/gsRegrid.rst | 65 ++++----- docs/source/hgrid.rst | 95 ++++++------- docs/source/mvBaseWriter.rst | 8 +- docs/source/mvCdmsRegrid.rst | 23 ++-- docs/source/mvESMFRegrid.rst | 32 ++--- docs/source/mvGenericRegrid.rst | 16 ++- docs/source/mvSphereMesh.rst | 15 ++- docs/source/mvVTKSGWriter.rst | 11 +- docs/source/mvVTKUGWriter.rst | 12 +- docs/source/mvVsWriter.rst | 12 +- docs/source/restApi.rst | 65 ++++----- docs/source/scrip.rst | 30 +++-- docs/source/selectors.rst | 65 ++++----- docs/source/slabinterface.rst | 29 ++-- 25 files changed, 506 insertions(+), 579 deletions(-) diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst index 4cf04081..3ee8546c 100644 --- a/docs/source/CDML.rst +++ b/docs/source/CDML.rst @@ -2,12 +2,13 @@ CDML ==== +.. currentmodule:: cdms2.CDML -.. automodule:: cdms2.CDML - :members: +.. autosummary:: + :toctree: generated/ CDML - buildDTD - buildExtra + CDML.buildDTD + CDML.buildExtra diff --git a/docs/source/cache.rst b/docs/source/cache.rst index fd528839..242984d2 100644 --- a/docs/source/cache.rst +++ b/docs/source/cache.rst @@ -2,24 +2,25 @@ cache ===== +.. currentmodule:: cdms2.cache -.. automodule:: cdms2.cache - :members: +.. autosummary:: + :toctree: generated/ Cache - get - put - deleteEntry - copyFile - getFile - delete - clean - lock - unlock - lockpath - useWindow - useTTY - useGlobusTransfer - usePythonTransfer - useRequestManagerTransfer + Cache.get + Cache.put + Cache.deleteEntry + Cache.copyFile + Cache.getFile + Cache.delete + Cache.clean + Cache.lock + Cache.unlock + Cache.lockpath + Cache.useWindow + Cache.useTTY + Cache.useGlobusTransfer + Cache.usePythonTransfer + Cache.useRequestManagerTransfer diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst index 947261d9..ea700f0d 100644 --- a/docs/source/cdurllib.rst +++ b/docs/source/cdurllib.rst @@ -2,13 +2,14 @@ cdurllib ======== - -.. automodule:: cdms2.cdurllib - :members: +.. currentmodule:: cdms2.cdurllib + +.. autosummary:: + :toctree: generated/ CDURLopener - setUserObject - open_tfp - retrieve - sampleReportHook + CDURLopener.setUserObject + CDURLopener.open_tfp + CDURLopener.retrieve + CDURLopener.sampleReportHook diff --git a/docs/source/cdurlparse.rst b/docs/source/cdurlparse.rst index 71f65019..9e860d5b 100644 --- a/docs/source/cdurlparse.rst +++ b/docs/source/cdurlparse.rst @@ -2,9 +2,10 @@ cdurlparse ========== +.. currentmodule:: cdms2.cdurlparse -.. automodule:: cdms2.cdurlparse - :members: +.. autosummary:: + :toctree: generated/ clear_cache urlparse diff --git a/docs/source/coord.rst b/docs/source/coord.rst index 7bab223f..d0856c2e 100644 --- a/docs/source/coord.rst +++ b/docs/source/coord.rst @@ -2,44 +2,45 @@ coord ===== +.. currentmodule:: cdms2.coord -.. automodule:: cdms2.coord - :members: +.. autosummary:: + :toctree: generated/ AbstractCoordinateAxis - createCoordinateAxis - isAbstractCoordinate - clone - designateLatitude - designateLevel - designateLongitude - designateTime - getCalendar - getData - getExplicitBounds - info - isLatitude - isLevel - isLongitude - isTime - isForecast - listall - getBounds - setBounds - setCalendar - size - writeToFile + AbstractCoordinateAxis.createCoordinateAxis + AbstractCoordinateAxis.isAbstractCoordinate + AbstractCoordinateAxis.clone + AbstractCoordinateAxis.designateLatitude + AbstractCoordinateAxis.designateLevel + AbstractCoordinateAxis.designateLongitude + AbstractCoordinateAxis.designateTime + AbstractCoordinateAxis.getCalendar + AbstractCoordinateAxis.getData + AbstractCoordinateAxis.getExplicitBounds + AbstractCoordinateAxis.info + AbstractCoordinateAxis.isLatitude + AbstractCoordinateAxis.isLevel + AbstractCoordinateAxis.isLongitude + AbstractCoordinateAxisisTime + AbstractCoordinateAxis.isForecast + AbstractCoordinateAxis.listall + AbstractCoordinateAxis.getBounds + AbstractCoordinateAxis.setBounds + AbstractCoordinateAxis.setCalendar + AbstractCoordinateAxis.size + AbstractCoordinateAxiswriteToFile AbstractAxis2D - clone - setBounds - subSlice + AbstractAxis2D.clone + AbstractAxis2D.setBounds + AbstractAxis2D.subSlice DatasetAxis2D - rpr + DatasetAxis2D.rpr FileAxis2D - rpr + FileAxis2D.rpr TransientAxis2D diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst index 06bf14ae..befbfb21 100644 --- a/docs/source/cudsinterface.rst +++ b/docs/source/cudsinterface.rst @@ -2,31 +2,32 @@ cudsinterface ============= +.. currentmodule:: cdms2.cudsinterface -.. automodule:: cdms2.cudsinterface - :members: +.. autosummary:: + :toctree: generated/ cuDataSet - call - getitem - v - defaultvariable - cleardefault - listall - listattribute - listdimension - listglobal - listvariable - showglobal - showvariable - showattribute - showdimension - showall - dimensionobject - dimensionarray - getdimensionunits - getglobal - getattribute - getslab - readScripGrid + cuDataSet.call + cuDataSet.getitem + cuDataSet.v + cuDataSet.defaultvariable + cuDataSet.cleardefault + cuDataSet.listall + cuDataSet.listattribute + cuDataSet.listdimension + cuDataSet.listglobal + cuDataSet.listvariable + cuDataSet.showglobal + cuDataSet.showvariable + cuDataSet.showattribute + cuDataSet.showdimension + cuDataSet.showall + cuDataSet.dimensionobject + cuDataSet.dimensionarray + cuDataSet.getdimensionunits + cuDataSet.getglobal + cuDataSet.getattribute + cuDataSet.getslab + cuDataSet.readScripGrid diff --git a/docs/source/database.rst b/docs/source/database.rst index 908107ec..1f8ea482 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -2,49 +2,50 @@ database ======== +.. currentmodule:: cdms2.database -.. automodule:: cdms2.database - :members: +.. autosummary:: + :toctree: generated/ AbstractDatabase - connect - loadString - close - cachecdml - getDataset - getObjFromDataset - openDataset - searchFilter - enableCache - disableCache - useRequestManager - usingRequestManager - repr + AbstractDatabase.connect + AbstractDatabase.loadString + AbstractDatabase.close + AbstractDatabase.cachecdml + AbstractDatabase.getDataset + AbstractDatabase.getObjFromDataset + AbstractDatabase.openDataset + AbstractDatabase.searchFilter + AbstractDatabase.enableCache + AbstractDatabase.disableCache + AbstractDatabase.useRequestManager + AbstractDatabase.usingRequestManager + AbstractDatabase.repr LDAPDatabase - close - del - normalizedn - cachecdml - getDataset - getObjFromDataset - openDataset - setExternalDict - searchFilter - listDatasets + LDAPDatabase.close + LDAPDatabase.del + LDAPDatabase.normalizedn + LDAPDatabase.cachecdml + LDAPDatabase.getDataset + LDAPDatabase.getObjFromDataset + LDAPDatabase.openDataset + LDAPDatabase.setExternalDict + LDAPDatabase.searchFilter + LDAPDatabase.listDatasets AbstractSearchResult - getitem - len - searchPredicate + AbstractSearchResult.getitem + AbstractSearchResult.len + AbstractSearchResult.searchPredicate LDAPSearchResult - getitem - searchPredicate - len + LDAPSearchResult.getitem + LDAPSearchResult.searchPredicate + LDAPSearchResult.len AbstractResultEntry - getObject + AbstractResultEntry.getObject LDAPResultEntry diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst index f45da483..c07b99d0 100644 --- a/docs/source/esmf.rst +++ b/docs/source/esmf.rst @@ -2,38 +2,38 @@ regrid2- esmf ============= +.. currentmodule:: cdms2.regrid2-esmf - -.. automodule:: regrid2.esmf - :members: +.. autosummary:: + :toctree: generated/ EsmfUnstructGrid - setCells - setNodes - toVTK - del + EsmfUnstructGrid.setCells + EsmfUnstructGrid.setNodes + EsmfUnstructGrid.toVTK + EsmfUnstructGrid.del EsmfStructGrid - getLocalSlab - getLoHiBounds - getCoordShape - setCoords - getCoords - setCellAreas - getCellAreas - getMask - setMask - del + EsmfStructGrid.getLocalSlab + EsmfStructGrid.getLoHiBounds + EsmfStructGrid.getCoordShape + EsmfStructGrid.setCoords + EsmfStructGrid.getCoords + EsmfStructGrid.setCellAreas + EsmfStructGrid.getCellAreas + EsmfStructGrid.getMask + EsmfStructGrid.setMask + EsmfStructGrid.del EsmfStructField - getPointer - getData - setLocalData + EsmfStructField.getPointer + EsmfStructField.getData + EsmfStructField.setLocalData EsmfRegrid - getSrcAreas - getDstAreas - getSrcAreaFractions - getDstAreaFractions - call - del + EsmfRegrid.getSrcAreas + EsmfRegrid.getDstAreas + EsmfRegrid.getSrcAreaFractions + EsmfRegrid.getDstAreaFractions + EsmfRegrid.call + EsmfRegrid.del diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index cc321fb6..4a6eaf0a 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -2,25 +2,26 @@ forecast ======== +.. currentmodule:: cdms2.convention -.. automodule:: cdms2.forecast - :members: +.. autosummary:: + :toctree: generated/ forecast - two_times_from_one - comptime - close - call - getitem - rpr - available_forecasts + forecast.two_times_from_one + forecast.comptime + forecast.close + forecast.call + forecast.getitem + forecast.rpr + forecast.available_forecasts forecasts - forecast_times_to_list - time_interval_to_list - reduce_inplace - close - call - forecast_axis - getitem - rpr + forecasts.forecast_times_to_list + forecasts.time_interval_to_list + forecasts.reduce_inplace + forecasts.close + forecasts.call + forecasts.forecast_axis + forecasts.getitem + forecasts.rpr diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst index 711ac391..114c5e0a 100644 --- a/docs/source/gengrid.rst +++ b/docs/source/gengrid.rst @@ -2,40 +2,41 @@ gengrid ======= +.. currentmodule:: cdms2.gengrid -.. automodule:: cdms2.gengrid - :members: +.. autosummary:: + :toctree: generated/ AbstractGenericGrid - clone - getMesh - getShape - getAxis - genBounds - getMask - size - writeScrip - writeToFile - subSlice - getGridSlices - getIndex - intersect - getAxisList - isClose - checkAxes - reconcile - flatAxes - toGenericGrid + AbstractGenericGrid.clone + AbstractGenericGrid.getMesh + AbstractGenericGrid.getShape + AbstractGenericGrid.getAxis + AbstractGenericGrid.genBounds + AbstractGenericGrid.getMask + AbstractGenericGrid.size + AbstractGenericGrid.writeScrip + AbstractGenericGrid.writeToFile + AbstractGenericGrid.subSlice + AbstractGenericGrid.getGridSlices + AbstractGenericGrid.getIndex + AbstractGenericGrid.intersect + AbstractGenericGrid.getAxisList + AbstractGenericGrid.isClose + AbstractGenericGrid.checkAxes + AbstractGenericGrid.reconcile + AbstractGenericGrid.flatAxes + AbstractGenericGrid.toGenericGrid DatasetGenericGrid - rpr + DatasetGenericGrid.rpr FileGenericGrid - rpr + FileGenericGrid.rpr TransientGenericGrid - rpr - toGenericGrid - readScripGenericGrid + TransientGenericGrid.rpr + TransientGenericGrid.toGenericGrid + TransientGenericGrid.readScripGenericGrid diff --git a/docs/source/grid.rst b/docs/source/grid.rst index 61e9652a..adda2c49 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -6,78 +6,78 @@ grid .. currentmodule:: cdms2.grid .. autosummary:: - :toctree: ./generated + :toctree: generated/ AbstractGrid.hasCoordType - isGrid - setClassifyGrids - createRectGrid - createUniformGrid - createGlobalmeanGrid - createZonalGrid - createGenericGrid - createGaussianGrid - defaultRegion - setRegionSpecs + AbstractGrid.hasCoordType.isGrid + AbstractGrid.hasCoordType.setClassifyGrids + AbstractGrid.hasCoordType.createRectGrid + AbstractGrid.hasCoordType.createUniformGrid + AbstractGrid.hasCoordType.createGlobalmeanGrid + AbstractGrid.hasCoordType.createZonalGrid + AbstractGrid.hasCoordType.createGenericGrid + AbstractGrid.hasCoordType.createGaussianGrid + AbstractGrid.hasCoordType.defaultRegion + AbstractGrid.hasCoordType.setRegionSpecs AbstractGrid - listall - str - info - writeToFile - subSlice - hasCoordType - getAxisList - isClose - checkAxes - reconcile - clone - flatAxes - size - writeScrip - + AbstractGrid.listall + AbstractGrid.str + AbstractGrid.info + AbstractGrid.writeToFile + AbstractGrid.subSlice + AbstractGrid.hasCoordType + AbstractGrid.getAxisList + AbstractGrid.isClose + AbstractGrid.checkAxes + AbstractGrid.reconcile + AbstractGrid.clone + AbstractGrid.flatAxes + AbstractGrid.size + AbstractGrid.writeScrip + + AbstractRectGrid + AbstractRectGrid.listall + AbstractRectGrid.getshape + AbstractRectGrid.getAxis + AbstractRectGrid.getBounds + AbstractRectGrid.getLatitude + AbstractRectGrid.getLongitude + AbstractRectGrid.getMask + AbstractRectGrid.setMask + AbstractRectGrid.GetOrder + AbstractRectGrid.getType + AbstractRectGrid.setType + AbstractRectGrid.getWeights + AbstractRectGrid.subGrid + AbstractRectGrid.subGridRegion + AbstractRectGrid.transpose AbstractRectGrid.classify - listall - getshape - getAxis - getBounds - getLatitude - getLongitude - getMask - setMask - GetOrder - getType - setType - getWeights - subGrid - subGridRegion - transpose - classify - classifyInFamily - genBounds - writeToFile - getMesh - glatAxes - size - writeScrip - toCurveGrid - toGenericGrid - initDomain - getMask - getMaskVar + AbstractRectGrid.classifyInFamily + AbstractRectGrid.genBounds + AbstractRectGrid.writeToFile + AbstractRectGrid.getMesh + AbstractRectGrid.glatAxes + AbstractRectGrid.size + AbstractRectGrid.writeScrip + AbstractRectGrid.toCurveGrid + AbstractRectGrid.toGenericGrid + AbstractRectGrid.initDomain + AbstractRectGrid.getMask + AbstractRectGrid.getMaskVar FileRectGrid - setBounds - getMask - setMask - getMaskVar + FileRectGrid.setBounds + FileRectGrid.getMask + FileRectGrid.setMask + FileRectGrid.getMaskVar TransientRectGrid - getMask - setMask - setBounds - isGrid - writeScripGrid + TransientRectGrid.getMask + TransientRectGrid.setMask + TransientRectGrid.setBounds + TransientRectGrid.isGrid + TransientRectGrid.writeScripGrid @@ -87,106 +87,4 @@ grid - getAxis(naxis) - getBounds - getLatitude - getLongitude - getMask - getMesh - Generate a mesh array for the meshfill graphics method. - getOrder - getType - getWeights - setMask(mask, permanent=0) - setType(gridtype) - size - Return number of cells in the grid - subGrid(latinterval, loninterval - subGridRegion(latRegion, lonRegion) - toCurveGrid(gridid=None) - Convert to a curvilinear grid. - Parameters: - gridid – is the string identifier of the resulting curvilinear grid object. - _ (None) – - - toGenericGrid(gridid=None) - transpose - writeScrip(cufile, gridTitle=None) - Write a grid to a SCRIP file. - Parameters: - - cufile – is a Cdunif file, NOT a CDMS file. - gridtitle – is a string identifying the grid. - - writeToFile(file) -class FileRectGrid(parent, gridname, latobj, lonobj, order, gridtype, maskobj=None, tempMask=None) - getMask - getMaskVar - setBounds(latBounds, lonBounds, persistent=0) - setMask(mask, persistent=0) -class RectGrid(parent, rectgridNode=None) - getMask - getMaskVar - initDomain(axisdict, vardict) -class TransientRectGrid(latobj, lonobj, order, gridtype, maskarray=None) - Grids that live in memory only. - getMask - setBounds(latBounds, lonBounds) - setMask(mask, persistent=0) -createGaussianGrid(nlats, xorigin=0.0) - Create a Gaussian grid, with shape (nlats, 2*nlats). - Parameters: - nlats – is the number of latitudes. - xorigin – is the origin of the longitude axis - order – is either “yx” or “xy” -createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None) -createGlobalMeanGrid(grid) -createRectGrid(lat, lon, order='yx', type='generic', mask=None) -createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None) -createZonalGrid(grid) -defaultRegion() - Returns: a specification for a default (full) region. -isGrid(grid) - Is grid a grid? - Parameters: - grid-cdms2 – contruct to be examined - _ (None) – -setClassifyGrids(mode) - setRegionSpecs(grid, coordSpec, coordType, resultSpec) - Modify a list of coordinate specifications, given a coordinate type and a specification for that coordinate. - Parameters: - grid – is the grid object to be associated with the region. - coordSpec – - is a coordinate specification, having one of the forms: - x - (x,y) - (x,y,’co’) - (x,y,’co’,cycle) - ’:’ - None - coordType – is one of CoordinateTypes - resultSpec – is a list of 4-tuples of the form (x,y,’co’,cycle), or None if no spec for the corresponding dimension type. The function sets the appropriate coordinate in resultSpec, in the canonical form (x,y,’co’,cycle). A CDMSError exception is raised if the entry in resultSpec is not None. - Note: that time coordinate types are not permitted. -writeScripGrid(path, grid, gridTitle=None) - Write a grid to a SCRIP grid file. - Parameters: - path – is the path of the SCRIP file to be created. - grid – is a CDMS grid object. - gridTitle – is a string ID for the grid. - -Table Of Contents - - 1. Introduction - 2. CDMS Python Application Programming Interface - 3. Module: CdTime - 4. Regridding Data - 5. Plotting CDMS data in Python - 6. Climate Data Markup Language (CDML) - 7. CDMS Utilities - 8. APPENDIX A - 9. APPENDIX B - 10. APPENDIX C - 11. CDMS Sample Dataset - 12. API - -Search + diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst index e514db14..3c32e152 100644 --- a/docs/source/gsRegrid.rst +++ b/docs/source/gsRegrid.rst @@ -2,39 +2,40 @@ regrid2-gsRegrid ================ +.. currentmodule:: cdms2.regrid2-gsRegrid -.. automodule:: regrid2.gsRegrid - :members: +.. autosummary:: + :toctree: generated/ Regrid - catchError - getTensorProduct - makeCurvilinear - makeCoordsCyclic - checkForCoordCut - handleCoordsCut - getIndices - getPeriodicities - del - find - setValidMask - setMask - computeWeights - apply - call - getNumValid - getNumDstPoints - getSRcGrid - getDstGrid - getIndicesAndWeights - extend - findIndices - testMakeCyclic - testHandleCut - test - funcl - func2 - testMasking - func1 - func2 + Regrid.catchError + Regrid.getTensorProduct + Regrid.makeCurvilinear + Regrid.makeCoordsCyclic + Regrid.checkForCoordCut + Regrid.handleCoordsCut + Regrid.getIndices + Regrid.getPeriodicities + Regrid.del + Regrid.find + Regrid.setValidMask + Regrid.setMask + Regrid.computeWeights + Regrid.apply + Regrid.call + Regrid.getNumValid + Regrid.getNumDstPoints + Regrid.getSRcGrid + Regrid.getDstGrid + Regrid.getIndicesAndWeights + Regrid.extend + Regrid.findIndices + Regrid.testMakeCyclic + Regrid.testHandleCut + Regrid.test + Regrid.funcl + Regrid.func2 + Regrid.testMasking + Regrid.func1 + Regrid.func2 diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst index 7e60ee85..ac244207 100644 --- a/docs/source/hgrid.rst +++ b/docs/source/hgrid.rst @@ -2,62 +2,63 @@ hgrid ===== +.. currentmodule:: cdms2.hgrid -.. automodule:: cdms2.hgrid - :members: +.. autosummary:: + :toctree: generated/ AbstractHorizontalGrid - flatten - genBounds - getAxis - getBounds - getLatitude - getLongitude - getMask - getMesh - getWeightsArray - listall - setMask - subGridRegion - hasCoordType - checkConvex - fixCutCells + AbstractHorizontalGrid.flatten + AbstractHorizontalGrid.genBounds + AbstractHorizontalGrid.getAxis + AbstractHorizontalGrid.getBounds + AbstractHorizontalGrid.getLatitude + AbstractHorizontalGrid.getLongitude + AbstractHorizontalGrid.getMask + AbstractHorizontalGrid.getMesh + AbstractHorizontalGridgetWeightsArray + AbstractHorizontalGrid.listall + AbstractHorizontalGrid.setMask + AbstractHorizontalGrid.subGridRegion + AbstractHorizontalGrid.hasCoordType + AbstractHorizontalGrid.checkConvex + AbstractHorizontalGrid.fixCutCells AbstractCurveGrid - clone - rpr - getMesh - getShape - genBounds - getAxis - getMask - size - writeScrip - toGenericGrid - toCurveGrid - writeToFile - writeg - write_gridspec - init_from_gridspec - init_from_gridspec_file - subSlice - getGridSlices - getIndex - intersect - getAxisList - isClose - checkAxes - reconcile - flatAxes + AbstractCurveGrid.clone + AbstractCurveGrid.rpr + AbstractCurveGrid.getMesh + AbstractCurveGrid.getShape + AbstractCurveGrid.genBounds + AbstractCurveGrid.getAxis + AbstractCurveGrid.getMask + AbstractCurveGrid.size + AbstractCurveGrid.writeScrip + AbstractCurveGrid.toGenericGrid + AbstractCurveGrid.toCurveGrid + AbstractCurveGrid.writeToFile + AbstractCurveGrid.writeg + AbstractCurveGrid.write_gridspec + AbstractCurveGrid.init_from_gridspec + AbstractCurveGrid.init_from_gridspec_file + AbstractCurveGrid.subSlice + AbstractCurveGrid.getGridSlices + AbstractCurveGrid.getIndex + AbstractCurveGrid.intersect + AbstractCurveGrid.getAxisList + AbstractCurveGrid.isClose + AbstractCurveGrid.checkAxes + AbstractCurveGrid.reconcile + AbstractCurveGrid.flatAxes DatasetCurveGrid - rpr + DatasetCurveGrid.rpr FileCurveGrid - rpr + FileCurveGrid.rpr TransientCurveGrid - rpr - toCurveGrid - readScripCurveGrid + TransientCurveGrid.rpr + TransientCurveGrid.toCurveGrid + TransientCurveGrid.readScripCurveGrid diff --git a/docs/source/mvBaseWriter.rst b/docs/source/mvBaseWriter.rst index 18dd6f64..34bfb29d 100644 --- a/docs/source/mvBaseWriter.rst +++ b/docs/source/mvBaseWriter.rst @@ -2,9 +2,11 @@ mvBaseWriter ============ +.. currentmodule:: cdms2.mvBaseWriter -.. automodule:: cdms2.mvBaseWriter - :members: +.. autosummary:: + :toctree: generated/ +: BaseWriter - write + BaseWriter.write diff --git a/docs/source/mvCdmsRegrid.rst b/docs/source/mvCdmsRegrid.rst index 92035524..8d0b4aee 100644 --- a/docs/source/mvCdmsRegrid.rst +++ b/docs/source/mvCdmsRegrid.rst @@ -2,17 +2,18 @@ mvCdmsRegrid ============ +.. currentmodule:: cdms2.mvCdmsRegrid -.. automodule:: cdms2.mvCdmsRegrid - :members: +.. autosummary:: + :toctree: generated/ CdmsRegrid - getboundlist - areCellsOk - projectToSphere - buildBounds - getBoundList - getCoordList - getDstDataShape - getAxisList - call + CdmsRegrid.getboundlist + CdmsRegrid.areCellsOk + CdmsRegrid.projectToSphere + CdmsRegrid.buildBounds + CdmsRegrid.getBoundList + CdmsRegrid.getCoordList + CdmsRegrid.getDstDataShape + CdmsRegrid.getAxisList + CdmsRegrid.call diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst index aceb02ff..343139d7 100644 --- a/docs/source/mvESMFRegrid.rst +++ b/docs/source/mvESMFRegrid.rst @@ -2,23 +2,25 @@ regrid2-mvESMFRegrid ==================== +.. currentmodule:: cdms2.regrid2-mvESMFRegrid + +.. autosummary:: + :toctree: generated/ -.. automodule:: regrid2.mvESMFRegrid - :members: ESMFRegrid - setCoords - computeWeights - apply - getDstGrid - getSrcAreas - getDstAreas - getSrcAreaFractions - getDstAreaFractions - getSrcLocalShape - getDstLocalShape - getSrcLocalSlab - getDstLocalSlab - fillInDiagnosticData + ESMFRegrid.setCoords + ESMFRegrid.computeWeights + ESMFRegrid.apply + ESMFRegrid.getDstGrid + ESMFRegrid.getSrcAreas + ESMFRegrid.getDstAreas + ESMFRegrid.getSrcAreaFractions + ESMFRegrid.getDstAreaFractions + ESMFRegrid.getSrcLocalShape + ESMFRegrid.getDstLocalShape + ESMFRegrid.getSrcLocalSlab + ESMFRegrid.getDstLocalSlab + ESMFRegrid.fillInDiagnosticData diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst index 2f216bb0..87c6d127 100644 --- a/docs/source/mvGenericRegrid.rst +++ b/docs/source/mvGenericRegrid.rst @@ -2,14 +2,16 @@ regrid2-mvGenericRegrid ======================= +.. currentmodule:: cdms2.regrid2-mvGenericRegrid + +.. autosummary:: + :toctree: generated/ -.. automodule:: regrid2.mvGenericRegrid - :members: GenericRegrid - guessPeriodicity - computeWeights - apply - getDstGrid - fillInDiagnosticData + GenericRegrid.guessPeriodicity + GenericRegrid.computeWeights + GenericRegrid.apply + GenericRegrid.getDstGrid + GenericRegrid.fillInDiagnosticData diff --git a/docs/source/mvSphereMesh.rst b/docs/source/mvSphereMesh.rst index 0b77b686..bcc1017e 100644 --- a/docs/source/mvSphereMesh.rst +++ b/docs/source/mvSphereMesh.rst @@ -2,14 +2,15 @@ mvSphereMesh ============ +.. currentmodule:: cdms2.mvSphereMesh -.. automodule:: cdms2.mvSphereMesh - :members: +.. autosummary:: + :toctree: generated/ SphereMesh - getXYZCoords - test2DRect - test2D - test3DRect - test3DposDown + SphereMesh.getXYZCoords + SphereMesh.test2DRect + SphereMesh.test2D + SphereMesh.test3DRect + SphereMesh.test3DposDown diff --git a/docs/source/mvVTKSGWriter.rst b/docs/source/mvVTKSGWriter.rst index 8ca9ecb5..02b41729 100644 --- a/docs/source/mvVTKSGWriter.rst +++ b/docs/source/mvVTKSGWriter.rst @@ -2,13 +2,14 @@ mvVTKSGWriter ============= +.. currentmodule:: cdms2.mvVTKSGWriter -.. automodule:: cdms2.mvVTKSGWriter - :members: +.. autosummary:: + :toctree: generated/ VTKSGWriter - write - test2DRect - test3D + VTKSGWriter.write + VTKSGWriter.test2DRect + VTKSGWriter.test3D diff --git a/docs/source/mvVTKUGWriter.rst b/docs/source/mvVTKUGWriter.rst index c50ee754..d16a9ce9 100644 --- a/docs/source/mvVTKUGWriter.rst +++ b/docs/source/mvVTKUGWriter.rst @@ -2,13 +2,15 @@ mvVTKUGWriter ============= +.. currentmodule:: cdms2.mvVTKUGWriter + +.. autosummary:: + :toctree: generated/ -.. automodule:: cdms2.mvVTKUGWriter - :members: VTKUGWriter - write - test2DRect - test3D + VTKUGWriter.write + VTKUGWriter.test2DRect + VTKUGWriter.test3D diff --git a/docs/source/mvVsWriter.rst b/docs/source/mvVsWriter.rst index cf50820f..dc2e978e 100644 --- a/docs/source/mvVsWriter.rst +++ b/docs/source/mvVsWriter.rst @@ -2,11 +2,13 @@ mvVsWriter ========== +.. currentmodule:: cdms2.mvVsWriter -.. automodule:: cdms2.mvVsWriter - :members: +.. autosummary:: + :toctree: generated/ +: VsWriter - write - test2DRect - test3D + VsWriter.write + VsWriter.test2DRect + VsWriter.test3D diff --git a/docs/source/restApi.rst b/docs/source/restApi.rst index a0d46d49..181d31a6 100644 --- a/docs/source/restApi.rst +++ b/docs/source/restApi.rst @@ -2,51 +2,52 @@ restApi ======= +.. currentmodule:: cdms2.restApi -.. automodule:: cdms2.restApi - :members: +.. autosummary:: + :toctree: generated/ esgfConnectionException esgfDatasetException esgfFilesException FacetConnection - get_xmlelement - make_facet_dict - get_xmlelement_count - make_facet_dict_count + FacetConnection.get_xmlelement + FacetConnection.make_facet_dict + FacetConnection.get_xmlelement_count + FacetConnection.make_facet_dict_count esgfConnection - getitem - setitem - search - generateRequest - request - extractTag - searchDatasets + esgfConnection.getitem + esgfConnection.setitem + esgfConnection.search + esgfConnection.generateRequest + esgfConnection.request + esgfConnection.extractTag + esgfConnection.searchDatasets esgfDataset - extractFiles - info - str - clearWebCache - saveCache - loadCache - clearOriginalQueryCache - clear - search + esgfDataset.extractFiles + esgfDataset.info + esgfDataset.str + esgfDataset.clearWebCache + esgfDataset.saveCache + esgfDataset.loadCache + esgfDataset.clearOriginalQueryCache + esgfDataset.clear + esgfDataset.search esgfFiles - getitem - setitem - len - getMapping - getMappingKeys - setMapping - remap + esgfFiles.getitem + esgfFiles.setitem + esgfFiles.len + esgfFiles.getMapping + esgfFiles.getMappingKeys + esgfFiles.setMapping + esgfFiles.remap esgfFile - getitem - setitem - str + esgfFile.getitem + esgfFile.setitem + esgfFile.str diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst index c8039991..9dfabf32 100644 --- a/docs/source/scrip.rst +++ b/docs/source/scrip.rst @@ -2,30 +2,32 @@ regrid2-scrip ============= +.. currentmodule:: cdms2.regrid2-scrip + +.. autosummary:: + :toctree: generated/ -.. automodule:: regrid2.scrip - :members: ScripRegridder - call - getOutputGrid - getInputGrid - getSourceFraction - getDestinationFraction + ScripRegridder.call + ScripRegridder.getOutputGrid + ScripRegridder.getInputGrid + ScripRegridder.getSourceFraction + ScripRegridder.getDestinationFraction ConservativeRegridder - getSourceArea - getDestinationArea - regrid + ConservativeRegridder.getSourceArea + ConservativeRegridder.getDestinationArea + ConservativeRegridder.regrid BilinearRegridder - regrid + BilinearRegridder.regrid BicubicRegridder - call + BicubicRegridder.call DistwgtRegridder - regrid - readRegridder + DistwgtRegridder.regrid + DistwgtRegridder.readRegridder diff --git a/docs/source/selectors.rst b/docs/source/selectors.rst index 564e9350..56a0f6ba 100644 --- a/docs/source/selectors.rst +++ b/docs/source/selectors.rst @@ -2,52 +2,53 @@ selectors ========= +.. currentmodule:: cdms2.selectors + +.. autosummary:: + :toctree: generated/ -.. automodule:: cdms2.selectors - :members: - SelectorError Selector - components - refine - repr - and - clone - call - select - unmodifiedselect + Selector.components + Selector.refine + Selector.repr + Selector.and + Selector.clone + Selector.call + Selector.select + Selector.unmodifiedselect SelectorComponent - specify - specifyGrid - post + SelectorComponent.specify + SelectorComponent.specifyGrid + SelectorComponent.post axisComponent - specify - repr + axisComponent.specify + axisComponent.repr coordinateComponent - specifyGrid + coordinateComponent.specifyGrid requiredComponent - specify + requiredComponent.specify indexComponent indexedComponent - specify + indexedComponent.specify positionalComponent - specify - repr - longitude - latitude - time - level - required - kwselect - timeslice - latitudeslice - longitudeslice - levelslice - setslice + positionalComponent.specify + positionalComponent.repr + positionalComponent.longitude + positionalComponent.latitude + positionalComponent.time + positionalComponent.level + positionalComponent.required + positionalComponent.kwselect + positionalComponent.timeslice + positionalComponent.latitudeslice + positionalComponent.longitudeslice + positionalComponent.levelslice + positionalComponent.setslice diff --git a/docs/source/slabinterface.rst b/docs/source/slabinterface.rst index 938e2f78..085ba699 100644 --- a/docs/source/slabinterface.rst +++ b/docs/source/slabinterface.rst @@ -2,22 +2,23 @@ slabinterface ============= +.. currentmodule:: cdms2.slabinterface -.. automodule:: cdms2.slabinterface - :members: +.. autosummary:: + :toctree: generated/ Slab - getattribute - setattribute - createattribute - deleteattribute - listattributes - listdimattributes - getdimattribute - showdim - listdimnames - listall - info - cdms_bounds2cu_bounds + Slab.getattribute + Slab.setattribute + Slab.createattribute + Slab.deleteattribute + Slab.listattributes + Slab.listdimattributes + Slab.getdimattribute + Slab.showdim + Slab.listdimnames + Slab.listall + Slab.info + Slab.cdms_bounds2cu_bounds From 556d92f6ad968ed9e77eb386a0f4be52e3538169 Mon Sep 17 00:00:00 2001 From: Lina Muryanto <35277663+muryanto1@users.noreply.github.com> Date: Wed, 8 Aug 2018 09:49:13 -0700 Subject: [PATCH 206/239] Revisit run tests (#262) * migrate run_tests.py to use TestRunnerBase * remove accidentally added tests/coverage.json * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * revisit run_tests.py * add cacert.pem in run_tests.py when running cdms test within the lab * add cacert.pem in run_tests.py when running cdms test within the lab * add cacert.pem in run_tests.py when running cdms test within the lab * add cacert.pem in run_tests.py when running cdms test within the lab - rerun tests * add cacert.pem in run_tests.py when running cdms test within the lab - remove install from -c cdat/label/unstable * put back -c cdat/label/unstable --- .circleci/config.yml | 17 +- run_tests.py | 362 +++++++++------------------------------ tests/cdms_runtests.json | 8 + 3 files changed, 98 insertions(+), 289 deletions(-) create mode 100644 tests/cdms_runtests.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e1432ed..4b1a83a6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,8 +22,8 @@ aliases: conda config --set always_yes yes --set changeps1 no conda update -y -q conda conda config --set anaconda_upload no - conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" - conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 "python<3" + conda create -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info testsrunner numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python>3" + conda create -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge -c cdat libcf distarray cdtime libcdms cdat_info testsrunner numpy esmf esmpy libdrs_f pyopenssl nose requests flake8 myproxyclient "python<3" if [ $(uname) == "Linux" ]; then conda install -n py3 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 conda install -n py2 -c cdat/label/unstable -c cdat/label/nightly -c conda-forge gcc_linux-64 @@ -38,17 +38,10 @@ aliases: export PATH=$HOME/project/$WORKDIR/miniconda/bin:$PATH export UVCDAT_ANONYMOUS_LOG=False source activate py3 - mkdir $HOME/.esg - echo "Get ESGF certificates" - echo ${ESGF_PWD} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l ${ESGF_USER} -o $HOME/.esg/esgf.cert - echo "Create .dods_cookies" - curl -L -v -c $HOME/.esg/.dods_cookies --cert $HOME/.esg/esgf.cert --key $HOME/.esg/esgf.cert "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" if [ $(uname) == "Linux" ];then - cp tests/dodsrccircleciLinux $HOME/.dodsrc export LDSHARED="$CC -shared -pthread" LDSHARED="$CC -shared -pthread" python setup.py install else - cp tests/dodsrccircleciDarwin $HOME/.dodsrc python setup.py install fi source activate py2 @@ -67,11 +60,11 @@ aliases: export UVCDAT_ANONYMOUS_LOG=False set -e source activate py2 - python run_tests.py -v2 + python run_tests.py --subdir -v2 PY2_RESULT=$? - echo "*** py2 test result: "${PY2_RESULT} + echo "**** py2 test result: "${PY2_RESULT} source activate py3 - python run_tests.py -v2 + python run_tests.py --subdir -v2 PY3_RESULT=$? echo "*** py3 test result: "${PY3_RESULT} echo $PY2_RESULT > $HOME/project/$WORKDIR/py2_result.txt diff --git a/run_tests.py b/run_tests.py index 287a7814..ce3e7df9 100644 --- a/run_tests.py +++ b/run_tests.py @@ -1,291 +1,99 @@ -#!/usr/bin/env python -from __future__ import print_function -import shutil -import glob -import sys import os -import argparse -import multiprocessing -import subprocess -import codecs -import time -import webbrowser -import shlex +import sys +import shutil import cdat_info -import numpy.distutils -import distutils - -root = os.getcwd() -cpus = multiprocessing.cpu_count() - -parser = argparse.ArgumentParser(description="Run VCS tests", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) -parser.add_argument("-H", "--html", action="store_true", - help="create and show html result page") -parser.add_argument("-p", "--package", action="store_true", - help="package test results") - -parser.add_argument( - "-c", - "--coverage", - action="store_true", - help="run coverage (not implemented)") -parser.add_argument( - "-v", - "--verbosity", - default=1, - choices=[ - 0, - 1, - 2], - type=int, - help="verbosity output level") -parser.add_argument( - "-n", - "--cpus", - default=cpus, - type=int, - help="number of cpus to use") -parser.add_argument( - "-f", - "--failed-only", - action="store_true", - default=False, - help="runs only tests that failed last time and are in the list you provide") -parser.add_argument("-s","--subdir",action="store_true",help="run in a subdirectory") - -parser.add_argument("tests", nargs="*", help="tests to run") - -args = parser.parse_args() - - -def abspath(path, name, prefix): - full_path = os.path.abspath(os.path.join(os.getcwd(), "..", path)) - if not os.path.exists(name): - os.makedirs(name) - new = os.path.join(nm, prefix + "_" + os.path.basename(full_path)) - try: - shutil.copy(full_path, new) - except: - pass - return new - - -def findDiffFiles(log): - i = -1 - file1 = "" - file2 = "" - diff = "" - N = len(log) - while log[i].find("Source file") == -1 and i > -N: - i -= 1 - if i > -N: - file1 = log[i - 1].split()[-1] - for j in range(i, N): - if log[j].find("New best!") > -1: - if log[j].find("Comparing") > -1: - file2 = log[j].split()[2] - else: - k = j - 1 - while log[k].find("Comparing") == -1 and k > -N: - k -= 1 - try: - file2 = log[k].split()[2] - except: - file2 = log[k].split()[1][:-1]+log[j].split()[0] - print(("+++++++++++++++++++++++++",file2)) - if log[j].find("Saving image diff") > -1: - diff = log[j].split()[-1] - # break - return file1, file2, diff - - -def run_command(command, join_stderr=True): - if isinstance(command, str): - command = shlex.split(command) - if args.verbosity > 0: - print("Executing %s in %s" % (" ".join(command), os.getcwd())) - if join_stderr: - stderr = subprocess.STDOUT - else: - stderr = subprocess.PIPE - P = subprocess.Popen( - command, - stdout=subprocess.PIPE, - stderr=stderr, - bufsize=0, - cwd=os.getcwd()) - out = [] - while P.poll() is None: - read = P.stdout.readline().rstrip() - out.append(read) - if args.verbosity > 1 and len(read) != 0: - print(read) - return P, out - - -def run_nose(test_name): - opts = [] - if args.coverage: - opts += ["--with-coverage"] - command = ["nosetests", ] + opts + ["-s", test_name] - start = time.time() - P, out = run_command(command) - end = time.time() - return {test_name: {"result": P.poll(), "log": out, "times": { - "start": start, "end": end}}} - - -sys.path.append( - os.path.join( - os.path.dirname( - os.path.abspath(__file__)), - "tests")) - - -if len(args.tests) == 0: - names = glob.glob("tests/test_*.py") -else: - names = set(args.tests) - - -if args.failed_only and os.path.exists(os.path.join("tests",".last_failure")): - if not os.path.exists("tests"): - os.makedirs("tests") - f = open(os.path.join("tests",".last_failure")) - failed = set(eval(f.read().strip())) - f.close() - new_names = [] - for fnm in failed: - if fnm in names: - new_names.append(fnm) - names = new_names +import socket + +from testsrunner.Util import run_command +import tempfile + +SUCCESS = 0 + +class CDMSTestRunner(cdat_info.TestRunnerBase): + + def __setup_cdms(self): + home = os.environ["HOME"] + esg_dir = "{h}/.esg".format(h=home) + if os.path.isdir(esg_dir): + shutil.rmtree(esg_dir) + os.mkdir(esg_dir) + + # check if we are running tests from within the lab. + hostname = socket.gethostname() + cacert_pem = "" + if hostname.endswith('.llnl.gov'): + cmd = "curl https://access.llnl.gov/cspca.cer -o {h}/cspca.cer".format(h=home) + ret_code, out = run_command(cmd) + if ret_code != SUCCESS: + return ret_code + + python_ver = "python{a}.{i}".format(a=sys.version_info.major, + i=sys.version_info.minor) + coverage_opts = "" + dest = os.path.join(sys.prefix, 'lib', python_ver, 'site-packages', 'certifi', 'cacert.pem') + cmd = "cat {h}/cspca.cer >> {dest}".format(h=home, dest=dest) + cacert_pem = "--cacert {cacert}".format(cacert=dest) + + esgf_pwd = os.environ["ESGF_PWD"] + esgf_user = os.environ["ESGF_USER"] + cmd = "echo {p} | myproxyclient logon -s esgf-node.llnl.gov -p 7512 -t 12 -S -b -l {u} -o {h}/.esg/esgf.cert".format(p=esgf_pwd, u=esgf_user, h=home) + os.system(cmd) + + cookies = "-c {h}/.esg/.dods_cookies".format(h=home) + cert_opt = "--cert {h}/.esg/esgf.cert".format(h=home) + key_opt = "--key {h}/.esg/esgf.cert".format(h=home) + dds = "https://aims3.llnl.gov/thredds/dodsC/cmip5_css02_data/cmip5/output1/CMCC/CMCC-CM/decadal2005/mon/atmos/Amon/r1i1p1/cct/1/cct_Amon_CMCC-CM_decadal2005_r1i1p1_202601-203512.nc.dds" + cmd = "curl -L -v {cacert} {cookies} {cert} {key} \"{dds}\"".format(cacert=cacert_pem, + cookies=cookies, + cert=cert_opt, + key=key_opt, + dds=dds) + print("CMD: {cmd}".format(cmd=cmd)) + os.system(cmd) + + if sys.platform == 'darwin': + cmd = "cp tests/dodsrccircleciDarwin {h}/.dodsrc".format(h=home) + else: + cmd = "cp tests/dodsrccircleciLinux {h}/.dodsrc".format(h=home) + ret_code, out = run_command(cmd) + return ret_code -if args.subdir: - import tempfile - tmpdir = tempfile.mkdtemp() - os.chdir(tmpdir) - names = [ os.path.join(root,t) for t in names] - print("RUNNNIG FROM:",tmpdir) + def run(self, workdir, tests=None): -if len(names)==0: - print("No tests to run") - sys.exit(0) + os.chdir(workdir) + test_names = super(CDMSTestRunner, self)._get_tests(workdir, self.args.tests) -if args.verbosity > 1: - print(("Names:", names)) + ret_code = self.__setup_cdms() + if ret_code != SUCCESS: + return(ret_code) -# Make sure we have sample data -cdat_info.download_sample_data_files(os.path.join(distutils.sysconfig.get_python_lib(),"share","cdms2","test_data_files.txt"),cdat_info.get_sampledata_path()) + if self.args.checkout_baseline: + ret_code = super(CDMSTestRunner, self)._get_baseline(workdir) + if ret_code != SUCCESS: + return(ret_code) -p = multiprocessing.Pool(args.cpus) -outs = p.map(run_nose, names) -results = {} -failed = [] -for d in outs: - results.update(d) - nm = list(d.keys())[0] - if d[nm]["result"] != 0: - failed.append(nm) -if args.subdir: - f = open(os.path.join(root,"tests",".last_failure"),"w") -else: - f = open(os.path.join("tests",".last_failure"),"w") -f.write(repr(failed)) -f.close() + if self.args.subdir: + tmpdir = tempfile.mkdtemp() + os.chdir(tmpdir) + ret_code = super(CDMSTestRunner, self)._do_run_tests(workdir, test_names) + os.chdir(workdir) -if args.verbosity > 0: - print("Ran %i tests, %i failed (%.2f%% success)" %\ - (len(outs), len(failed), 100. - float(len(failed)) / len(outs) * 100.)) - if len(failed) > 0: - print("Failed tests:") - for f in failed: - print("\t", f) -if args.html or args.package: - if not os.path.exists("tests_html"): - os.makedirs("tests_html") - os.chdir("tests_html") + if self.args.html or self.args.package: + super(CDMSTestRunner, self)._generate_html(workdir) - js = "" + if self.args.package: + super(CDMSTestRunner, self)._package_results(workdir) - fi = open("index.html", "w") - print("", file=fi) - print("""VCS Test Results %s - - - - - """ % time.asctime(), file=fi) - print("

VCS Test results: %s

" % time.asctime(), file=fi) - print("", file=fi) - print("", file=fi) - print("", file=fi) + return ret_code - for t in sorted(results.keys()): - result = results[t] - nm = t.split("/")[-1][:-3] - print("" % nm, end=' ', file=fi) - fe = codecs.open("%s.html" % nm, "w", encoding="utf-8") - print("", file=fe) - print("%s" % nm, file=fe) - if result["result"] == 0: - print("" % nm, end=' ', file=fi) - print("", file=fe) - print("Back To Results List", file=fe) - else: - print("" % nm, end=' ', file=fi) - print("" % js, file=fe) - print("Back To Results List", file=fe) - print("

Failed test: %s on %s

" % (nm, time.asctime()), file=fe) - file1, file2, diff = findDiffFiles(result["log"]) - if file1 != "": - print('
' % ( - abspath(file2, nm, "test"), abspath(file1, nm, "source")), file=fe) - print("", file=fe) - print("
diff file
" % abspath( - diff, nm, "diff"), file=fe) - print("", file=fe) - print('

Log

%s
' % "\n".join(result[ - "log"]), file=fe) - print("Back To Results List", file=fe) - print("", file=fe) - fe.close() - t = result["times"] - print("" % ( - time.ctime(t["start"]), time.ctime(t["end"]), t["end"] - t["start"]), file=fi) - print("
TestResultStart TimeEnd TimeTime
TestResultStart TimeEnd TimeTime
%sOKFail%s%s%s
", file=fi) - fi.close() - if args.html: - webbrowser.open("file://%s/index.html" % os.getcwd()) -else: - if len(failed) == 0 and args.subdir: - print("Remving temp run dir: %s" % tmpdir) - os.chdir(root) - shutil.rmtree(tmpdir) +test_suite_name = 'cdms' -if args.package: - import tarfile - os.chdir(tmpdir) - tnm = "results_%s_%s_%s.tar.bz2" % (os.uname()[0],os.uname()[1],time.strftime("%Y-%m-%d_%H:%M")) - t = tarfile.open(tnm, "w:bz2") - print("PATH TARRING FROM: %s" % os.getcwd()) - t.add("tests_html") - t.add("tests_html") - t.close() - if args.verbosity > 0: - print("Packaged Result Info in:", tnm) +workdir = os.getcwd() +runner = CDMSTestRunner(test_suite_name, options=["--subdir"], + options_files=["tests/cdms_runtests.json"], + get_sample_data=True, + test_data_files_info="share/test_data_files.txt") +ret_code = runner.run(workdir) -if args.subdir and len(failed)!=0: - print("Do not removing to clean temp directory: %s" % tmpdir) -os.chdir(root) -sys.exit(len(failed)) +sys.exit(ret_code) diff --git a/tests/cdms_runtests.json b/tests/cdms_runtests.json new file mode 100644 index 00000000..2870a7a5 --- /dev/null +++ b/tests/cdms_runtests.json @@ -0,0 +1,8 @@ +{ + "--subdir": { + "action": "store_true", + "default": true, + "help": "specifies if tests should be run in a subdir", + "type": null + } +} From d474e9ca76d768e73dff2297b4ad39ec973a7fa5 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 20 Aug 2018 14:00:24 -0700 Subject: [PATCH 207/239] fix Axis.py --- Lib/axis.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index c097e351..70c93069 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -271,9 +271,10 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', meaning for the right-hand point. The third character indicates how the intersection of the interval and axis is treated: - 'n' - the node is in the interval - - 'b' - the interval intersects the cell bounds + 'n' - the node is in the interval + 'b' - the interval intersects the cell bounds + 's' - the cell bounds are a subset of the interval + 'e' - same as 'n', plus an extra node on either side. Returns ------- @@ -1722,13 +1723,13 @@ def clone(self, copyData=1): else: mycopy = createAxis(self[:]) mycopy.id = self.id + mycopy.__dict__.update(self.__dict__.copy()) + mycopy._obj_ = None # Erase Cdfile object if exist try: mycopy.setBounds(b, isGeneric=isGeneric[0]) except CDMSError: b = mycopy.genGenericBounds() mycopy.setBounds(b, isGeneric=False) - for k, v in list(self.attributes.items()): - setattr(mycopy, k, v) return mycopy def listall(self, all=None): @@ -1929,16 +1930,16 @@ def __init__(self, data, bounds=None, id=None, self._data_ = data[:] else: self._data_ = numpy.array(data[:]) - elif isinstance(data, numpy.ma.MaskedArray): - if numpy.ma.getmask(data).any() is numpy.bool_(True): - raise CDMSError( - 'Cannot construct an axis with a missing value.') - data = data.data + elif isinstance(data, numpy.ndarray): if copy == 0: self._data_ = data else: self._data_ = numpy.array(data) - elif isinstance(data, numpy.ndarray): + elif isinstance(data, numpy.ma.MaskedArray): + if numpy.ma.getmask(data) is not numpy.ma.nomask: + raise CDMSError( + 'Cannot construct an axis with a missing value.') + data = data.data if copy == 0: self._data_ = data else: From 6e40d4c276f6e7fcd00e6ce6354d1d667cc94846 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 20 Aug 2018 16:48:17 -0700 Subject: [PATCH 208/239] update documentation --- Lib/cache.py | 13 +++++++++++ Lib/cdurllib.py | 6 +++++ Lib/cdxmllib.py | 3 +++ Lib/database.py | 11 +++++++++ Lib/forecast.py | 1 + docs/generatedRST.py | 2 +- docs/source/API.rst | 6 +---- docs/source/cache.rst | 19 ++++++++-------- docs/source/cdurllib.rst | 18 ++++++++++----- docs/source/cdxmllib.rst | 18 --------------- docs/source/cudsinterface.rst | 42 ++++++++++++++++------------------- docs/source/database.rst | 31 ++------------------------ docs/source/forecast.rst | 17 +++++--------- docs/source/index.rst | 24 +------------------- 14 files changed, 85 insertions(+), 126 deletions(-) diff --git a/Lib/cache.py b/Lib/cache.py index cd1ba0cd..396edb17 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -299,6 +299,10 @@ def __init__(self): def get(self, filekey): """ Get the path associated with , or None if not present. +Parameters +---------- + + filekey for cache """ filekey = str(filekey) lock("index_lock") @@ -318,6 +322,10 @@ def get(self, filekey): def put(self, filekey, path): """ cache[filekey] = path +Parameters +---------- + + filekey for cache """ filekey = str(filekey) @@ -341,6 +349,11 @@ def put(self, filekey, path): def deleteEntry(self, filekey): """ Delete a cache index entry. + +Parameters +---------- + + filekey for cache """ filekey = str(filekey) diff --git a/Lib/cdurllib.py b/Lib/cdurllib.py index 9caac63f..dd8ec1f6 100644 --- a/Lib/cdurllib.py +++ b/Lib/cdurllib.py @@ -20,10 +20,14 @@ def __init__(self, proxies=None): # Attach an object to be returned with callbacks def setUserObject(self, userObject): + """ + """ self._userObject = userObject # Use FTP protocol def open_ftp(self, url): + """ + """ host, path = urllib.parse.splithost(url) if not host: raise IOError('ftp error', 'no host given') @@ -85,6 +89,8 @@ def open_ftp(self, url): raise IOError('ftp error', msg).with_traceback(sys.exc_info()[2]) def retrieve(self, url, filename=None, reporthook=None, blocksize=262144): + """ + """ url = urllib.unwrap(url) if self.tempcache and url in self.tempcache: return self.tempcache[url] diff --git a/Lib/cdxmllib.py b/Lib/cdxmllib.py index 81507bbd..8443f13f 100644 --- a/Lib/cdxmllib.py +++ b/Lib/cdxmllib.py @@ -145,6 +145,9 @@ def __fixdict(self, dict): # Interface -- reset this instance. Loses all unprocessed data def reset(self): + """ + Reset this instance. Loses all unprocessed data + """ self.rawdata = '' self.stack = [] self.nomoretags = 0 diff --git a/Lib/database.py b/Lib/database.py index 05fadac5..f8085181 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -225,14 +225,23 @@ def __del__(self): self.close() def normalizedn(self, dn): + """ + Returns + ------- + string + """ explodeddn = ldap.explode_dn(dn) return string.join(explodeddn, ',') def cachecdml(self, name, cdml, datapath): + """ + """ normaldn = self.normalizedn(name) self._cdmlcache_[normaldn] = (cdml, datapath) def getDataset(self, dn): + """ + """ normaldn = self.normalizedn(dn) if normaldn in self._cache_: dataset = self._cache_[normaldn] @@ -262,6 +271,8 @@ def getDataset(self, dn): return dataset def getObjFromDataset(self, dn): + """ + """ # Get the parent dataset explodeddn = ldap.explode_dn(dn) diff --git a/Lib/forecast.py b/Lib/forecast.py index 0653b64f..f5f42e61 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -113,6 +113,7 @@ def __init__(self, tau0time, dataset_list, path="."): self.file = cdms2.open(self.filename) def close(self): + """close file.""" self.file.close() def __call__(self, varname): diff --git a/docs/generatedRST.py b/docs/generatedRST.py index bd2bf500..27625c00 100644 --- a/docs/generatedRST.py +++ b/docs/generatedRST.py @@ -54,7 +54,7 @@ def createRSTfiles(modules): RSTwrite(module, cdms2_all_list) if __name__ == "__main__": - modules = ["cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] + modules = ["cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] createRSTfiles(modules) diff --git a/docs/source/API.rst b/docs/source/API.rst index 19a0495d..325f6525 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -14,13 +14,11 @@ Classes ":ref:`axis`", "CDMS Axis objects" ":ref:`fvariable`", "CDMS File-based variables." ":ref:`bindex`", "Bin index for non-rectilinear grids" - ":ref:`variable`", "DatasetVariable: Dataset-based variables" ":ref:`cache`", "CDMS cache management and file movement objects" - ":ref:`CDML`", "CDML Document Type Definition This defines the CDML language" + ":ref:`variable`", "DatasetVariable: Dataset-based variables" ":ref:`cdurllib`", "Customized URLopener" ":ref:`cdurlparse`", "Parse (absolute and relative) URLs." ":ref:`cdxmllib`", "A parser for XML, using the derived class as static DTD." - ":ref:`convention`", "metadata conventions" ":ref:`coord`", "CDMS CoordinateAxis objects" ":ref:`cudsinterface`", "Emulation of old cu package" ":ref:`database`", "CDMS database objects" @@ -49,11 +47,9 @@ Classes bindex variable cache - CDML cdurllib cdurlparse cdxmllib - convention coord cudsinterface database diff --git a/docs/source/cache.rst b/docs/source/cache.rst index 242984d2..cb7f6bba 100644 --- a/docs/source/cache.rst +++ b/docs/source/cache.rst @@ -7,20 +7,19 @@ cache .. autosummary:: :toctree: generated/ - Cache + copyFile + lock + unlock + lockpath + useWindow + useTTY + useGlobusTransfer + usePythonTransfer + useRequestManagerTransfer Cache.get Cache.put Cache.deleteEntry - Cache.copyFile Cache.getFile Cache.delete Cache.clean - Cache.lock - Cache.unlock - Cache.lockpath - Cache.useWindow - Cache.useTTY - Cache.useGlobusTransfer - Cache.usePythonTransfer - Cache.useRequestManagerTransfer diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst index ea700f0d..f7910f31 100644 --- a/docs/source/cdurllib.rst +++ b/docs/source/cdurllib.rst @@ -7,9 +7,17 @@ cdurllib .. autosummary:: :toctree: generated/ - CDURLopener - CDURLopener.setUserObject - CDURLopener.open_tfp - CDURLopener.retrieve - CDURLopener.sampleReportHook + CDURLopener.addheader + CDURLopener.http_error_default + CDURLopener.http_error + CDURLopener.open_data + CDURLopener.open_file + CDURLopener._open_generic_http + CDURLopener.open_http + CDURLopener.open_https + CDURLopener.open_local_file + CDURLopener.open + CDURLopener.open_unknown_proxy + CDURLopener.open_unknown + diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst index bb03be6d..29edcf08 100644 --- a/docs/source/cdxmllib.rst +++ b/docs/source/cdxmllib.rst @@ -8,7 +8,6 @@ cdxmllib :toctree: generated/ - XMLParser XMLParser.fixelements XMLParser.fixclass XMLParser.fixdict @@ -44,20 +43,3 @@ cdxmllib XMLParser.unknown_charref XMLParser.unknown_entityref - TextXMLParser - TextXMLParser.handle_xml - TextXMLParser.handle_data - TextXMLParser.flush - TextXMLParser.handle_cdata - TextXMLParser.handle_proc - TextXMLParser.handle_comment - TextXMLParser.syntax_error - TextXMLParser.unknown_starttag - TextXMLParser.unknown_endtag - TextXMLParser.unknown_entityref - TextXMLParser.unknown_charref - TextXMLParser.close - TextXMLParser.test - - - diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst index befbfb21..52f40170 100644 --- a/docs/source/cudsinterface.rst +++ b/docs/source/cudsinterface.rst @@ -7,27 +7,23 @@ cudsinterface .. autosummary:: :toctree: generated/ - cuDataSet - cuDataSet.call - cuDataSet.getitem - cuDataSet.v - cuDataSet.defaultvariable - cuDataSet.cleardefault - cuDataSet.listall - cuDataSet.listattribute - cuDataSet.listdimension - cuDataSet.listglobal - cuDataSet.listvariable - cuDataSet.showglobal - cuDataSet.showvariable - cuDataSet.showattribute - cuDataSet.showdimension - cuDataSet.showall - cuDataSet.dimensionobject - cuDataSet.dimensionarray - cuDataSet.getdimensionunits - cuDataSet.getglobal - cuDataSet.getattribute - cuDataSet.getslab - cuDataSet.readScripGrid + cuDataset.default_variable + cuDataset.cleardefault + cuDataset.listall + cuDataset.listattribute + cuDataset.listdimension + cuDataset.listglobal + cuDataset.listvariable + cuDataset.showglobal + cuDataset.showvariable + cuDataset.showattribute + cuDataset.showdimension + cuDataset.showall + cuDataset.dimensionobject + cuDataset.dimensionarray + cuDataset.getdimensionunits + cuDataset.getglobal + cuDataset.getattribute + cuDataset.getslab + cuDataset.readScripGrid diff --git a/docs/source/database.rst b/docs/source/database.rst index 1f8ea482..d5dd1066 100644 --- a/docs/source/database.rst +++ b/docs/source/database.rst @@ -7,45 +7,18 @@ database .. autosummary:: :toctree: generated/ - AbstractDatabase - AbstractDatabase.connect - AbstractDatabase.loadString - AbstractDatabase.close - AbstractDatabase.cachecdml - AbstractDatabase.getDataset - AbstractDatabase.getObjFromDataset - AbstractDatabase.openDataset - AbstractDatabase.searchFilter - AbstractDatabase.enableCache - AbstractDatabase.disableCache - AbstractDatabase.useRequestManager - AbstractDatabase.usingRequestManager - AbstractDatabase.repr + connect + loadString - LDAPDatabase LDAPDatabase.close - LDAPDatabase.del - LDAPDatabase.normalizedn - LDAPDatabase.cachecdml - LDAPDatabase.getDataset - LDAPDatabase.getObjFromDataset LDAPDatabase.openDataset - LDAPDatabase.setExternalDict LDAPDatabase.searchFilter LDAPDatabase.listDatasets - AbstractSearchResult - AbstractSearchResult.getitem - AbstractSearchResult.len AbstractSearchResult.searchPredicate - LDAPSearchResult - LDAPSearchResult.getitem LDAPSearchResult.searchPredicate - LDAPSearchResult.len - AbstractResultEntry AbstractResultEntry.getObject - LDAPResultEntry diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index 4a6eaf0a..970a73dc 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -2,26 +2,19 @@ forecast ======== -.. currentmodule:: cdms2.convention +.. currentmodule:: cdms2.forecast .. autosummary:: :toctree: generated/ - forecast - forecast.two_times_from_one - forecast.comptime + two_times_from_one + available_forecasts + comptime + forecast.close - forecast.call - forecast.getitem - forecast.rpr - forecast.available_forecasts forecasts forecasts.forecast_times_to_list forecasts.time_interval_to_list forecasts.reduce_inplace - forecasts.close - forecasts.call forecasts.forecast_axis - forecasts.getitem - forecasts.rpr diff --git a/docs/source/index.rst b/docs/source/index.rst index 3cbec1f9..8092b80a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,30 +23,8 @@ CDMS documentation manual/cdms_7 manual/cdms_appendix manual/sample_data + API -# AbstractAxis -# AbstractVariable -# avariable -# axis -# bindex -# cache -# cdmsfile -# cdmsobj -# database -# dataset -# fvariable -# gengrid -# grid -# gsHost -# gsStaticVariable -# gsTimeVariable -# hgrid -# MV2 -# mvSphereMesh -# mvCdmsRegrid -# selectors -# sliceut -# tvariable Indices and tables From cbb943ed3a1ebd67313d376f72493b87c010081c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 20 Aug 2018 17:01:29 -0700 Subject: [PATCH 209/239] fix environment dependencies --- docs/environment.yml | 166 +++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 92 deletions(-) diff --git a/docs/environment.yml b/docs/environment.yml index a687d9a7..fc2d8ad8 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -1,111 +1,93 @@ -name: readthedoctest +name: cdms2 channels: - conda-forge - defaults dependencies: - - asn1crypto=0.24.0=py27_0 - - ca-certificates=2018.4.16=0 + - alabaster=0.7.11=py_3 + - asn1crypto=0.24.0=py27_2 + - babel=2.6.0=py_1 + - bzip2=1.0.6=h470a237_2 + - ca-certificates=2018.8.13=ha4d7672_0 - cdat_info=8.0=py27_0 - - cdms2=3.0=py27_6 - - cdtime=3.0=py27_0 - - certifi=2018.4.16=py27_0 - - cffi=1.11.5=py27_0 - - chardet=3.0.4=py27_0 + - cdms2=3.0.1=py27h6091dcd_1 + - cdtime=3.0=py27h6091dcd_1 + - certifi=2018.8.13=py27_0 + - cffi=1.11.5=py27h5e8e0c9_1 + - chardet=3.0.4=py27_3 - clapack=3.2.1=0 - - colorama=0.3.9=py27_0 + - colorama=0.3.9=py_1 - colorlog=3.1.2=py27_0 - - cryptography=2.2.1=py27_0 - - curl=7.59.0=1 + - cryptography=2.3.1=py27hdffb7b8_0 + - cryptography-vectors=2.3.1=py27_0 + - curl=7.61.0=h93b3f91_1 - distarray=2.12.2=py27_0 - - easydev=0.9.36=py27_0 + - docutils=0.14=py27_0 + - easydev=0.9.36=py_1 - enum34=1.1.6=py27_1 - - esmf=7.1.0r=0 + - esmf=7.1.0r=1 - esmpy=7.1.0r=py27_1 - - g2clib=1.6.0=5 - - gmp=6.1.2=0 + - future=0.16.0=py27_2 + - g2clib=1.6.0=3 - hdf4=4.2.13=0 - hdf5=1.10.1=2 - - idna=2.6=py27_1 + - idna=2.7=py27_2 + - imagesize=1.0.0=py_1 - ipaddress=1.0.22=py_1 - jasper=1.900.1=4 - - jpeg=9b=2 + - jinja2=2.10=py_1 + - jpeg=9c=h470a237_0 - krb5=1.14.6=0 - lapack=3.6.1=1 - - libcdms=3.0.1=0 - - libcf=1.0.1=py27_1 - - libdrs=3.0=0 - - libdrs_f=3.0=0 - - libffi=3.2.1=3 - - libnetcdf=4.4.1.1=10 - - libpng=1.6.34=0 - - libssh2=1.8.0=2 - - libtiff=4.0.9=0 - - mkl_fft=1.0.2=py27_0 - - mkl_random=1.0.1=py27_0 - - mpc=1.1.0=4 - - mpfr=3.1.5=0 - - mpi=1.0=mpich - - mpich=3.2.1=0 - - ncurses=5.9=10 - - netcdf-fortran=4.4.4=6 - - openssl=1.0.2o=0 - - ossuuid=1.6.2=0 - - pexpect=4.5.0=py27_0 - - pip=9.0.3=py27_0 - - ptyprocess=0.5.2=py27_0 - - pycparser=2.18=py27_0 - - pyopenssl=17.5.0=py27_1 - - pysocks=1.6.8=py27_1 - - python=2.7.14=5 - - readline=7.0=0 - - requests=2.18.4=py27_1 - - setuptools=39.0.1=py27_0 - - six=1.11.0=py27_1 - - sqlite=3.20.1=2 - - tk=8.6.7=0 - - urllib3=1.22=py27_0 - - wheel=0.31.0=py27_0 - - xz=5.2.3=0 - - zlib=1.2.11=0 - - alabaster=0.7.10=py27he5a193a_0 - - babel=2.5.3=py27_0 - - cloog=0.18.0=0 - - docutils=0.14=py27hae222c1_0 - - freetype=2.8=hab7d2ae_1 - - funcsigs=1.0.2=py27h83f16ab_0 - - future=0.16.0=py27_1 - - gcc=4.8.5=7 - - imagesize=1.0.0=py27_0 - - intel-openmp=2018.0.0=8 - - isl=0.12.2=0 - - jinja2=2.10=py27h4114e70_0 + - libcdms=3.0.1=h9ac9557_2 + - libcf=1.0.1=py27_2 + - libdrs=3.0.1=h6e3784b_3 + - libdrs_f=3.0.1=h2cd7f18_3 + - libffi=3.2.1=hfc679d8_4 - libgcc=7.2.0=h69d50b8_2 - - libgcc-ng=7.2.0=hdf63c60_3 - libgfortran=3.0.0=1 - libgfortran-ng=7.2.0=hdf63c60_3 - - libstdcxx-ng=7.2.0=hdf63c60_3 - - markupsafe=1.0=py27h97b2822_1 - - mkl=2018.0.2=1 - - mock=2.0.0=py27h0c0c831_0 - - numpy=1.14.2=py27hdbf6ddf_1 - - olefile=0.45.1=py27_0 - - packaging=17.1=py27_0 - - pbr=4.0.2=py27_0 - - pillow=5.1.0=py27h3deb7b8_0 - - pygments=2.2.0=py27h4a8b6f5_0 - - pyparsing=2.2.0=py27hf1513f8_1 - - pytz=2018.4=py27_0 - - snowballstemmer=1.2.1=py27h44e2768_0 - - sphinx=1.7.3=py27_0 - - sphinx_rtd_theme=0.3.0=py27_0 - - sphinxcontrib=1.0=py27h1512b58_1 - - sphinxcontrib-websupport=1.0.1=py27hf906f22_1 - - typing=3.6.4=py27_0 - - pip: - - commonmark==0.5.4 - - mv2==3.0.0 - - nilsimsa==0.3.8 - - readthedocs-sphinx-ext==0.5.10 - - recommonmark==0.4.0 - - regrid2==3.0.0 -prefix: /home/docs/.conda/envs/readthedoctest + - libnetcdf=4.6.1=2 + - libpng=1.6.35=ha92aebf_0 + - libssh2=1.8.0=h5b517e9_2 + - libtiff=4.0.9=he6b73bb_1 + - markupsafe=1.0=py27_0 + - mpi=1.0=mpich + - mpich=3.2.1=h26a2512_4 + - ncurses=6.1=hfc679d8_1 + - netcdf-fortran=4.4.4=7 + - openssl=1.0.2o=h470a237_1 + - ossuuid=1.6.2=hfc679d8_0 + - packaging=17.1=py_0 + - pexpect=4.6.0=py27_0 + - ptyprocess=0.6.0=py27_0 + - pycparser=2.18=py_1 + - pygments=2.2.0=py_1 + - pyopenssl=18.0.0=py27_0 + - pyparsing=2.2.0=py_1 + - pysocks=1.6.8=py27_1 + - python=2.7.15=h9fef7bc_0 + - pytz=2018.5=py_0 + - readline=7.0=haf1bffa_1 + - requests=2.19.1=py27_1 + - setuptools=40.0.0=py27_1 + - six=1.11.0=py27_1 + - snowballstemmer=1.2.1=py_1 + - sphinx=1.7.5=py27_0 + - sphinxcontrib-websupport=1.0.1=py27_0 + - sqlite=3.24.0=h2f33b56_0 + - tk=8.6.8=0 + - typing=3.6.4=py27_2 + - urllib3=1.23=py27_1 + - xz=5.2.4=h470a237_1 + - zlib=1.2.11=h470a237_3 + - binutils_impl_linux-64=2.31.1=h6176602_0 + - binutils_linux-64=2.31.1=h6176602_2 + - gcc_impl_linux-64=7.3.0=habb00fd_0 + - gcc_linux-64=7.3.0=h553295d_2 + - libgcc-ng=8.2.0=hdf63c60_1 + - libopenblas=0.2.20=h9ac9557_7 + - libstdcxx-ng=8.2.0=hdf63c60_1 + - numpy=1.14.3=py27h28100ab_1 + - numpy-base=1.14.3=py27h0ea5e3f_1 +prefix: /export/reshel3/anaconda52/envs/cdms2 + From 794a5e5bd735a144020c5eca4a6aecfd0cb860f3 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 20 Aug 2018 17:28:38 -0700 Subject: [PATCH 210/239] add/remote generated files --- docs/source/CDML.rst | 14 -------------- docs/source/CDMLParser.rst | 9 --------- docs/source/generated/cdms2.cache.Cache.clean.rst | 6 ++++++ .../generated/cdms2.cache.Cache.copyFile.rst | 6 ++++++ docs/source/generated/cdms2.cache.Cache.delete.rst | 6 ++++++ .../generated/cdms2.cache.Cache.deleteEntry.rst | 6 ++++++ docs/source/generated/cdms2.cache.Cache.get.rst | 6 ++++++ .../source/generated/cdms2.cache.Cache.getFile.rst | 6 ++++++ docs/source/generated/cdms2.cache.Cache.put.rst | 6 ++++++ docs/source/generated/cdms2.cache.copyFile.rst | 6 ++++++ docs/source/generated/cdms2.cache.lock.rst | 6 ++++++ docs/source/generated/cdms2.cache.lockpath.rst | 6 ++++++ docs/source/generated/cdms2.cache.unlock.rst | 6 ++++++ .../generated/cdms2.cache.useGlobusTransfer.rst | 6 ++++++ .../generated/cdms2.cache.usePythonTransfer.rst | 6 ++++++ .../cdms2.cache.useRequestManagerTransfer.rst | 6 ++++++ docs/source/generated/cdms2.cache.useTTY.rst | 6 ++++++ docs/source/generated/cdms2.cache.useWindow.rst | 6 ++++++ ...ms2.cdurllib.CDURLopener._open_generic_http.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.addheader.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.http_error.rst | 6 ++++++ ...ms2.cdurllib.CDURLopener.http_error_default.rst | 6 ++++++ .../generated/cdms2.cdurllib.CDURLopener.open.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_data.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_file.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_http.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_https.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_local_file.rst | 6 ++++++ .../cdms2.cdurllib.CDURLopener.open_unknown.rst | 6 ++++++ ...ms2.cdurllib.CDURLopener.open_unknown_proxy.rst | 6 ++++++ .../generated/cdms2.cdurlparse.clear_cache.rst | 6 ++++++ docs/source/generated/cdms2.cdurlparse.test.rst | 6 ++++++ .../generated/cdms2.cdurlparse.urldefrag.rst | 6 ++++++ docs/source/generated/cdms2.cdurlparse.urljoin.rst | 6 ++++++ .../source/generated/cdms2.cdurlparse.urlparse.rst | 6 ++++++ .../generated/cdms2.cdurlparse.urlunparse.rst | 6 ++++++ ...cdms2.convention.CFConvention.getAxisAuxIds.rst | 6 ++++++ .../cdms2.convention.CFConvention.getAxisIds.rst | 6 ++++++ ...nvention.CFConvention.getDsetnodeAuxAxisIds.rst | 6 ++++++ ...2.convention.CFConvention.getVariableBounds.rst | 6 ++++++ ...dms2.convention.COARDSConvention.getAxisIds.rst | 6 ++++++ .../cdms2.convention.NUGConvention.getAxisIds.rst | 6 ++++++ .../cdms2.convention.getDatasetConvention.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.__call__.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.__getitem__.rst | 6 ++++++ .../generated/cdms2.cudsinterface.cuDataset._v.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.cleardefault.rst | 6 ++++++ ...s2.cudsinterface.cuDataset.default_variable.rst | 6 ++++++ ...dms2.cudsinterface.cuDataset.dimensionarray.rst | 6 ++++++ ...ms2.cudsinterface.cuDataset.dimensionobject.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.getattribute.rst | 6 ++++++ ...2.cudsinterface.cuDataset.getdimensionunits.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.getglobal.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.getslab.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.listall.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.listattribute.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.listdimension.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.listglobal.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.listvariable.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.listvariables.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.readScripGrid.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.showall.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.showattribute.rst | 6 ++++++ ...cdms2.cudsinterface.cuDataset.showdimension.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.showglobal.rst | 6 ++++++ .../cdms2.cudsinterface.cuDataset.showvariable.rst | 6 ++++++ .../cdms2.database.AbstractDatabase.dump.rst | 6 ++++++ ...dms2.database.AbstractDatabase.matchPattern.rst | 6 ++++++ .../cdms2.database.AbstractDatabase.matchone.rst | 6 ++++++ ...ms2.database.AbstractDatabase.searchPattern.rst | 6 ++++++ ...2.database.AbstractDatabase.searchPredicate.rst | 6 ++++++ .../cdms2.database.AbstractDatabase.searchone.rst | 6 ++++++ ...dms2.database.AbstractResultEntry.getObject.rst | 6 ++++++ ...2.database.AbstractSearchResult.__getitem__.rst | 6 ++++++ ...cdms2.database.AbstractSearchResult.__len__.rst | 6 ++++++ ...tabase.AbstractSearchResult.searchPredicate.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.close.rst | 6 ++++++ .../generated/cdms2.database.LDAPDatabase.dump.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.listDatasets.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.matchPattern.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.matchone.rst | 6 ++++++ .../generated/cdms2.database.LDAPDatabase.open.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.openDataset.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.searchFilter.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.searchPattern.rst | 6 ++++++ ...cdms2.database.LDAPDatabase.searchPredicate.rst | 6 ++++++ .../cdms2.database.LDAPDatabase.searchone.rst | 6 ++++++ ...2.database.LDAPSearchResult.searchPredicate.rst | 6 ++++++ docs/source/generated/cdms2.database.connect.rst | 6 ++++++ .../source/generated/cdms2.database.loadString.rst | 6 ++++++ .../cdms2.forecast.available_forecasts.rst | 6 ++++++ docs/source/generated/cdms2.forecast.comptime.rst | 6 ++++++ .../generated/cdms2.forecast.forecast.__call__.rst | 6 ++++++ .../cdms2.forecast.forecast.__getitem__.rst | 6 ++++++ .../generated/cdms2.forecast.forecast.__init__.rst | 6 ++++++ .../cdms2.forecast.forecasts.__call__.rst | 6 ++++++ .../cdms2.forecast.forecasts.__getitem__.rst | 6 ++++++ .../cdms2.forecast.forecasts.__init__.rst | 6 ++++++ .../cdms2.forecast.forecasts.forecast_axis.rst | 6 ++++++ ...2.forecast.forecasts.forecast_times_to_list.rst | 6 ++++++ .../cdms2.forecast.forecasts.reduce_inplace.rst | 6 ++++++ ...s2.forecast.forecasts.time_interval_to_list.rst | 6 ++++++ .../cdms2.forecast.two_times_from_one.rst | 6 ++++++ 103 files changed, 606 insertions(+), 23 deletions(-) delete mode 100644 docs/source/CDML.rst delete mode 100644 docs/source/CDMLParser.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.clean.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.copyFile.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.delete.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.deleteEntry.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.get.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.getFile.rst create mode 100644 docs/source/generated/cdms2.cache.Cache.put.rst create mode 100644 docs/source/generated/cdms2.cache.copyFile.rst create mode 100644 docs/source/generated/cdms2.cache.lock.rst create mode 100644 docs/source/generated/cdms2.cache.lockpath.rst create mode 100644 docs/source/generated/cdms2.cache.unlock.rst create mode 100644 docs/source/generated/cdms2.cache.useGlobusTransfer.rst create mode 100644 docs/source/generated/cdms2.cache.usePythonTransfer.rst create mode 100644 docs/source/generated/cdms2.cache.useRequestManagerTransfer.rst create mode 100644 docs/source/generated/cdms2.cache.useTTY.rst create mode 100644 docs/source/generated/cdms2.cache.useWindow.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener._open_generic_http.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.addheader.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.http_error.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.http_error_default.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_data.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_file.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_http.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_https.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_local_file.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown.rst create mode 100644 docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown_proxy.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.clear_cache.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.test.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.urldefrag.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.urljoin.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.urlparse.rst create mode 100644 docs/source/generated/cdms2.cdurlparse.urlunparse.rst create mode 100644 docs/source/generated/cdms2.convention.CFConvention.getAxisAuxIds.rst create mode 100644 docs/source/generated/cdms2.convention.CFConvention.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.convention.CFConvention.getDsetnodeAuxAxisIds.rst create mode 100644 docs/source/generated/cdms2.convention.CFConvention.getVariableBounds.rst create mode 100644 docs/source/generated/cdms2.convention.COARDSConvention.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.convention.NUGConvention.getAxisIds.rst create mode 100644 docs/source/generated/cdms2.convention.getDatasetConvention.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.__call__.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.__getitem__.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset._v.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.cleardefault.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.default_variable.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionarray.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionobject.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.getattribute.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.getdimensionunits.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.getglobal.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.getslab.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listall.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listattribute.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listdimension.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listglobal.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listvariable.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.listvariables.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.readScripGrid.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.showall.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.showattribute.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.showdimension.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.showglobal.rst create mode 100644 docs/source/generated/cdms2.cudsinterface.cuDataset.showvariable.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.dump.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.matchPattern.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.matchone.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.searchPattern.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.database.AbstractDatabase.searchone.rst create mode 100644 docs/source/generated/cdms2.database.AbstractResultEntry.getObject.rst create mode 100644 docs/source/generated/cdms2.database.AbstractSearchResult.__getitem__.rst create mode 100644 docs/source/generated/cdms2.database.AbstractSearchResult.__len__.rst create mode 100644 docs/source/generated/cdms2.database.AbstractSearchResult.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.close.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.dump.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.listDatasets.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.matchPattern.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.matchone.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.open.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.openDataset.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.searchFilter.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.searchPattern.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.database.LDAPDatabase.searchone.rst create mode 100644 docs/source/generated/cdms2.database.LDAPSearchResult.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.database.connect.rst create mode 100644 docs/source/generated/cdms2.database.loadString.rst create mode 100644 docs/source/generated/cdms2.forecast.available_forecasts.rst create mode 100644 docs/source/generated/cdms2.forecast.comptime.rst create mode 100644 docs/source/generated/cdms2.forecast.forecast.__call__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecast.__getitem__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecast.__init__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.__call__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.__getitem__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.__init__.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.forecast_axis.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.forecast_times_to_list.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.reduce_inplace.rst create mode 100644 docs/source/generated/cdms2.forecast.forecasts.time_interval_to_list.rst create mode 100644 docs/source/generated/cdms2.forecast.two_times_from_one.rst diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst deleted file mode 100644 index 3ee8546c..00000000 --- a/docs/source/CDML.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _CDML: - -CDML -==== -.. currentmodule:: cdms2.CDML - -.. autosummary:: - :toctree: generated/ - - CDML - CDML.buildDTD - CDML.buildExtra - - diff --git a/docs/source/CDMLParser.rst b/docs/source/CDMLParser.rst deleted file mode 100644 index f2d801d9..00000000 --- a/docs/source/CDMLParser.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _CDMLParser: - -CDMLParser -========== - -.. automodule:: cdms2.CDMLParser - :members: - - diff --git a/docs/source/generated/cdms2.cache.Cache.clean.rst b/docs/source/generated/cdms2.cache.Cache.clean.rst new file mode 100644 index 00000000..c03d33b6 --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.clean.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.clean diff --git a/docs/source/generated/cdms2.cache.Cache.copyFile.rst b/docs/source/generated/cdms2.cache.Cache.copyFile.rst new file mode 100644 index 00000000..c3d25605 --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.copyFile.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.copyFile diff --git a/docs/source/generated/cdms2.cache.Cache.delete.rst b/docs/source/generated/cdms2.cache.Cache.delete.rst new file mode 100644 index 00000000..4b5fd1f0 --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.delete.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.delete diff --git a/docs/source/generated/cdms2.cache.Cache.deleteEntry.rst b/docs/source/generated/cdms2.cache.Cache.deleteEntry.rst new file mode 100644 index 00000000..7d65a32f --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.deleteEntry.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.deleteEntry diff --git a/docs/source/generated/cdms2.cache.Cache.get.rst b/docs/source/generated/cdms2.cache.Cache.get.rst new file mode 100644 index 00000000..7676981b --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.get.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.get diff --git a/docs/source/generated/cdms2.cache.Cache.getFile.rst b/docs/source/generated/cdms2.cache.Cache.getFile.rst new file mode 100644 index 00000000..22fd36d0 --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.getFile.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.getFile diff --git a/docs/source/generated/cdms2.cache.Cache.put.rst b/docs/source/generated/cdms2.cache.Cache.put.rst new file mode 100644 index 00000000..b0490823 --- /dev/null +++ b/docs/source/generated/cdms2.cache.Cache.put.rst @@ -0,0 +1,6 @@ +cdms2.cache:Cache +================= + +.. currentmodule:: cdms2.cache + +.. automethod:: Cache.put diff --git a/docs/source/generated/cdms2.cache.copyFile.rst b/docs/source/generated/cdms2.cache.copyFile.rst new file mode 100644 index 00000000..ce9ff869 --- /dev/null +++ b/docs/source/generated/cdms2.cache.copyFile.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: copyFile diff --git a/docs/source/generated/cdms2.cache.lock.rst b/docs/source/generated/cdms2.cache.lock.rst new file mode 100644 index 00000000..c49408eb --- /dev/null +++ b/docs/source/generated/cdms2.cache.lock.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: lock diff --git a/docs/source/generated/cdms2.cache.lockpath.rst b/docs/source/generated/cdms2.cache.lockpath.rst new file mode 100644 index 00000000..1e6f1120 --- /dev/null +++ b/docs/source/generated/cdms2.cache.lockpath.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: lockpath diff --git a/docs/source/generated/cdms2.cache.unlock.rst b/docs/source/generated/cdms2.cache.unlock.rst new file mode 100644 index 00000000..17cc4727 --- /dev/null +++ b/docs/source/generated/cdms2.cache.unlock.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: unlock diff --git a/docs/source/generated/cdms2.cache.useGlobusTransfer.rst b/docs/source/generated/cdms2.cache.useGlobusTransfer.rst new file mode 100644 index 00000000..aeb8064f --- /dev/null +++ b/docs/source/generated/cdms2.cache.useGlobusTransfer.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: useGlobusTransfer diff --git a/docs/source/generated/cdms2.cache.usePythonTransfer.rst b/docs/source/generated/cdms2.cache.usePythonTransfer.rst new file mode 100644 index 00000000..6906f0c0 --- /dev/null +++ b/docs/source/generated/cdms2.cache.usePythonTransfer.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: usePythonTransfer diff --git a/docs/source/generated/cdms2.cache.useRequestManagerTransfer.rst b/docs/source/generated/cdms2.cache.useRequestManagerTransfer.rst new file mode 100644 index 00000000..5084e76f --- /dev/null +++ b/docs/source/generated/cdms2.cache.useRequestManagerTransfer.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: useRequestManagerTransfer diff --git a/docs/source/generated/cdms2.cache.useTTY.rst b/docs/source/generated/cdms2.cache.useTTY.rst new file mode 100644 index 00000000..bb392776 --- /dev/null +++ b/docs/source/generated/cdms2.cache.useTTY.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: useTTY diff --git a/docs/source/generated/cdms2.cache.useWindow.rst b/docs/source/generated/cdms2.cache.useWindow.rst new file mode 100644 index 00000000..6c13e569 --- /dev/null +++ b/docs/source/generated/cdms2.cache.useWindow.rst @@ -0,0 +1,6 @@ +cdms2.cache +=========== + +.. currentmodule:: cdms2.cache + +.. autofunction:: useWindow diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener._open_generic_http.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener._open_generic_http.rst new file mode 100644 index 00000000..0a710c50 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener._open_generic_http.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener._open_generic_http diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.addheader.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.addheader.rst new file mode 100644 index 00000000..7a502568 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.addheader.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.addheader diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error.rst new file mode 100644 index 00000000..b3dab6fb --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.http_error diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error_default.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error_default.rst new file mode 100644 index 00000000..7617befd --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.http_error_default.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.http_error_default diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open.rst new file mode 100644 index 00000000..ba023f59 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_data.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_data.rst new file mode 100644 index 00000000..e8821a21 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_data.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_data diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_file.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_file.rst new file mode 100644 index 00000000..d188b166 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_file.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_file diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_http.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_http.rst new file mode 100644 index 00000000..dff0ad90 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_http.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_http diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_https.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_https.rst new file mode 100644 index 00000000..b33b4b36 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_https.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_https diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_local_file.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_local_file.rst new file mode 100644 index 00000000..fbecf6fa --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_local_file.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_local_file diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown.rst new file mode 100644 index 00000000..7d7795cb --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_unknown diff --git a/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown_proxy.rst b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown_proxy.rst new file mode 100644 index 00000000..65428393 --- /dev/null +++ b/docs/source/generated/cdms2.cdurllib.CDURLopener.open_unknown_proxy.rst @@ -0,0 +1,6 @@ +cdms2.cdurllib:CDURLopener +========================== + +.. currentmodule:: cdms2.cdurllib + +.. automethod:: CDURLopener.open_unknown_proxy diff --git a/docs/source/generated/cdms2.cdurlparse.clear_cache.rst b/docs/source/generated/cdms2.cdurlparse.clear_cache.rst new file mode 100644 index 00000000..e8b7365f --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.clear_cache.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: clear_cache diff --git a/docs/source/generated/cdms2.cdurlparse.test.rst b/docs/source/generated/cdms2.cdurlparse.test.rst new file mode 100644 index 00000000..307d10d6 --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.test.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: test diff --git a/docs/source/generated/cdms2.cdurlparse.urldefrag.rst b/docs/source/generated/cdms2.cdurlparse.urldefrag.rst new file mode 100644 index 00000000..fe79673e --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.urldefrag.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: urldefrag diff --git a/docs/source/generated/cdms2.cdurlparse.urljoin.rst b/docs/source/generated/cdms2.cdurlparse.urljoin.rst new file mode 100644 index 00000000..e1762622 --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.urljoin.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: urljoin diff --git a/docs/source/generated/cdms2.cdurlparse.urlparse.rst b/docs/source/generated/cdms2.cdurlparse.urlparse.rst new file mode 100644 index 00000000..331c0364 --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.urlparse.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: urlparse diff --git a/docs/source/generated/cdms2.cdurlparse.urlunparse.rst b/docs/source/generated/cdms2.cdurlparse.urlunparse.rst new file mode 100644 index 00000000..2265dd19 --- /dev/null +++ b/docs/source/generated/cdms2.cdurlparse.urlunparse.rst @@ -0,0 +1,6 @@ +cdms2.cdurlparse +================ + +.. currentmodule:: cdms2.cdurlparse + +.. autofunction:: urlunparse diff --git a/docs/source/generated/cdms2.convention.CFConvention.getAxisAuxIds.rst b/docs/source/generated/cdms2.convention.CFConvention.getAxisAuxIds.rst new file mode 100644 index 00000000..6583fef4 --- /dev/null +++ b/docs/source/generated/cdms2.convention.CFConvention.getAxisAuxIds.rst @@ -0,0 +1,6 @@ +cdms2.convention:CFConvention +============================= + +.. currentmodule:: cdms2.convention + +.. automethod:: CFConvention.getAxisAuxIds diff --git a/docs/source/generated/cdms2.convention.CFConvention.getAxisIds.rst b/docs/source/generated/cdms2.convention.CFConvention.getAxisIds.rst new file mode 100644 index 00000000..94bb884e --- /dev/null +++ b/docs/source/generated/cdms2.convention.CFConvention.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.convention:CFConvention +============================= + +.. currentmodule:: cdms2.convention + +.. automethod:: CFConvention.getAxisIds diff --git a/docs/source/generated/cdms2.convention.CFConvention.getDsetnodeAuxAxisIds.rst b/docs/source/generated/cdms2.convention.CFConvention.getDsetnodeAuxAxisIds.rst new file mode 100644 index 00000000..3139114f --- /dev/null +++ b/docs/source/generated/cdms2.convention.CFConvention.getDsetnodeAuxAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.convention:CFConvention +============================= + +.. currentmodule:: cdms2.convention + +.. automethod:: CFConvention.getDsetnodeAuxAxisIds diff --git a/docs/source/generated/cdms2.convention.CFConvention.getVariableBounds.rst b/docs/source/generated/cdms2.convention.CFConvention.getVariableBounds.rst new file mode 100644 index 00000000..c6650e25 --- /dev/null +++ b/docs/source/generated/cdms2.convention.CFConvention.getVariableBounds.rst @@ -0,0 +1,6 @@ +cdms2.convention:CFConvention +============================= + +.. currentmodule:: cdms2.convention + +.. automethod:: CFConvention.getVariableBounds diff --git a/docs/source/generated/cdms2.convention.COARDSConvention.getAxisIds.rst b/docs/source/generated/cdms2.convention.COARDSConvention.getAxisIds.rst new file mode 100644 index 00000000..c15cd92b --- /dev/null +++ b/docs/source/generated/cdms2.convention.COARDSConvention.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.convention:COARDSConvention +================================= + +.. currentmodule:: cdms2.convention + +.. automethod:: COARDSConvention.getAxisIds diff --git a/docs/source/generated/cdms2.convention.NUGConvention.getAxisIds.rst b/docs/source/generated/cdms2.convention.NUGConvention.getAxisIds.rst new file mode 100644 index 00000000..3b03ba0c --- /dev/null +++ b/docs/source/generated/cdms2.convention.NUGConvention.getAxisIds.rst @@ -0,0 +1,6 @@ +cdms2.convention:NUGConvention +============================== + +.. currentmodule:: cdms2.convention + +.. automethod:: NUGConvention.getAxisIds diff --git a/docs/source/generated/cdms2.convention.getDatasetConvention.rst b/docs/source/generated/cdms2.convention.getDatasetConvention.rst new file mode 100644 index 00000000..9ae1b8ee --- /dev/null +++ b/docs/source/generated/cdms2.convention.getDatasetConvention.rst @@ -0,0 +1,6 @@ +cdms2.convention +================ + +.. currentmodule:: cdms2.convention + +.. autofunction:: getDatasetConvention diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.__call__.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.__call__.rst new file mode 100644 index 00000000..1b5ac285 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.__call__.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.__call__ diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.__getitem__.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.__getitem__.rst new file mode 100644 index 00000000..bde84212 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.__getitem__ diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset._v.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset._v.rst new file mode 100644 index 00000000..2d97463b --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset._v.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset._v diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.cleardefault.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.cleardefault.rst new file mode 100644 index 00000000..e3f0aba1 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.cleardefault.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.cleardefault diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.default_variable.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.default_variable.rst new file mode 100644 index 00000000..5fa8e86a --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.default_variable.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.default_variable diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionarray.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionarray.rst new file mode 100644 index 00000000..6ec31f1a --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionarray.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.dimensionarray diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionobject.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionobject.rst new file mode 100644 index 00000000..c32e0d07 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.dimensionobject.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.dimensionobject diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.getattribute.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.getattribute.rst new file mode 100644 index 00000000..e3c30cb0 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.getattribute diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.getdimensionunits.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.getdimensionunits.rst new file mode 100644 index 00000000..448a86a6 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.getdimensionunits.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.getdimensionunits diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.getglobal.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.getglobal.rst new file mode 100644 index 00000000..ed5e5f79 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.getglobal.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.getglobal diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.getslab.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.getslab.rst new file mode 100644 index 00000000..72dfb87c --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.getslab.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.getslab diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listall.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listall.rst new file mode 100644 index 00000000..9dee43bf --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listall.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listall diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listattribute.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listattribute.rst new file mode 100644 index 00000000..7c0082e3 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listattribute.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listattribute diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listdimension.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listdimension.rst new file mode 100644 index 00000000..e29d2a5b --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listdimension.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listdimension diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listglobal.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listglobal.rst new file mode 100644 index 00000000..72a9acbb --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listglobal.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listglobal diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariable.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariable.rst new file mode 100644 index 00000000..70a934d4 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariable.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listvariable diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariables.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariables.rst new file mode 100644 index 00000000..6810c4bd --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.listvariables.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.listvariables diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.readScripGrid.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.readScripGrid.rst new file mode 100644 index 00000000..13c0c676 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.readScripGrid.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.readScripGrid diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.showall.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.showall.rst new file mode 100644 index 00000000..462ebaed --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.showall.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.showall diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.showattribute.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.showattribute.rst new file mode 100644 index 00000000..dc9c7ffd --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.showattribute.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.showattribute diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.showdimension.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.showdimension.rst new file mode 100644 index 00000000..db1a7889 --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.showdimension.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.showdimension diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.showglobal.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.showglobal.rst new file mode 100644 index 00000000..b9b1735b --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.showglobal.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.showglobal diff --git a/docs/source/generated/cdms2.cudsinterface.cuDataset.showvariable.rst b/docs/source/generated/cdms2.cudsinterface.cuDataset.showvariable.rst new file mode 100644 index 00000000..9347494f --- /dev/null +++ b/docs/source/generated/cdms2.cudsinterface.cuDataset.showvariable.rst @@ -0,0 +1,6 @@ +cdms2.cudsinterface:cuDataset +============================= + +.. currentmodule:: cdms2.cudsinterface + +.. automethod:: cuDataset.showvariable diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.dump.rst b/docs/source/generated/cdms2.database.AbstractDatabase.dump.rst new file mode 100644 index 00000000..695fb3d7 --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.dump.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.dump diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.matchPattern.rst b/docs/source/generated/cdms2.database.AbstractDatabase.matchPattern.rst new file mode 100644 index 00000000..656379ef --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.matchPattern diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.matchone.rst b/docs/source/generated/cdms2.database.AbstractDatabase.matchone.rst new file mode 100644 index 00000000..1776806e --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.matchone.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.matchone diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.searchPattern.rst b/docs/source/generated/cdms2.database.AbstractDatabase.searchPattern.rst new file mode 100644 index 00000000..c9416223 --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.searchPattern diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.searchPredicate.rst b/docs/source/generated/cdms2.database.AbstractDatabase.searchPredicate.rst new file mode 100644 index 00000000..84e383d3 --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.searchPredicate diff --git a/docs/source/generated/cdms2.database.AbstractDatabase.searchone.rst b/docs/source/generated/cdms2.database.AbstractDatabase.searchone.rst new file mode 100644 index 00000000..0c67ed3d --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractDatabase.searchone.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractDatabase +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractDatabase.searchone diff --git a/docs/source/generated/cdms2.database.AbstractResultEntry.getObject.rst b/docs/source/generated/cdms2.database.AbstractResultEntry.getObject.rst new file mode 100644 index 00000000..bf8d4400 --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractResultEntry.getObject.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractResultEntry +================================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractResultEntry.getObject diff --git a/docs/source/generated/cdms2.database.AbstractSearchResult.__getitem__.rst b/docs/source/generated/cdms2.database.AbstractSearchResult.__getitem__.rst new file mode 100644 index 00000000..bd76ffc0 --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractSearchResult.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractSearchResult +=================================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractSearchResult.__getitem__ diff --git a/docs/source/generated/cdms2.database.AbstractSearchResult.__len__.rst b/docs/source/generated/cdms2.database.AbstractSearchResult.__len__.rst new file mode 100644 index 00000000..90e7a64f --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractSearchResult.__len__.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractSearchResult +=================================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractSearchResult.__len__ diff --git a/docs/source/generated/cdms2.database.AbstractSearchResult.searchPredicate.rst b/docs/source/generated/cdms2.database.AbstractSearchResult.searchPredicate.rst new file mode 100644 index 00000000..8e45863f --- /dev/null +++ b/docs/source/generated/cdms2.database.AbstractSearchResult.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.database:AbstractSearchResult +=================================== + +.. currentmodule:: cdms2.database + +.. automethod:: AbstractSearchResult.searchPredicate diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.close.rst b/docs/source/generated/cdms2.database.LDAPDatabase.close.rst new file mode 100644 index 00000000..b78d127b --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.close.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.close diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.dump.rst b/docs/source/generated/cdms2.database.LDAPDatabase.dump.rst new file mode 100644 index 00000000..894dd450 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.dump.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.dump diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.listDatasets.rst b/docs/source/generated/cdms2.database.LDAPDatabase.listDatasets.rst new file mode 100644 index 00000000..515c0c83 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.listDatasets.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.listDatasets diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.matchPattern.rst b/docs/source/generated/cdms2.database.LDAPDatabase.matchPattern.rst new file mode 100644 index 00000000..5fb35485 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.matchPattern diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.matchone.rst b/docs/source/generated/cdms2.database.LDAPDatabase.matchone.rst new file mode 100644 index 00000000..6370b6de --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.matchone.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.matchone diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.open.rst b/docs/source/generated/cdms2.database.LDAPDatabase.open.rst new file mode 100644 index 00000000..be1a703a --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.open.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.open diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.openDataset.rst b/docs/source/generated/cdms2.database.LDAPDatabase.openDataset.rst new file mode 100644 index 00000000..602a9ba2 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.openDataset.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.openDataset diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.searchFilter.rst b/docs/source/generated/cdms2.database.LDAPDatabase.searchFilter.rst new file mode 100644 index 00000000..891f985d --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.searchFilter.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.searchFilter diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.searchPattern.rst b/docs/source/generated/cdms2.database.LDAPDatabase.searchPattern.rst new file mode 100644 index 00000000..0d543cfd --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.searchPattern diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.searchPredicate.rst b/docs/source/generated/cdms2.database.LDAPDatabase.searchPredicate.rst new file mode 100644 index 00000000..d0f813a5 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.searchPredicate diff --git a/docs/source/generated/cdms2.database.LDAPDatabase.searchone.rst b/docs/source/generated/cdms2.database.LDAPDatabase.searchone.rst new file mode 100644 index 00000000..ff05a514 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPDatabase.searchone.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPDatabase +=========================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPDatabase.searchone diff --git a/docs/source/generated/cdms2.database.LDAPSearchResult.searchPredicate.rst b/docs/source/generated/cdms2.database.LDAPSearchResult.searchPredicate.rst new file mode 100644 index 00000000..5d033896 --- /dev/null +++ b/docs/source/generated/cdms2.database.LDAPSearchResult.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.database:LDAPSearchResult +=============================== + +.. currentmodule:: cdms2.database + +.. automethod:: LDAPSearchResult.searchPredicate diff --git a/docs/source/generated/cdms2.database.connect.rst b/docs/source/generated/cdms2.database.connect.rst new file mode 100644 index 00000000..e97aebc6 --- /dev/null +++ b/docs/source/generated/cdms2.database.connect.rst @@ -0,0 +1,6 @@ +cdms2.database +============== + +.. currentmodule:: cdms2.database + +.. autofunction:: connect diff --git a/docs/source/generated/cdms2.database.loadString.rst b/docs/source/generated/cdms2.database.loadString.rst new file mode 100644 index 00000000..ed4d741f --- /dev/null +++ b/docs/source/generated/cdms2.database.loadString.rst @@ -0,0 +1,6 @@ +cdms2.database +============== + +.. currentmodule:: cdms2.database + +.. autofunction:: loadString diff --git a/docs/source/generated/cdms2.forecast.available_forecasts.rst b/docs/source/generated/cdms2.forecast.available_forecasts.rst new file mode 100644 index 00000000..5d159851 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.available_forecasts.rst @@ -0,0 +1,6 @@ +cdms2.forecast +============== + +.. currentmodule:: cdms2.forecast + +.. autofunction:: available_forecasts diff --git a/docs/source/generated/cdms2.forecast.comptime.rst b/docs/source/generated/cdms2.forecast.comptime.rst new file mode 100644 index 00000000..f202860a --- /dev/null +++ b/docs/source/generated/cdms2.forecast.comptime.rst @@ -0,0 +1,6 @@ +cdms2.forecast +============== + +.. currentmodule:: cdms2.forecast + +.. autofunction:: comptime diff --git a/docs/source/generated/cdms2.forecast.forecast.__call__.rst b/docs/source/generated/cdms2.forecast.forecast.__call__.rst new file mode 100644 index 00000000..1e491e5b --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecast.__call__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecast +======================= + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecast.__call__ diff --git a/docs/source/generated/cdms2.forecast.forecast.__getitem__.rst b/docs/source/generated/cdms2.forecast.forecast.__getitem__.rst new file mode 100644 index 00000000..b43cbaac --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecast.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecast +======================= + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecast.__getitem__ diff --git a/docs/source/generated/cdms2.forecast.forecast.__init__.rst b/docs/source/generated/cdms2.forecast.forecast.__init__.rst new file mode 100644 index 00000000..236aadc0 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecast.__init__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecast +======================= + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecast.__init__ diff --git a/docs/source/generated/cdms2.forecast.forecasts.__call__.rst b/docs/source/generated/cdms2.forecast.forecasts.__call__.rst new file mode 100644 index 00000000..bb67c001 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.__call__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.__call__ diff --git a/docs/source/generated/cdms2.forecast.forecasts.__getitem__.rst b/docs/source/generated/cdms2.forecast.forecasts.__getitem__.rst new file mode 100644 index 00000000..e045a251 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.__getitem__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.__getitem__ diff --git a/docs/source/generated/cdms2.forecast.forecasts.__init__.rst b/docs/source/generated/cdms2.forecast.forecasts.__init__.rst new file mode 100644 index 00000000..6e50e9bc --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.__init__.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.__init__ diff --git a/docs/source/generated/cdms2.forecast.forecasts.forecast_axis.rst b/docs/source/generated/cdms2.forecast.forecasts.forecast_axis.rst new file mode 100644 index 00000000..e94664fb --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.forecast_axis.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.forecast_axis diff --git a/docs/source/generated/cdms2.forecast.forecasts.forecast_times_to_list.rst b/docs/source/generated/cdms2.forecast.forecasts.forecast_times_to_list.rst new file mode 100644 index 00000000..9a40a0a2 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.forecast_times_to_list.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.forecast_times_to_list diff --git a/docs/source/generated/cdms2.forecast.forecasts.reduce_inplace.rst b/docs/source/generated/cdms2.forecast.forecasts.reduce_inplace.rst new file mode 100644 index 00000000..e9d2c64a --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.reduce_inplace.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.reduce_inplace diff --git a/docs/source/generated/cdms2.forecast.forecasts.time_interval_to_list.rst b/docs/source/generated/cdms2.forecast.forecasts.time_interval_to_list.rst new file mode 100644 index 00000000..9f7f5d62 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.forecasts.time_interval_to_list.rst @@ -0,0 +1,6 @@ +cdms2.forecast:forecasts +======================== + +.. currentmodule:: cdms2.forecast + +.. automethod:: forecasts.time_interval_to_list diff --git a/docs/source/generated/cdms2.forecast.two_times_from_one.rst b/docs/source/generated/cdms2.forecast.two_times_from_one.rst new file mode 100644 index 00000000..c5a67118 --- /dev/null +++ b/docs/source/generated/cdms2.forecast.two_times_from_one.rst @@ -0,0 +1,6 @@ +cdms2.forecast +============== + +.. currentmodule:: cdms2.forecast + +.. autofunction:: two_times_from_one From 4bddf0424c7c14d8d4146054a221574536b81cec Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 11:07:52 -0700 Subject: [PATCH 211/239] try to fix API.rst --- docs/source/API.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/API.rst b/docs/source/API.rst index 325f6525..97b04a99 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -73,7 +73,9 @@ Classes Regridder --------- + .. autosummary:: + regrid2.horizontal regrid2.esmf regrid2.crossSection From ff931a7721939f94dd48e1c75af1ac04cd9862d3 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 14:05:53 -0700 Subject: [PATCH 212/239] add regrid2 to docs --- docs/generatedRST.py | 4 +- docs/source/API.rst | 57 +++++-------------- docs/source/crossSection.rst | 22 +++++-- docs/source/esmf.rst | 16 ++---- .../regrid2.crossSection.checkdimension.rst | 6 ++ .../regrid2.crossSection.generic_wts_bnds.rst | 6 ++ ...id2.crossSection.get_latitude_wts_bnds.rst | 6 ++ ...ssSection.get_region_latitude_wts_bnds.rst | 6 ++ .../regrid2.crossSection.latitude_bounds.rst | 6 ++ .../regrid2.crossSection.rmserror.rst | 6 ++ .../regrid2.crossSection.section.rst | 6 ++ .../regrid2.crossSection.sectionmask.rst | 6 ++ .../regrid2.crossSection.sendmsg.rst | 6 ++ .../regrid2.esmf.EsmfRegrid.__call__.rst | 6 ++ .../regrid2.esmf.EsmfRegrid.__init__.rst | 6 ++ ...d2.esmf.EsmfRegrid.getDstAreaFractions.rst | 6 ++ .../regrid2.esmf.EsmfRegrid.getDstAreas.rst | 6 ++ ...d2.esmf.EsmfRegrid.getSrcAreaFractions.rst | 6 ++ .../regrid2.esmf.EsmfRegrid.getSrcAreas.rst | 6 ++ .../regrid2.esmf.EsmfStructField.__init__.rst | 6 ++ .../regrid2.esmf.EsmfStructField.getData.rst | 6 ++ ...egrid2.esmf.EsmfStructField.getPointer.rst | 6 ++ ...rid2.esmf.EsmfStructField.setLocalData.rst | 6 ++ .../regrid2.esmf.EsmfStructGrid.__init__.rst | 6 ++ ...grid2.esmf.EsmfStructGrid.getCellAreas.rst | 6 ++ ...rid2.esmf.EsmfStructGrid.getCoordShape.rst | 6 ++ .../regrid2.esmf.EsmfStructGrid.getCoords.rst | 6 ++ ...rid2.esmf.EsmfStructGrid.getLoHiBounds.rst | 6 ++ ...grid2.esmf.EsmfStructGrid.getLocalSlab.rst | 6 ++ .../regrid2.esmf.EsmfStructGrid.getMask.rst | 6 ++ ...grid2.esmf.EsmfStructGrid.setCellAreas.rst | 6 ++ .../regrid2.esmf.EsmfStructGrid.setCoords.rst | 6 ++ .../regrid2.esmf.EsmfStructGrid.setMask.rst | 6 ++ ...regrid2.esmf.EsmfUnstructGrid.__init__.rst | 6 ++ ...regrid2.esmf.EsmfUnstructGrid.setCells.rst | 6 ++ ...regrid2.esmf.EsmfUnstructGrid.setNodes.rst | 6 ++ .../regrid2.esmf.EsmfUnstructGrid.toVTK.rst | 6 ++ .../regrid2.horizontal.extractBounds.rst | 6 ++ .../regrid2.horizontal.input_mask.rst | 6 ++ ...mvGenericRegrid.GenericRegrid.__init__.rst | 6 ++ ...d2.mvGenericRegrid.GenericRegrid.apply.rst | 6 ++ ...ricRegrid.GenericRegrid.computeWeights.rst | 6 ++ ...rid.GenericRegrid.fillInDiagnosticData.rst | 6 ++ ...GenericRegrid.GenericRegrid.getDstGrid.rst | 6 ++ ...grid2.mvGenericRegrid.guessPeriodicity.rst | 6 ++ .../generated/regrid2.pressure.checkorder.rst | 6 ++ .../generated/regrid2.pressure.sendmsg.rst | 6 ++ ...egrid2.scrip.BicubicRegridder.__call__.rst | 6 ++ ...id2.scrip.ConservativeRegridder.regrid.rst | 6 ++ .../generated/regrid2.scrip.readRegridder.rst | 6 ++ docs/source/horizontal.rst | 15 +++-- docs/source/mvESMFRegrid.rst | 8 +-- docs/source/mvGenericRegrid.rst | 12 ++-- docs/source/pressure.rst | 15 +++-- docs/source/scrip.rst | 31 ++-------- regrid2/Lib/esmf.py | 10 ++-- regrid2/Lib/scrip.py | 29 +++++----- 57 files changed, 370 insertions(+), 125 deletions(-) create mode 100644 docs/source/generated/regrid2.crossSection.checkdimension.rst create mode 100644 docs/source/generated/regrid2.crossSection.generic_wts_bnds.rst create mode 100644 docs/source/generated/regrid2.crossSection.get_latitude_wts_bnds.rst create mode 100644 docs/source/generated/regrid2.crossSection.get_region_latitude_wts_bnds.rst create mode 100644 docs/source/generated/regrid2.crossSection.latitude_bounds.rst create mode 100644 docs/source/generated/regrid2.crossSection.rmserror.rst create mode 100644 docs/source/generated/regrid2.crossSection.section.rst create mode 100644 docs/source/generated/regrid2.crossSection.sectionmask.rst create mode 100644 docs/source/generated/regrid2.crossSection.sendmsg.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.__call__.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.__init__.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreaFractions.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreas.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreaFractions.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreas.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructField.__init__.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructField.getData.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructField.getPointer.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructField.setLocalData.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.__init__.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getCellAreas.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoordShape.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoords.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getLoHiBounds.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getLocalSlab.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.getMask.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.setCellAreas.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.setCoords.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfStructGrid.setMask.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfUnstructGrid.__init__.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setCells.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setNodes.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfUnstructGrid.toVTK.rst create mode 100644 docs/source/generated/regrid2.horizontal.extractBounds.rst create mode 100644 docs/source/generated/regrid2.horizontal.input_mask.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.__init__.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.apply.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.computeWeights.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.fillInDiagnosticData.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.getDstGrid.rst create mode 100644 docs/source/generated/regrid2.mvGenericRegrid.guessPeriodicity.rst create mode 100644 docs/source/generated/regrid2.pressure.checkorder.rst create mode 100644 docs/source/generated/regrid2.pressure.sendmsg.rst create mode 100644 docs/source/generated/regrid2.scrip.BicubicRegridder.__call__.rst create mode 100644 docs/source/generated/regrid2.scrip.ConservativeRegridder.regrid.rst create mode 100644 docs/source/generated/regrid2.scrip.readRegridder.rst diff --git a/docs/generatedRST.py b/docs/generatedRST.py index 27625c00..5e73d97c 100644 --- a/docs/generatedRST.py +++ b/docs/generatedRST.py @@ -3,6 +3,7 @@ import importlib import sys import cdms2 +import regrid2 def getMember(imported_module): member_list = [] @@ -54,7 +55,8 @@ def createRSTfiles(modules): RSTwrite(module, cdms2_all_list) if __name__ == "__main__": - modules = ["cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] + + modules = ["cdms2.avariable:AbstractVariable","regrid2.horizontal", "regrid2.esmf", "regrid2.esmf:EsmfUnstructGrid","regrid2.esmf:EsmfStructField","regrid2.esmf:EsmfRegrid", "regrid2.esmf:EsmfStructGrid","regrid2.crossSection","regrid2.mvESMFRegrid","regrid2.mvGenericRegrid","regrid2.pressure","regrid2.scrip","regrid2.pressure","regrid2.scrip","regrid2.mvGenericRegrid:GenericRegrid","regrid2.scrip","regrid2.scrip.ScripRegridder","regrid2.scrip.ConservativeRegridder","regrid2.scrip.BilinearRegridder","regrid2.scrip.BicubicRegridder","regrid2.scrip.DistwgtRegridder","regrid2.horizontal","cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] createRSTfiles(modules) diff --git a/docs/source/API.rst b/docs/source/API.rst index 97b04a99..eb6a36e0 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -5,6 +5,7 @@ API Classes ------- + .. csv-table:: :header: "Type", "Constructor" :widths: 10, 40 @@ -39,52 +40,24 @@ Classes ":ref:`restApi`", "" ":ref:`slabinterface`", "Read part of the old cu slab interface implemented over CDMS" -.. autosummary:: - - avariable - axis - fvariable - bindex - variable - cache - cdurllib - cdurlparse - cdxmllib - coord - cudsinterface - database - dataset - forecast - gengrid - grid - hgrid - MV2 - mvCdmsRegrid - selectors - tvariable - mvBaseWriter - mvSphereMesh - mvVsWriter - mvVTKSGWriter - mvVTKUGWriter - restApi - slabinterface - Regridder --------- -.. autosummary:: - - regrid2.horizontal - regrid2.esmf - regrid2.crossSection - regrid2.gsRegrid - regrid2.mvESMFRegrid - regrid2.mvGenericRegrid - regrid2.pressure - regrid2.scrip - regrid2.mvcdms2.FRegrid +.. currentmodule:: regrid2 + +.. csv-table:: + :header: "Type", "Constructor" + :widths: 10, 40 + :align: left + + ":ref:`horizontal`", "Create a horizontal regridder" + ":ref:`esmf`", "Regrid source grid data to destination grid data using ESMF" + ":ref:`crossSection`", "" + ":ref:`mvESMFRegrid`", "" + ":ref:`mvGenericRegrid`", "" + ":ref:`pressure`", "" + ":ref:`scrip`", "" diff --git a/docs/source/crossSection.rst b/docs/source/crossSection.rst index e6b9de3d..8f946f30 100644 --- a/docs/source/crossSection.rst +++ b/docs/source/crossSection.rst @@ -1,9 +1,21 @@ -.. _regrid2: +.. _crossSection: -regrid2- crossSection -===================== +crossSection +============ -.. automodule:: regrid2.crossSection - :members: +.. currentmodule:: regrid2.crossSection + +.. autosummary:: + :toctree: generated/ + + checkdimension + generic_wts_bnds + get_latitude_wts_bnds + get_region_latitude_wts_bnds + latitude_bounds + rmserror + sectionmask + section + sendmsg diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst index c07b99d0..0a4d50a8 100644 --- a/docs/source/esmf.rst +++ b/docs/source/esmf.rst @@ -1,19 +1,16 @@ -.. _regrid2.esmf: +.. _esmf: -regrid2- esmf -============= -.. currentmodule:: cdms2.regrid2-esmf +esmf +==== +.. currentmodule:: regrid2.esmf .. autosummary:: :toctree: generated/ - EsmfUnstructGrid EsmfUnstructGrid.setCells EsmfUnstructGrid.setNodes EsmfUnstructGrid.toVTK - EsmfUnstructGrid.del - EsmfStructGrid EsmfStructGrid.getLocalSlab EsmfStructGrid.getLoHiBounds EsmfStructGrid.getCoordShape @@ -23,17 +20,12 @@ regrid2- esmf EsmfStructGrid.getCellAreas EsmfStructGrid.getMask EsmfStructGrid.setMask - EsmfStructGrid.del - EsmfStructField EsmfStructField.getPointer EsmfStructField.getData EsmfStructField.setLocalData - EsmfRegrid EsmfRegrid.getSrcAreas EsmfRegrid.getDstAreas EsmfRegrid.getSrcAreaFractions EsmfRegrid.getDstAreaFractions - EsmfRegrid.call - EsmfRegrid.del diff --git a/docs/source/generated/regrid2.crossSection.checkdimension.rst b/docs/source/generated/regrid2.crossSection.checkdimension.rst new file mode 100644 index 00000000..05d9e9ca --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.checkdimension.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: checkdimension diff --git a/docs/source/generated/regrid2.crossSection.generic_wts_bnds.rst b/docs/source/generated/regrid2.crossSection.generic_wts_bnds.rst new file mode 100644 index 00000000..6ea0b290 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.generic_wts_bnds.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: generic_wts_bnds diff --git a/docs/source/generated/regrid2.crossSection.get_latitude_wts_bnds.rst b/docs/source/generated/regrid2.crossSection.get_latitude_wts_bnds.rst new file mode 100644 index 00000000..a671ad87 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.get_latitude_wts_bnds.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: get_latitude_wts_bnds diff --git a/docs/source/generated/regrid2.crossSection.get_region_latitude_wts_bnds.rst b/docs/source/generated/regrid2.crossSection.get_region_latitude_wts_bnds.rst new file mode 100644 index 00000000..736c5eb6 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.get_region_latitude_wts_bnds.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: get_region_latitude_wts_bnds diff --git a/docs/source/generated/regrid2.crossSection.latitude_bounds.rst b/docs/source/generated/regrid2.crossSection.latitude_bounds.rst new file mode 100644 index 00000000..67129ac4 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.latitude_bounds.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: latitude_bounds diff --git a/docs/source/generated/regrid2.crossSection.rmserror.rst b/docs/source/generated/regrid2.crossSection.rmserror.rst new file mode 100644 index 00000000..48956680 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.rmserror.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: rmserror diff --git a/docs/source/generated/regrid2.crossSection.section.rst b/docs/source/generated/regrid2.crossSection.section.rst new file mode 100644 index 00000000..f29fca30 --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.section.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: section diff --git a/docs/source/generated/regrid2.crossSection.sectionmask.rst b/docs/source/generated/regrid2.crossSection.sectionmask.rst new file mode 100644 index 00000000..11bbcd6f --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.sectionmask.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: sectionmask diff --git a/docs/source/generated/regrid2.crossSection.sendmsg.rst b/docs/source/generated/regrid2.crossSection.sendmsg.rst new file mode 100644 index 00000000..02986aee --- /dev/null +++ b/docs/source/generated/regrid2.crossSection.sendmsg.rst @@ -0,0 +1,6 @@ +regrid2.crossSection +==================== + +.. currentmodule:: regrid2.crossSection + +.. autofunction:: sendmsg diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.__call__.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.__call__.rst new file mode 100644 index 00000000..c2a736b9 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.__call__.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.__call__ diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.__init__.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.__init__.rst new file mode 100644 index 00000000..5f6b4fe2 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.__init__.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.__init__ diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreaFractions.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreaFractions.rst new file mode 100644 index 00000000..d4b271ef --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreaFractions.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.getDstAreaFractions diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreas.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreas.rst new file mode 100644 index 00000000..bb5d0d60 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.getDstAreas.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.getDstAreas diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreaFractions.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreaFractions.rst new file mode 100644 index 00000000..ecf244eb --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreaFractions.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.getSrcAreaFractions diff --git a/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreas.rst b/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreas.rst new file mode 100644 index 00000000..4274818b --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfRegrid.getSrcAreas.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfRegrid +======================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfRegrid.getSrcAreas diff --git a/docs/source/generated/regrid2.esmf.EsmfStructField.__init__.rst b/docs/source/generated/regrid2.esmf.EsmfStructField.__init__.rst new file mode 100644 index 00000000..da90a484 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructField.__init__.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructField +============================ + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructField.__init__ diff --git a/docs/source/generated/regrid2.esmf.EsmfStructField.getData.rst b/docs/source/generated/regrid2.esmf.EsmfStructField.getData.rst new file mode 100644 index 00000000..07bf5dca --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructField.getData.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructField +============================ + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructField.getData diff --git a/docs/source/generated/regrid2.esmf.EsmfStructField.getPointer.rst b/docs/source/generated/regrid2.esmf.EsmfStructField.getPointer.rst new file mode 100644 index 00000000..afb6d32a --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructField.getPointer.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructField +============================ + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructField.getPointer diff --git a/docs/source/generated/regrid2.esmf.EsmfStructField.setLocalData.rst b/docs/source/generated/regrid2.esmf.EsmfStructField.setLocalData.rst new file mode 100644 index 00000000..566f9876 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructField.setLocalData.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructField +============================ + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructField.setLocalData diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.__init__.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.__init__.rst new file mode 100644 index 00000000..b0bfc3ec --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.__init__.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.__init__ diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCellAreas.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCellAreas.rst new file mode 100644 index 00000000..1433c2cb --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCellAreas.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getCellAreas diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoordShape.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoordShape.rst new file mode 100644 index 00000000..21dbff94 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoordShape.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getCoordShape diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoords.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoords.rst new file mode 100644 index 00000000..59d0768a --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getCoords.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getCoords diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLoHiBounds.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLoHiBounds.rst new file mode 100644 index 00000000..9d08d2c5 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLoHiBounds.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getLoHiBounds diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLocalSlab.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLocalSlab.rst new file mode 100644 index 00000000..e8928d69 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getLocalSlab.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getLocalSlab diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.getMask.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getMask.rst new file mode 100644 index 00000000..b810114a --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.getMask.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.getMask diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCellAreas.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCellAreas.rst new file mode 100644 index 00000000..00f7d82a --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCellAreas.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.setCellAreas diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCoords.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCoords.rst new file mode 100644 index 00000000..eea9bcd6 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setCoords.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.setCoords diff --git a/docs/source/generated/regrid2.esmf.EsmfStructGrid.setMask.rst b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setMask.rst new file mode 100644 index 00000000..a9ce99f1 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfStructGrid.setMask.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfStructGrid +=========================== + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfStructGrid.setMask diff --git a/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.__init__.rst b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.__init__.rst new file mode 100644 index 00000000..242eca51 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.__init__.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfUnstructGrid +============================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfUnstructGrid.__init__ diff --git a/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setCells.rst b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setCells.rst new file mode 100644 index 00000000..75e9b7c9 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setCells.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfUnstructGrid +============================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfUnstructGrid.setCells diff --git a/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setNodes.rst b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setNodes.rst new file mode 100644 index 00000000..471e181c --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.setNodes.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfUnstructGrid +============================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfUnstructGrid.setNodes diff --git a/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.toVTK.rst b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.toVTK.rst new file mode 100644 index 00000000..6bdb0f1b --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.toVTK.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfUnstructGrid +============================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfUnstructGrid.toVTK diff --git a/docs/source/generated/regrid2.horizontal.extractBounds.rst b/docs/source/generated/regrid2.horizontal.extractBounds.rst new file mode 100644 index 00000000..9151cc4c --- /dev/null +++ b/docs/source/generated/regrid2.horizontal.extractBounds.rst @@ -0,0 +1,6 @@ +regrid2.horizontal +================== + +.. currentmodule:: regrid2.horizontal + +.. autofunction:: extractBounds diff --git a/docs/source/generated/regrid2.horizontal.input_mask.rst b/docs/source/generated/regrid2.horizontal.input_mask.rst new file mode 100644 index 00000000..0359c972 --- /dev/null +++ b/docs/source/generated/regrid2.horizontal.input_mask.rst @@ -0,0 +1,6 @@ +regrid2.horizontal +================== + +.. currentmodule:: regrid2.horizontal + +.. autofunction:: input_mask diff --git a/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.__init__.rst b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.__init__.rst new file mode 100644 index 00000000..5c02e51b --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.__init__.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid:GenericRegrid +===================================== + +.. currentmodule:: regrid2.mvGenericRegrid + +.. automethod:: GenericRegrid.__init__ diff --git a/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.apply.rst b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.apply.rst new file mode 100644 index 00000000..1160eccf --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.apply.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid:GenericRegrid +===================================== + +.. currentmodule:: regrid2.mvGenericRegrid + +.. automethod:: GenericRegrid.apply diff --git a/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.computeWeights.rst b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.computeWeights.rst new file mode 100644 index 00000000..4315ae54 --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.computeWeights.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid:GenericRegrid +===================================== + +.. currentmodule:: regrid2.mvGenericRegrid + +.. automethod:: GenericRegrid.computeWeights diff --git a/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.fillInDiagnosticData.rst b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.fillInDiagnosticData.rst new file mode 100644 index 00000000..99cd63e2 --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.fillInDiagnosticData.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid:GenericRegrid +===================================== + +.. currentmodule:: regrid2.mvGenericRegrid + +.. automethod:: GenericRegrid.fillInDiagnosticData diff --git a/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.getDstGrid.rst b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.getDstGrid.rst new file mode 100644 index 00000000..565c2a3c --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.GenericRegrid.getDstGrid.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid:GenericRegrid +===================================== + +.. currentmodule:: regrid2.mvGenericRegrid + +.. automethod:: GenericRegrid.getDstGrid diff --git a/docs/source/generated/regrid2.mvGenericRegrid.guessPeriodicity.rst b/docs/source/generated/regrid2.mvGenericRegrid.guessPeriodicity.rst new file mode 100644 index 00000000..9dbb474f --- /dev/null +++ b/docs/source/generated/regrid2.mvGenericRegrid.guessPeriodicity.rst @@ -0,0 +1,6 @@ +regrid2.mvGenericRegrid +======================= + +.. currentmodule:: regrid2.mvGenericRegrid + +.. autofunction:: guessPeriodicity diff --git a/docs/source/generated/regrid2.pressure.checkorder.rst b/docs/source/generated/regrid2.pressure.checkorder.rst new file mode 100644 index 00000000..b8397c44 --- /dev/null +++ b/docs/source/generated/regrid2.pressure.checkorder.rst @@ -0,0 +1,6 @@ +regrid2.pressure +================ + +.. currentmodule:: regrid2.pressure + +.. autofunction:: checkorder diff --git a/docs/source/generated/regrid2.pressure.sendmsg.rst b/docs/source/generated/regrid2.pressure.sendmsg.rst new file mode 100644 index 00000000..1512a0aa --- /dev/null +++ b/docs/source/generated/regrid2.pressure.sendmsg.rst @@ -0,0 +1,6 @@ +regrid2.pressure +================ + +.. currentmodule:: regrid2.pressure + +.. autofunction:: sendmsg diff --git a/docs/source/generated/regrid2.scrip.BicubicRegridder.__call__.rst b/docs/source/generated/regrid2.scrip.BicubicRegridder.__call__.rst new file mode 100644 index 00000000..8550ffcb --- /dev/null +++ b/docs/source/generated/regrid2.scrip.BicubicRegridder.__call__.rst @@ -0,0 +1,6 @@ +regrid2.scrip.BicubicRegridder +============================== + +.. currentmodule:: regrid2.scrip.BicubicRegridder + +.. automethod:: .__call__ diff --git a/docs/source/generated/regrid2.scrip.ConservativeRegridder.regrid.rst b/docs/source/generated/regrid2.scrip.ConservativeRegridder.regrid.rst new file mode 100644 index 00000000..8378efb6 --- /dev/null +++ b/docs/source/generated/regrid2.scrip.ConservativeRegridder.regrid.rst @@ -0,0 +1,6 @@ +regrid2.scrip.ConservativeRegridder +=================================== + +.. currentmodule:: regrid2.scrip.ConservativeRegridder + +.. automethod:: .regrid diff --git a/docs/source/generated/regrid2.scrip.readRegridder.rst b/docs/source/generated/regrid2.scrip.readRegridder.rst new file mode 100644 index 00000000..9c351297 --- /dev/null +++ b/docs/source/generated/regrid2.scrip.readRegridder.rst @@ -0,0 +1,6 @@ +regrid2.scrip +============= + +.. currentmodule:: regrid2.scrip + +.. autofunction:: readRegridder diff --git a/docs/source/horizontal.rst b/docs/source/horizontal.rst index 8af38184..056d5629 100644 --- a/docs/source/horizontal.rst +++ b/docs/source/horizontal.rst @@ -1,9 +1,14 @@ -.. _regrid2.horizontal: +.. _horizontal: -regrid2-horizontal -================== +horizontal +========== -.. automodule:: regrid2.horizontal - :members: +.. currentmodule:: regrid2.horizontal + +.. autosummary:: + :toctree: generated/ + + extractBounds + input_mask diff --git a/docs/source/mvESMFRegrid.rst b/docs/source/mvESMFRegrid.rst index 343139d7..840ba9c4 100644 --- a/docs/source/mvESMFRegrid.rst +++ b/docs/source/mvESMFRegrid.rst @@ -1,8 +1,8 @@ -.. _regrid2.mvESMFRegrid: +.. _mvESMFRegrid: -regrid2-mvESMFRegrid -==================== -.. currentmodule:: cdms2.regrid2-mvESMFRegrid +mvESMFRegrid +============ +.. currentmodule:: cdms2.regrid2.mvESMFRegrid .. autosummary:: :toctree: generated/ diff --git a/docs/source/mvGenericRegrid.rst b/docs/source/mvGenericRegrid.rst index 87c6d127..0509275d 100644 --- a/docs/source/mvGenericRegrid.rst +++ b/docs/source/mvGenericRegrid.rst @@ -1,15 +1,13 @@ -.. _regrid2.mvGenericRegrid: +.. _mvGenericRegrid: -regrid2-mvGenericRegrid -======================= -.. currentmodule:: cdms2.regrid2-mvGenericRegrid +mvGenericRegrid +=============== +.. currentmodule:: regrid2.mvGenericRegrid .. autosummary:: :toctree: generated/ - - GenericRegrid - GenericRegrid.guessPeriodicity + guessPeriodicity GenericRegrid.computeWeights GenericRegrid.apply GenericRegrid.getDstGrid diff --git a/docs/source/pressure.rst b/docs/source/pressure.rst index d04d999a..20e49373 100644 --- a/docs/source/pressure.rst +++ b/docs/source/pressure.rst @@ -1,9 +1,14 @@ -.. _regrid2.pressure: +.. _pressure: -regrid2-pressure -================ +pressure +======== -.. automodule:: regrid2.pressure - :members: +.. currentmodule:: regrid2.pressure + +.. autosummary:: + :toctree: generated/ + + checkorder + sendmsg diff --git a/docs/source/scrip.rst b/docs/source/scrip.rst index 9dfabf32..2ebdbb1d 100644 --- a/docs/source/scrip.rst +++ b/docs/source/scrip.rst @@ -1,33 +1,14 @@ -.. _regrid2.scrip: +.. _scrip: -regrid2-scrip -============= -.. currentmodule:: cdms2.regrid2-scrip +scrip +===== + +.. currentmodule:: regrid2.scrip .. autosummary:: :toctree: generated/ - ScripRegridder - ScripRegridder.call - ScripRegridder.getOutputGrid - ScripRegridder.getInputGrid - ScripRegridder.getSourceFraction - ScripRegridder.getDestinationFraction - - ConservativeRegridder - ConservativeRegridder.getSourceArea - ConservativeRegridder.getDestinationArea - ConservativeRegridder.regrid - - BilinearRegridder - BilinearRegridder.regrid - - BicubicRegridder - BicubicRegridder.call - - DistwgtRegridder - DistwgtRegridder.regrid - DistwgtRegridder.readRegridder + readRegridder diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index fc73f8ed..756ecbe7 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -182,10 +182,8 @@ class EsmfStructGrid: """ Structured grid - Constructor - -Parameters ----------- + Parameters + ---------- shape Tuple of cell sizes along each axis @@ -618,8 +616,8 @@ class EsmfRegrid: Constuct regrid object -Parameters ----------- + Parameters + ---------- srcField the source field object of type EsmfStructFields diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 56c9b0a6..81c89a71 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -157,6 +157,9 @@ def getDestinationArea(self): return self.destArea def regrid(self, input): + """ + call regridder + """ if self.normal is None: # print "On input, num_links = %d"%(len(self.sourceAddress)) # print "On input, nextra = %d"%(input.shape[0]) @@ -210,7 +213,19 @@ def regrid(self, input): class BicubicRegridder(ScripRegridder): - """Bicubic regrid.""" + """Bicubic regrid. + + Parameters + ---------- + gradLat: + df/di + + gradLon: + df/dj + + gradLatlon: + d(df)/(di)(dj) + """ def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, sourceFrac=None, destFrac=None): @@ -225,18 +240,6 @@ def __init__(self, outputGrid, remapMatrix, sourceAddress, destFrac=destFrac) def __call__(self, input, gradLat, gradLon, gradLatlon): - """ - Parameters - ---------- - gradLat: - df/di - - gradLon: - df/dj - - gradLatlon: - d(df)/(di)(dj) - """ import numpy.ma from cdms2 import isVariable From b0493599221ac367c8976cbc03cdd4bbcd5ba3a3 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 15:36:34 -0700 Subject: [PATCH 213/239] Changes made to API --- regrid2/Lib/crossSection.py | 76 ++++++++++++++++++++------------ regrid2/Lib/crossSection.py.orig | 32 ++++++++------ 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index 23cadb08..ec0b9135 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -543,19 +543,26 @@ def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" + """ + + Purpose + + dimension checks + 1. has a len method + 2. data type is float32 + 3. monotonically increasing vectors + + Parameters + ---------- + + x - coordinate vector + name - coordinate vector ID + + Returns + ------- + + x, xsize -- dimension vector and its size + """ data = x[:] try: @@ -605,20 +612,35 @@ def generic_wts_bnds(lat): def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" + """ + + routine: get_latitude_wts_bnds + + purpose: compare the passed checklatpass with the correct geophysical + ones calculated here. After finding a match call the function + to get the bounds. + + usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + where + + Parameters + ---------- + + checklatpass + + is the grid to check + + None- + + N/A + + + Return + ------ + + wts, bnds - tuple with weights and bounds + + """ small = 0.001 # use as tolerance in checking values nlat = len(checklatpass) diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig index c06eae4a..ded6b447 100644 --- a/regrid2/Lib/crossSection.py.orig +++ b/regrid2/Lib/crossSection.py.orig @@ -543,19 +543,25 @@ class CrossSectionRegridder: def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" + """ + + purpose: dimension checks + 1. has a len method + 2. data type is float32 + 3. monotonically increasing vectors + + Parameters + ---------- + + x - coordinate vector + name - coordinate vector ID + + Returns + ------- + + x, xsize -- dimension vector and its size + + """ data = x[:] try: From f300870e305ed8819452828d872acfc574b349f9 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 16:16:16 -0700 Subject: [PATCH 214/239] fix space with parameters --- Lib/axis.py | 42 ++++++++++++++++---------------- regrid2/Lib/crossSection.py.orig | 3 +-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index 70c93069..45475bbf 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -2622,34 +2622,34 @@ def axisMatchIndex(axes, specifications=None, omit=None, order=None): def axisMatches(axis, specification): """ - Parameters - ---------- - axis: - See note below - specifications: - See note below + Parameters + ---------- + axis: + See note below + specifications: + See note below - Returns - ------- - 1 or 0 depending on whether axis matches the specification. + Returns + ------- + 1 or 0 depending on whether axis matches the specification. - Note - ---- - Specification must be one of: + Note + ---- + Specification must be one of: - #. a string representing an axis id or one of the keywords time, - fctau0, latitude or lat, longitude or lon, or lev or level. + #. a string representing an axis id or one of the keywords time, + fctau0, latitude or lat, longitude or lon, or lev or level. - #. Axis may be surrounded with parentheses or spaces. + #. Axis may be surrounded with parentheses or spaces. - * We first attempt to match the axis id and the specification. - * Keywords try to match using isTime, isLatitude, etc. - * Comparisons to keywords and axis ids is case-insensitive. + * We first attempt to match the axis id and the specification. + * Keywords try to match using isTime, isLatitude, etc. + * Comparisons to keywords and axis ids is case-insensitive. - #. a function that takes an axis as an argument and returns a value. - * if the value returned is true, the axis matches. + #. a function that takes an axis as an argument and returns a value. + * if the value returned is true, the axis matches. - #. an axis object; will match if it is the same object as axis. + #. an axis object; will match if it is the same object as axis. """ if isinstance(specification, string_types): s = specification.lower() diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig index ded6b447..0d53ea48 100644 --- a/regrid2/Lib/crossSection.py.orig +++ b/regrid2/Lib/crossSection.py.orig @@ -544,8 +544,7 @@ class CrossSectionRegridder: def checkdimension(x, name): """ - - purpose: dimension checks + purpose: dimension checks 1. has a len method 2. data type is float32 3. monotonically increasing vectors From 3ca98770bc66cf5b02de42ec5e15375a3e986b17 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 16:48:50 -0700 Subject: [PATCH 215/239] fix readthedocs using numpydoc --- Lib/database.py | 2 ++ Lib/dataset.py | 29 +++++++++++++++++------------ docs/source/conf.py | 6 ++++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Lib/database.py b/Lib/database.py index f8085181..b96f4118 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -226,6 +226,8 @@ def __del__(self): def normalizedn(self, dn): """ + normalizedn + Returns ------- string diff --git a/Lib/dataset.py b/Lib/dataset.py index e4234b83..443fb623 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -345,36 +345,41 @@ def getNetcdfUseParallelFlag(): def getNetcdf4Flag(): - """Returns - ------- + """ + Returns + ------- NetCDF4 flag value.""" return Cdunif.CdunifGetNCFLAGS("netcdf4") def getNetcdfClassicFlag(): - """Returns - ------- + """ + Returns + ------- NetCDF classic flag value.""" return Cdunif.CdunifGetNCFLAGS("classic") def getNetcdfShuffleFlag(): - """Returns - ------- + """ + Returns + ------- NetCDF shuffle flag value.""" return Cdunif.CdunifGetNCFLAGS("shuffle") def getNetcdfDeflateFlag(): - """Returns - ------- + """ + Returns + ------- NetCDF deflate flag value. """ return Cdunif.CdunifGetNCFLAGS("deflate") def getNetcdfDeflateLevelFlag(): - """Returns - ------- + """ + Returns + ------- NetCDF deflate level flag value.""" return Cdunif.CdunifGetNCFLAGS("deflate_level") @@ -382,8 +387,8 @@ def getNetcdfDeflateLevelFlag(): def useNetcdf3(): """ Turns off (0) NetCDF flags for shuffle/cuDa/deflatelevel Output files are generated as NetCDF3 Classic after that - Returns - ------- + Returns + ------- No return value. """ setNetcdfShuffleFlag(0) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4eebb4fb..46791e74 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -57,14 +57,16 @@ # 'sphinx.ext.napoleon' #] extensions = [ + "sphinx.ext.autodoc", +# "readthedocs_ext.readthedocs", 'easydev.copybutton', 'sphinx.ext.autosummary', 'sphinx.ext.todo', - 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.graphviz', 'sphinx.ext.doctest', - 'sphinx.ext.napoleon' + "numpydoc" +# 'sphinx.ext.napoleon' ] jscopybutton_path = "copybutton.js" From 493d2c1d8a1d35c91d6ef7c3f9b3d5537c2870ab Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 16:51:53 -0700 Subject: [PATCH 216/239] update environment --- docs/environment.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/environment.yml b/docs/environment.yml index fc2d8ad8..d98a8754 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -55,6 +55,7 @@ dependencies: - mpich=3.2.1=h26a2512_4 - ncurses=6.1=hfc679d8_1 - netcdf-fortran=4.4.4=7 + - numpydoc=0.8.0=py_1 - openssl=1.0.2o=h470a237_1 - ossuuid=1.6.2=hfc679d8_0 - packaging=17.1=py_0 @@ -72,7 +73,6 @@ dependencies: - setuptools=40.0.0=py27_1 - six=1.11.0=py27_1 - snowballstemmer=1.2.1=py_1 - - sphinx=1.7.5=py27_0 - sphinxcontrib-websupport=1.0.1=py27_0 - sqlite=3.24.0=h2f33b56_0 - tk=8.6.8=0 @@ -82,12 +82,28 @@ dependencies: - zlib=1.2.11=h470a237_3 - binutils_impl_linux-64=2.31.1=h6176602_0 - binutils_linux-64=2.31.1=h6176602_2 + - freetype=2.9.1=h8a8886c_0 + - funcsigs=1.0.2=py27_0 - gcc_impl_linux-64=7.3.0=habb00fd_0 - gcc_linux-64=7.3.0=h553295d_2 - libgcc-ng=8.2.0=hdf63c60_1 - libopenblas=0.2.20=h9ac9557_7 - libstdcxx-ng=8.2.0=hdf63c60_1 + - mock=2.0.0=py27_0 - numpy=1.14.3=py27h28100ab_1 - numpy-base=1.14.3=py27h0ea5e3f_1 + - olefile=0.45.1=py27_0 + - pbr=4.2.0=py27_0 + - pillow=5.2.0=py27heded4f4_0 + - pip=10.0.1=py27_0 + - sphinx=1.7.6=py27_0 + - sphinx_rtd_theme=0.4.1=py27_0 + - wheel=0.31.1=py27_0 + - pip: + - commonmark==0.5.4 + - mv2==3.0.0 + - readthedocs-sphinx-ext==0.5.14 + - recommonmark==0.4.0 + - regrid2==3.0.0 prefix: /export/reshel3/anaconda52/envs/cdms2 From 304b3f1fc1f3652581ef46e7afd0caaa49af1588 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 18:06:07 -0700 Subject: [PATCH 217/239] fix some autodocs --- Lib/forecast.py | 8 +++--- Lib/hgrid.py | 54 ++++++++++++++++++++++++++++++++++++++++ docs/generatedRST.py | 2 +- docs/source/API.rst | 2 -- docs/source/cdxmllib.rst | 45 --------------------------------- docs/source/forecast.rst | 4 +-- docs/source/grid.rst | 36 ++++++++------------------- docs/source/hgrid.rst | 17 +++---------- 8 files changed, 73 insertions(+), 95 deletions(-) delete mode 100644 docs/source/cdxmllib.rst diff --git a/Lib/forecast.py b/Lib/forecast.py index f5f42e61..3f973992 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -83,16 +83,16 @@ class forecast(): dataset_list is used to get the forecast file from the forecast time. - Example - ------- + Example + ------- Each list item should look like this example: [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] Normally dataset_list = fm[i][1] where fm is the output of cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. - Note - ---- + Note + ---- N.B. This is like a CdmsFile. Creating a forecast means opening a file, so later on you should call forecast.close() to close it. diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 0ab0031e..7aea5d8c 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -31,6 +31,18 @@ def _flatten(boundsar): class AbstractHorizontalGrid(AbstractGrid): + """ Create an horizontal grid + + Parameters + ---------- + latAxis + lonAxis + id - Default None + maskvar - Default None + tempmask - Default None + node - Default None + + """ def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None, node=None): @@ -125,6 +137,9 @@ def subGridRegion(self, latRegion, lonRegion): raise CDMSError(MethodNotImplemented) def hasCoordType(self, coordType): + """ + Not documented + """ return ((coordType == LatitudeType) or (coordType == LongitudeType)) def checkConvex(self): @@ -240,6 +255,8 @@ def fixCutCells(self, nonConvexCells, threshold=270.0): class AbstractCurveGrid(AbstractHorizontalGrid): + """Create a curvilinear grid. + """ def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None, node=None): @@ -253,6 +270,9 @@ def __init__(self, latAxis, lonAxis, id=None, self._index_ = None def clone(self, copyData=1): + """ + Not documented + """ newlat = self._lataxis_.clone(copyData) newlon = self._lonaxis_.clone(copyData) return TransientCurveGrid(newlat, newlon, id=self.id) @@ -290,14 +310,23 @@ def getMesh(self, transpose=None): return self._mesh_ def _getShape(self): + """ + Not documented + """ return self._lataxis_.shape # Don't try to generate bounds for curvilinear grids def genBounds(self): + """ + Not documented + """ return (None, None) # Get the n-th index axis. naxis is 0 or 1. def getAxis(self, naxis): + """ + Not documented + """ return self._lataxis_.getAxis(naxis) def getMask(self): @@ -308,6 +337,9 @@ def getMask(self): return self._maskVar_[:] def size(self): + """ + Not documented + """ return self._lataxis_.size() def writeScrip(self, cufile, gridTitle=None): @@ -378,6 +410,9 @@ def writeScrip(self, cufile, gridTitle=None): gridcornerlon[:] = clon def toGenericGrid(self, gridid=None): + """ + Not documented + """ from .auxcoord import TransientAuxAxis1D from .coord import TransientVirtualAxis @@ -415,6 +450,9 @@ def toGenericGrid(self, gridid=None): return grid def toCurveGrid(self, gridid=None): + """ + Not documented + """ if gridid is None: gridid = self.id result = self.clone() @@ -422,6 +460,9 @@ def toCurveGrid(self, gridid=None): return result def writeToFile(self, file): + """ + Not documented + """ latvar = self._lataxis_.writeToFile(file) lonvar = self._lonaxis_.writeToFile(file) if self._maskVar_ is not None: @@ -725,6 +766,9 @@ def intersect(self, spec): return submask, indexspecs def getAxisList(self): + """ + Not documented + """ return (self._lataxis_.getAxis(0), self._lataxis_.getAxis(1)) def isClose(self, g): @@ -842,6 +886,9 @@ def __repr__(self): class FileCurveGrid(AbstractCurveGrid): + """ + Not documented + """ def __init__(self, latAxis, lonAxis, id, parent=None, maskvar=None, tempmask=None, node=None): @@ -857,6 +904,10 @@ def __repr__(self): class TransientCurveGrid(AbstractCurveGrid): + """ + Not documented + """ + grid_count = 0 @@ -874,6 +925,9 @@ def __repr__(self): self.id, repr(self.shape)) def toCurveGrid(self, gridid=None): + """ + Not documented + """ if gridid is None: result = self else: diff --git a/docs/generatedRST.py b/docs/generatedRST.py index 5e73d97c..1e3f90e5 100644 --- a/docs/generatedRST.py +++ b/docs/generatedRST.py @@ -56,7 +56,7 @@ def createRSTfiles(modules): if __name__ == "__main__": - modules = ["cdms2.avariable:AbstractVariable","regrid2.horizontal", "regrid2.esmf", "regrid2.esmf:EsmfUnstructGrid","regrid2.esmf:EsmfStructField","regrid2.esmf:EsmfRegrid", "regrid2.esmf:EsmfStructGrid","regrid2.crossSection","regrid2.mvESMFRegrid","regrid2.mvGenericRegrid","regrid2.pressure","regrid2.scrip","regrid2.pressure","regrid2.scrip","regrid2.mvGenericRegrid:GenericRegrid","regrid2.scrip","regrid2.scrip.ScripRegridder","regrid2.scrip.ConservativeRegridder","regrid2.scrip.BilinearRegridder","regrid2.scrip.BicubicRegridder","regrid2.scrip.DistwgtRegridder","regrid2.horizontal","cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] + modules = ["cdms2.hgrid", "cdms2.hgrid:AbstractHorizontalGrid", "cdms2.hgrid.DatasetCurveGrid","cdms2.hgrid.FileCurveGrid", "cdms2.hgrid:TransientCurveGrid","cdms2.hgrid:AbstractCurveGrid", "cdms2.grid:AbstractGrid:hasCoordType", "cdms2.grid:AbstractRectGrid","cdms2.grid:FileRectGrid", "cdms2.grid:TransientRectGrid", "cdms2.grid", "cdms2.grid:AbstractGrid","cdms2.avariable:AbstractVariable","regrid2.horizontal", "regrid2.esmf", "regrid2.esmf:EsmfUnstructGrid","regrid2.esmf:EsmfStructField","regrid2.esmf:EsmfRegrid", "regrid2.esmf:EsmfStructGrid","regrid2.crossSection","regrid2.mvESMFRegrid","regrid2.mvGenericRegrid","regrid2.pressure","regrid2.scrip","regrid2.pressure","regrid2.scrip","regrid2.mvGenericRegrid:GenericRegrid","regrid2.scrip","regrid2.scrip.ScripRegridder","regrid2.scrip.ConservativeRegridder","regrid2.scrip.BilinearRegridder","regrid2.scrip.BicubicRegridder","regrid2.scrip.DistwgtRegridder","regrid2.horizontal","cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] createRSTfiles(modules) diff --git a/docs/source/API.rst b/docs/source/API.rst index eb6a36e0..ecb230db 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -19,8 +19,6 @@ Classes ":ref:`variable`", "DatasetVariable: Dataset-based variables" ":ref:`cdurllib`", "Customized URLopener" ":ref:`cdurlparse`", "Parse (absolute and relative) URLs." - ":ref:`cdxmllib`", "A parser for XML, using the derived class as static DTD." - ":ref:`coord`", "CDMS CoordinateAxis objects" ":ref:`cudsinterface`", "Emulation of old cu package" ":ref:`database`", "CDMS database objects" ":ref:`dataset`", "CDMS dataset and file objects" diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst deleted file mode 100644 index 29edcf08..00000000 --- a/docs/source/cdxmllib.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _cdxmllib: - -cdxmllib -======== -.. currentmodule:: cdms2.cdxmllib - -.. autosummary:: - :toctree: generated/ - - - XMLParser.fixelements - XMLParser.fixclass - XMLParser.fixdict - XMLParser.reset - XMLParser.setnomoretags - XMLParser.setliteral - XMLParser.feed - XMLParser.close - XMLParser.translate_references - XMLParser.getnamespace - XMLParser.goahead - XMLParser.parse_comment - XMLParser.parse_doctype - XMLParser.parse_cdata - XMLParser.parse_proc - XMLParser.parse_attributes - XMLParser.parse_starttag - XMLParser.parse_endtag - XMLParser.finish_starttag - XMLParser.finish_endtag - XMLParser.handle_xml - XMLParser.handle_doctype - XMLParser.handle_starttag - XMLParser.handle_endtag - XMLParser.handle_charref - XMLParser.handle_data - XMLParser.handle_cdata - XMLParser.handle_comment - XMLParser.handle_proc - XMLParser.syntax_error - XMLParser.unknown_starttag - XMLParser.unknown_endtag - XMLParser.unknown_charref - XMLParser.unknown_entityref - diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst index 970a73dc..3c0b069a 100644 --- a/docs/source/forecast.rst +++ b/docs/source/forecast.rst @@ -10,10 +10,8 @@ forecast two_times_from_one available_forecasts comptime - - forecast.close - forecasts + forecasts.__init__ forecasts.forecast_times_to_list forecasts.time_interval_to_list forecasts.reduce_inplace diff --git a/docs/source/grid.rst b/docs/source/grid.rst index adda2c49..68d4855b 100644 --- a/docs/source/grid.rst +++ b/docs/source/grid.rst @@ -8,21 +8,17 @@ grid .. autosummary:: :toctree: generated/ - AbstractGrid.hasCoordType - AbstractGrid.hasCoordType.isGrid - AbstractGrid.hasCoordType.setClassifyGrids - AbstractGrid.hasCoordType.createRectGrid - AbstractGrid.hasCoordType.createUniformGrid - AbstractGrid.hasCoordType.createGlobalmeanGrid - AbstractGrid.hasCoordType.createZonalGrid - AbstractGrid.hasCoordType.createGenericGrid - AbstractGrid.hasCoordType.createGaussianGrid - AbstractGrid.hasCoordType.defaultRegion - AbstractGrid.hasCoordType.setRegionSpecs + isGrid + setClassifyGrids + createRectGrid + createUniformGrid + createGlobalMeanGrid + createZonalGrid + createGenericGrid + createGaussianGrid + defaultRegion + setRegionSpecs - AbstractGrid - AbstractGrid.listall - AbstractGrid.str AbstractGrid.info AbstractGrid.writeToFile AbstractGrid.subSlice @@ -36,16 +32,12 @@ grid AbstractGrid.size AbstractGrid.writeScrip - AbstractRectGrid - AbstractRectGrid.listall - AbstractRectGrid.getshape AbstractRectGrid.getAxis AbstractRectGrid.getBounds AbstractRectGrid.getLatitude AbstractRectGrid.getLongitude AbstractRectGrid.getMask AbstractRectGrid.setMask - AbstractRectGrid.GetOrder AbstractRectGrid.getType AbstractRectGrid.setType AbstractRectGrid.getWeights @@ -57,27 +49,19 @@ grid AbstractRectGrid.genBounds AbstractRectGrid.writeToFile AbstractRectGrid.getMesh - AbstractRectGrid.glatAxes - AbstractRectGrid.size AbstractRectGrid.writeScrip AbstractRectGrid.toCurveGrid AbstractRectGrid.toGenericGrid - AbstractRectGrid.initDomain AbstractRectGrid.getMask - AbstractRectGrid.getMaskVar - FileRectGrid FileRectGrid.setBounds FileRectGrid.getMask FileRectGrid.setMask FileRectGrid.getMaskVar - TransientRectGrid TransientRectGrid.getMask TransientRectGrid.setMask TransientRectGrid.setBounds - TransientRectGrid.isGrid - TransientRectGrid.writeScripGrid diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst index ac244207..b85dcdd0 100644 --- a/docs/source/hgrid.rst +++ b/docs/source/hgrid.rst @@ -8,7 +8,6 @@ hgrid :toctree: generated/ AbstractHorizontalGrid - AbstractHorizontalGrid.flatten AbstractHorizontalGrid.genBounds AbstractHorizontalGrid.getAxis AbstractHorizontalGrid.getBounds @@ -16,7 +15,7 @@ hgrid AbstractHorizontalGrid.getLongitude AbstractHorizontalGrid.getMask AbstractHorizontalGrid.getMesh - AbstractHorizontalGridgetWeightsArray + AbstractHorizontalGrid.getWeightsArray AbstractHorizontalGrid.listall AbstractHorizontalGrid.setMask AbstractHorizontalGrid.subGridRegion @@ -26,9 +25,8 @@ hgrid AbstractCurveGrid AbstractCurveGrid.clone - AbstractCurveGrid.rpr AbstractCurveGrid.getMesh - AbstractCurveGrid.getShape + AbstractCurveGrid._getShape AbstractCurveGrid.genBounds AbstractCurveGrid.getAxis AbstractCurveGrid.getMask @@ -51,14 +49,5 @@ hgrid AbstractCurveGrid.reconcile AbstractCurveGrid.flatAxes - DatasetCurveGrid - DatasetCurveGrid.rpr - - FileCurveGrid - FileCurveGrid.rpr - - TransientCurveGrid - TransientCurveGrid.rpr - TransientCurveGrid.toCurveGrid - TransientCurveGrid.readScripCurveGrid + readScripCurveGrid From ffc6f2e15b267761ed868f35ae9fab2874cfb749 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 21 Aug 2018 18:13:23 -0700 Subject: [PATCH 218/239] add hgrid --- docs/source/generated/cdms2.grid.AbstractGrid.checkAxes.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.dump.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.getAxisList.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.info.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.isClose.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.matchPattern.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.matchone.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.reconcile.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.searchPattern.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.searchPredicate.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.searchone.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.size.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractGrid.subSlice.rst | 6 ++++++ .../source/generated/cdms2.grid.AbstractGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.grid.AbstractGrid.writeToFile.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.checkAxes.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.classify.rst | 6 ++++++ .../cdms2.grid.AbstractRectGrid.classifyInFamily.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractRectGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractRectGrid.dump.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.genBounds.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getAxisList.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getBounds.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getLatitude.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getLongitude.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getMask.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getMesh.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getOrder.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getType.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.getWeights.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.grid.AbstractRectGrid.info.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.isClose.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.matchPattern.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.matchone.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.reconcile.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.searchPattern.rst | 6 ++++++ .../cdms2.grid.AbstractRectGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.searchone.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.setMask.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.setType.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.subGrid.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.subGridRegion.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.toCurveGrid.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.transpose.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.grid.AbstractRectGrid.writeToFile.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.checkAxes.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.classify.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.classifyInFamily.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.dump.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.flatAxes.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.genBounds.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.getAxisList.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getBounds.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.getLatitude.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.getLongitude.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getMask.rst | 6 ++++++ .../source/generated/cdms2.grid.FileRectGrid.getMaskVar.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getMesh.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getOrder.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.getType.rst | 6 ++++++ .../source/generated/cdms2.grid.FileRectGrid.getWeights.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.info.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.isClose.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.matchPattern.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.matchone.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.reconcile.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.searchPattern.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.searchPredicate.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.searchone.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.setBounds.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.setMask.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.setType.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.subGrid.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.subGridRegion.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.toCurveGrid.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.toGenericGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.FileRectGrid.transpose.rst | 6 ++++++ .../source/generated/cdms2.grid.FileRectGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.grid.FileRectGrid.writeToFile.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.checkAxes.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.classify.rst | 6 ++++++ .../cdms2.grid.TransientRectGrid.classifyInFamily.rst | 6 ++++++ .../source/generated/cdms2.grid.TransientRectGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.grid.TransientRectGrid.dump.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.genBounds.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getAxisList.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getBounds.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getLatitude.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getLongitude.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getMask.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getMesh.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getOrder.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getType.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.getWeights.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.grid.TransientRectGrid.info.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.isClose.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.matchPattern.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.matchone.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.reconcile.rst | 6 ++++++ .../cdms2.grid.TransientRectGrid.searchPattern.rst | 6 ++++++ .../cdms2.grid.TransientRectGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.searchone.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.setBounds.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.setMask.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.setType.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.subGrid.rst | 6 ++++++ .../cdms2.grid.TransientRectGrid.subGridRegion.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.toCurveGrid.rst | 6 ++++++ .../cdms2.grid.TransientRectGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.transpose.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.grid.TransientRectGrid.writeToFile.rst | 6 ++++++ docs/source/generated/cdms2.grid.createAxis.rst | 6 ++++++ docs/source/generated/cdms2.grid.createGaussianAxis.rst | 6 ++++++ docs/source/generated/cdms2.grid.createGaussianGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.createGenericGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.createGlobalMeanGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.createRectGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.createUniformGrid.rst | 6 ++++++ .../generated/cdms2.grid.createUniformLatitudeAxis.rst | 6 ++++++ .../generated/cdms2.grid.createUniformLongitudeAxis.rst | 6 ++++++ docs/source/generated/cdms2.grid.createZonalGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.defaultRegion.rst | 6 ++++++ docs/source/generated/cdms2.grid.getAutoBounds.rst | 6 ++++++ docs/source/generated/cdms2.grid.isGrid.rst | 6 ++++++ docs/source/generated/cdms2.grid.isSubsetVector.rst | 6 ++++++ docs/source/generated/cdms2.grid.lookupArray.rst | 6 ++++++ docs/source/generated/cdms2.grid.setClassifyGrids.rst | 6 ++++++ docs/source/generated/cdms2.grid.setRegionSpecs.rst | 6 ++++++ docs/source/generated/cdms2.grid.writeScripGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.__init__.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid._getShape.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.checkAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.checkConvex.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.clone.rst | 6 ++++++ .../source/generated/cdms2.hgrid.AbstractCurveGrid.dump.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.fixCutCells.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.genBounds.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getBounds.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.getGridSlices.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getIndex.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getLatitude.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.getLongitude.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getMask.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.getMesh.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.getWeightsArray.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.hasCoordType.rst | 6 ++++++ .../source/generated/cdms2.hgrid.AbstractCurveGrid.info.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.init_from_gridspec.rst | 6 ++++++ ...dms2.hgrid.AbstractCurveGrid.init_from_gridspec_file.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.intersect.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.isClose.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.listall.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.matchPattern.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.matchone.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.reconcile.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.searchPattern.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.searchone.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.setMask.rst | 6 ++++++ .../source/generated/cdms2.hgrid.AbstractCurveGrid.size.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.subGridRegion.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.toCurveGrid.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.writeToFile.rst | 6 ++++++ .../cdms2.hgrid.AbstractCurveGrid.write_gridspec.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractCurveGrid.writeg.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.checkAxes.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.checkConvex.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractHorizontalGrid.clone.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractHorizontalGrid.dump.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.fixCutCells.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.flatAxes.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.genBounds.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getAxis.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getAxisList.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getBounds.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getLatitude.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getLongitude.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getMask.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getMesh.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.getWeightsArray.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.hasCoordType.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractHorizontalGrid.info.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.isClose.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.listall.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.matchPattern.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.matchone.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.reconcile.rst | 6 ++++++ .../source/generated/cdms2.hgrid.AbstractHorizontalGrid.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.searchPattern.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.searchPredicate.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.searchone.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.setMask.rst | 6 ++++++ .../generated/cdms2.hgrid.AbstractHorizontalGrid.size.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.subGridRegion.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.subSlice.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.writeScrip.rst | 6 ++++++ .../cdms2.hgrid.AbstractHorizontalGrid.writeToFile.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.__init__.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid._getShape.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.checkAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.checkConvex.rst | 6 ++++++ .../source/generated/cdms2.hgrid.DatasetCurveGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.DatasetCurveGrid.dump.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.fixCutCells.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.genBounds.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getBounds.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.getGridSlices.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getIndex.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getLatitude.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getLongitude.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getMask.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.getMesh.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.getWeightsArray.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.DatasetCurveGrid.info.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.init_from_gridspec.rst | 6 ++++++ ...cdms2.hgrid.DatasetCurveGrid.init_from_gridspec_file.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.intersect.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.isClose.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.listall.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.matchPattern.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.matchone.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.reconcile.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.searchPattern.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.searchone.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.setMask.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.DatasetCurveGrid.size.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.subGridRegion.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.toCurveGrid.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.writeToFile.rst | 6 ++++++ .../cdms2.hgrid.DatasetCurveGrid.write_gridspec.rst | 6 ++++++ .../generated/cdms2.hgrid.DatasetCurveGrid.writeg.rst | 6 ++++++ .../source/generated/cdms2.hgrid.FileCurveGrid.__init__.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid._getShape.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.checkAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.checkConvex.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.clone.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.dump.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.fixCutCells.rst | 6 ++++++ .../source/generated/cdms2.hgrid.FileCurveGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.genBounds.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.getBounds.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.getGridSlices.rst | 6 ++++++ .../source/generated/cdms2.hgrid.FileCurveGrid.getIndex.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.getLatitude.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.getLongitude.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.getMask.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.getMesh.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.getWeightsArray.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.hasCoordType.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.info.rst | 6 ++++++ .../cdms2.hgrid.FileCurveGrid.init_from_gridspec.rst | 6 ++++++ .../cdms2.hgrid.FileCurveGrid.init_from_gridspec_file.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.intersect.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.isClose.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.listall.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.matchPattern.rst | 6 ++++++ .../source/generated/cdms2.hgrid.FileCurveGrid.matchone.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.reconcile.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.searchPattern.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.searchone.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.setMask.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.size.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.subGridRegion.rst | 6 ++++++ .../source/generated/cdms2.hgrid.FileCurveGrid.subSlice.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.toCurveGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.writeScrip.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.writeToFile.rst | 6 ++++++ .../generated/cdms2.hgrid.FileCurveGrid.write_gridspec.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.FileCurveGrid.writeg.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.__init__.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid._getShape.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.checkAxes.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.checkConvex.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.clone.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.dump.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.fixCutCells.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.flatAxes.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.genBounds.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.getAxis.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.getBounds.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.getGridSlices.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.getIndex.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.getLatitude.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.getLongitude.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.getMask.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.getMesh.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.getWeightsArray.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.hasCoordType.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.info.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.init_from_gridspec.rst | 6 ++++++ ...ms2.hgrid.TransientCurveGrid.init_from_gridspec_file.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.intersect.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.isClose.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.listall.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.matchPattern.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.matchone.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.reconcile.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.searchPattern.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.searchPredicate.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.searchone.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.setMask.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.size.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.subGridRegion.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.subSlice.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.toCurveGrid.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.toGenericGrid.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.writeScrip.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.writeToFile.rst | 6 ++++++ .../cdms2.hgrid.TransientCurveGrid.write_gridspec.rst | 6 ++++++ .../generated/cdms2.hgrid.TransientCurveGrid.writeg.rst | 6 ++++++ docs/source/generated/cdms2.hgrid._flatten.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.allclose.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.getAutoBounds.rst | 6 ++++++ docs/source/generated/cdms2.hgrid.readScripCurveGrid.rst | 6 ++++++ 347 files changed, 2082 insertions(+) create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.clone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.dump.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.getAxisList.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.info.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.size.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.classify.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.classifyInFamily.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.clone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.dump.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getAxisList.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getOrder.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getType.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.getWeights.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.info.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.setType.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.subGrid.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.transpose.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.grid.AbstractRectGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.classify.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.classifyInFamily.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.clone.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.dump.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getAxisList.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getMaskVar.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getOrder.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getType.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.getWeights.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.info.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.setBounds.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.setType.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.subGrid.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.transpose.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.grid.FileRectGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.classify.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.classifyInFamily.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.clone.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.dump.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getAxisList.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getOrder.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getType.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.getWeights.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.info.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.setBounds.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.setType.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.subGrid.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.transpose.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.grid.TransientRectGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.grid.createAxis.rst create mode 100644 docs/source/generated/cdms2.grid.createGaussianAxis.rst create mode 100644 docs/source/generated/cdms2.grid.createGaussianGrid.rst create mode 100644 docs/source/generated/cdms2.grid.createGenericGrid.rst create mode 100644 docs/source/generated/cdms2.grid.createGlobalMeanGrid.rst create mode 100644 docs/source/generated/cdms2.grid.createRectGrid.rst create mode 100644 docs/source/generated/cdms2.grid.createUniformGrid.rst create mode 100644 docs/source/generated/cdms2.grid.createUniformLatitudeAxis.rst create mode 100644 docs/source/generated/cdms2.grid.createUniformLongitudeAxis.rst create mode 100644 docs/source/generated/cdms2.grid.createZonalGrid.rst create mode 100644 docs/source/generated/cdms2.grid.defaultRegion.rst create mode 100644 docs/source/generated/cdms2.grid.getAutoBounds.rst create mode 100644 docs/source/generated/cdms2.grid.isGrid.rst create mode 100644 docs/source/generated/cdms2.grid.isSubsetVector.rst create mode 100644 docs/source/generated/cdms2.grid.lookupArray.rst create mode 100644 docs/source/generated/cdms2.grid.setClassifyGrids.rst create mode 100644 docs/source/generated/cdms2.grid.setRegionSpecs.rst create mode 100644 docs/source/generated/cdms2.grid.writeScripGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.__init__.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid._getShape.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkConvex.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.clone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.dump.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.fixCutCells.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getGridSlices.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getIndex.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getWeightsArray.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.info.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec_file.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.intersect.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.listall.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.size.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.write_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeg.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkConvex.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.clone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.dump.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.fixCutCells.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxisList.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getWeightsArray.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.info.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.listall.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.size.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.__init__.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid._getShape.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkConvex.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.clone.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.dump.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.fixCutCells.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getGridSlices.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getIndex.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getWeightsArray.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.info.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec_file.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.intersect.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.listall.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.size.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.write_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeg.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.__init__.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid._getShape.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.checkConvex.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.clone.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.dump.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.fixCutCells.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getGridSlices.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getIndex.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.getWeightsArray.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.info.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec_file.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.intersect.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.listall.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.size.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.write_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.FileCurveGrid.writeg.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.__init__.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid._getShape.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkConvex.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.clone.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.dump.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.fixCutCells.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.flatAxes.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.genBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getAxis.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getGridSlices.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getIndex.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLatitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLongitude.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMesh.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.getWeightsArray.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.hasCoordType.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.info.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec_file.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.intersect.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.isClose.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.listall.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.reconcile.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPattern.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPredicate.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchone.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.setMask.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.size.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.subGridRegion.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.subSlice.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.toCurveGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.toGenericGrid.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeScrip.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeToFile.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.write_gridspec.rst create mode 100644 docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeg.rst create mode 100644 docs/source/generated/cdms2.hgrid._flatten.rst create mode 100644 docs/source/generated/cdms2.hgrid.allclose.rst create mode 100644 docs/source/generated/cdms2.hgrid.getAutoBounds.rst create mode 100644 docs/source/generated/cdms2.hgrid.readScripCurveGrid.rst diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.checkAxes.rst b/docs/source/generated/cdms2.grid.AbstractGrid.checkAxes.rst new file mode 100644 index 00000000..ea7b9904 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.checkAxes diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.clone.rst b/docs/source/generated/cdms2.grid.AbstractGrid.clone.rst new file mode 100644 index 00000000..a5c3255a --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.clone diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.dump.rst b/docs/source/generated/cdms2.grid.AbstractGrid.dump.rst new file mode 100644 index 00000000..508c1814 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.dump diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.flatAxes.rst b/docs/source/generated/cdms2.grid.AbstractGrid.flatAxes.rst new file mode 100644 index 00000000..0d07d8d9 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.flatAxes diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.getAxisList.rst b/docs/source/generated/cdms2.grid.AbstractGrid.getAxisList.rst new file mode 100644 index 00000000..fcf23e65 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.getAxisList diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.hasCoordType.rst b/docs/source/generated/cdms2.grid.AbstractGrid.hasCoordType.rst new file mode 100644 index 00000000..2af6389a --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.hasCoordType diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.info.rst b/docs/source/generated/cdms2.grid.AbstractGrid.info.rst new file mode 100644 index 00000000..b2d91739 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.info diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.isClose.rst b/docs/source/generated/cdms2.grid.AbstractGrid.isClose.rst new file mode 100644 index 00000000..c24e892f --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.isClose diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.matchPattern.rst b/docs/source/generated/cdms2.grid.AbstractGrid.matchPattern.rst new file mode 100644 index 00000000..a8a6c6f1 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.matchPattern diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.matchone.rst b/docs/source/generated/cdms2.grid.AbstractGrid.matchone.rst new file mode 100644 index 00000000..fe57e6bb --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.matchone diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.reconcile.rst b/docs/source/generated/cdms2.grid.AbstractGrid.reconcile.rst new file mode 100644 index 00000000..00748dc5 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.reconcile diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.searchPattern.rst b/docs/source/generated/cdms2.grid.AbstractGrid.searchPattern.rst new file mode 100644 index 00000000..1c92a830 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.searchPattern diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.searchPredicate.rst b/docs/source/generated/cdms2.grid.AbstractGrid.searchPredicate.rst new file mode 100644 index 00000000..9bf66479 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.searchPredicate diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.searchone.rst b/docs/source/generated/cdms2.grid.AbstractGrid.searchone.rst new file mode 100644 index 00000000..45e84882 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.searchone diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.size.rst b/docs/source/generated/cdms2.grid.AbstractGrid.size.rst new file mode 100644 index 00000000..fb51c72c --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.size diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.subSlice.rst b/docs/source/generated/cdms2.grid.AbstractGrid.subSlice.rst new file mode 100644 index 00000000..5cccb1d6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.subSlice diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.writeScrip.rst b/docs/source/generated/cdms2.grid.AbstractGrid.writeScrip.rst new file mode 100644 index 00000000..33e94544 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.writeScrip diff --git a/docs/source/generated/cdms2.grid.AbstractGrid.writeToFile.rst b/docs/source/generated/cdms2.grid.AbstractGrid.writeToFile.rst new file mode 100644 index 00000000..74f297e2 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractGrid.writeToFile diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.checkAxes.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.checkAxes.rst new file mode 100644 index 00000000..efd9b75f --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.checkAxes diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.classify.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.classify.rst new file mode 100644 index 00000000..56190d04 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.classify.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.classify diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.classifyInFamily.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.classifyInFamily.rst new file mode 100644 index 00000000..091c74ef --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.classifyInFamily.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.classifyInFamily diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.clone.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.clone.rst new file mode 100644 index 00000000..79e4df1e --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.clone diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.dump.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.dump.rst new file mode 100644 index 00000000..753e3c62 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.dump diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.flatAxes.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.flatAxes.rst new file mode 100644 index 00000000..1fabe3ac --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.flatAxes diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.genBounds.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.genBounds.rst new file mode 100644 index 00000000..210dcd70 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.genBounds diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxis.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxis.rst new file mode 100644 index 00000000..0d57af36 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getAxis diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxisList.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxisList.rst new file mode 100644 index 00000000..549efe63 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getAxisList diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getBounds.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getBounds.rst new file mode 100644 index 00000000..5a2cdf5d --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getBounds diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getLatitude.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getLatitude.rst new file mode 100644 index 00000000..b14c4ce1 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getLatitude diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getLongitude.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getLongitude.rst new file mode 100644 index 00000000..e7c73742 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getLongitude diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getMask.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getMask.rst new file mode 100644 index 00000000..f58ecc65 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getMask diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getMesh.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getMesh.rst new file mode 100644 index 00000000..80e30a41 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getMesh diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getOrder.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getOrder.rst new file mode 100644 index 00000000..36ac500f --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getOrder diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getType.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getType.rst new file mode 100644 index 00000000..2dba4983 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getType.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getType diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.getWeights.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.getWeights.rst new file mode 100644 index 00000000..1ff4967e --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.getWeights.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.getWeights diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.hasCoordType.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.hasCoordType.rst new file mode 100644 index 00000000..9fe9b84b --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.hasCoordType diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.info.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.info.rst new file mode 100644 index 00000000..f73c9630 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.info diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.isClose.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.isClose.rst new file mode 100644 index 00000000..15d1464f --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.isClose diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.matchPattern.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.matchPattern.rst new file mode 100644 index 00000000..af69c48b --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.matchPattern diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.matchone.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.matchone.rst new file mode 100644 index 00000000..f94a6d7d --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.matchone diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.reconcile.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.reconcile.rst new file mode 100644 index 00000000..dc12512e --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.reconcile diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPattern.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPattern.rst new file mode 100644 index 00000000..7c397b08 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.searchPattern diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPredicate.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPredicate.rst new file mode 100644 index 00000000..734e6126 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.searchPredicate diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.searchone.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchone.rst new file mode 100644 index 00000000..9c8c3042 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.searchone diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.setMask.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.setMask.rst new file mode 100644 index 00000000..21774b26 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.setMask diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.setType.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.setType.rst new file mode 100644 index 00000000..d6dd3047 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.setType.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.setType diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.subGrid.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.subGrid.rst new file mode 100644 index 00000000..8458f1f0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.subGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.subGrid diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.subGridRegion.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.subGridRegion.rst new file mode 100644 index 00000000..6c9faf8b --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.subGridRegion diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.subSlice.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.subSlice.rst new file mode 100644 index 00000000..c86aefef --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.subSlice diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.toCurveGrid.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.toCurveGrid.rst new file mode 100644 index 00000000..49488744 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.toCurveGrid diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.toGenericGrid.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.toGenericGrid.rst new file mode 100644 index 00000000..e99ad0f5 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.toGenericGrid diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.transpose.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.transpose.rst new file mode 100644 index 00000000..19b1b1bd --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.transpose.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.transpose diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.writeScrip.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.writeScrip.rst new file mode 100644 index 00000000..59eaf8de --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.writeScrip diff --git a/docs/source/generated/cdms2.grid.AbstractRectGrid.writeToFile.rst b/docs/source/generated/cdms2.grid.AbstractRectGrid.writeToFile.rst new file mode 100644 index 00000000..b6ce22d8 --- /dev/null +++ b/docs/source/generated/cdms2.grid.AbstractRectGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.grid:AbstractRectGrid +=========================== + +.. currentmodule:: cdms2.grid + +.. automethod:: AbstractRectGrid.writeToFile diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.checkAxes.rst b/docs/source/generated/cdms2.grid.FileRectGrid.checkAxes.rst new file mode 100644 index 00000000..37c8ffc6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.checkAxes diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.classify.rst b/docs/source/generated/cdms2.grid.FileRectGrid.classify.rst new file mode 100644 index 00000000..3d1466ec --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.classify.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.classify diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.classifyInFamily.rst b/docs/source/generated/cdms2.grid.FileRectGrid.classifyInFamily.rst new file mode 100644 index 00000000..51e74711 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.classifyInFamily.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.classifyInFamily diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.clone.rst b/docs/source/generated/cdms2.grid.FileRectGrid.clone.rst new file mode 100644 index 00000000..abaa20c8 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.clone diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.dump.rst b/docs/source/generated/cdms2.grid.FileRectGrid.dump.rst new file mode 100644 index 00000000..f4bf8200 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.dump diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.flatAxes.rst b/docs/source/generated/cdms2.grid.FileRectGrid.flatAxes.rst new file mode 100644 index 00000000..e0a77e53 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.flatAxes diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.genBounds.rst b/docs/source/generated/cdms2.grid.FileRectGrid.genBounds.rst new file mode 100644 index 00000000..92e256c6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.genBounds diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getAxis.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getAxis.rst new file mode 100644 index 00000000..7e3343d0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getAxis diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getAxisList.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getAxisList.rst new file mode 100644 index 00000000..3b5eab63 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getAxisList diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getBounds.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getBounds.rst new file mode 100644 index 00000000..12613f61 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getBounds diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getLatitude.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getLatitude.rst new file mode 100644 index 00000000..9d88f915 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getLatitude diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getLongitude.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getLongitude.rst new file mode 100644 index 00000000..29011321 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getLongitude diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getMask.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getMask.rst new file mode 100644 index 00000000..f460be25 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getMask diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getMaskVar.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getMaskVar.rst new file mode 100644 index 00000000..204fc710 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getMaskVar.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getMaskVar diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getMesh.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getMesh.rst new file mode 100644 index 00000000..b8f6900d --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getMesh diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getOrder.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getOrder.rst new file mode 100644 index 00000000..2fde37ee --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getOrder diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getType.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getType.rst new file mode 100644 index 00000000..66343589 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getType.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getType diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.getWeights.rst b/docs/source/generated/cdms2.grid.FileRectGrid.getWeights.rst new file mode 100644 index 00000000..c91a0a3f --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.getWeights.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.getWeights diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.hasCoordType.rst b/docs/source/generated/cdms2.grid.FileRectGrid.hasCoordType.rst new file mode 100644 index 00000000..1861e051 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.hasCoordType diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.info.rst b/docs/source/generated/cdms2.grid.FileRectGrid.info.rst new file mode 100644 index 00000000..b6f5e0e5 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.info diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.isClose.rst b/docs/source/generated/cdms2.grid.FileRectGrid.isClose.rst new file mode 100644 index 00000000..34fcb434 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.isClose diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.matchPattern.rst b/docs/source/generated/cdms2.grid.FileRectGrid.matchPattern.rst new file mode 100644 index 00000000..6627dac3 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.matchPattern diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.matchone.rst b/docs/source/generated/cdms2.grid.FileRectGrid.matchone.rst new file mode 100644 index 00000000..4ec7a0db --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.matchone diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.reconcile.rst b/docs/source/generated/cdms2.grid.FileRectGrid.reconcile.rst new file mode 100644 index 00000000..6409fab0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.reconcile diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.searchPattern.rst b/docs/source/generated/cdms2.grid.FileRectGrid.searchPattern.rst new file mode 100644 index 00000000..6d91fd64 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.searchPattern diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.searchPredicate.rst b/docs/source/generated/cdms2.grid.FileRectGrid.searchPredicate.rst new file mode 100644 index 00000000..cda1b232 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.searchPredicate diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.searchone.rst b/docs/source/generated/cdms2.grid.FileRectGrid.searchone.rst new file mode 100644 index 00000000..971f2266 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.searchone diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.setBounds.rst b/docs/source/generated/cdms2.grid.FileRectGrid.setBounds.rst new file mode 100644 index 00000000..d67426fa --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.setBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.setBounds diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.setMask.rst b/docs/source/generated/cdms2.grid.FileRectGrid.setMask.rst new file mode 100644 index 00000000..101d0ca7 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.setMask diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.setType.rst b/docs/source/generated/cdms2.grid.FileRectGrid.setType.rst new file mode 100644 index 00000000..ad599dea --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.setType.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.setType diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.subGrid.rst b/docs/source/generated/cdms2.grid.FileRectGrid.subGrid.rst new file mode 100644 index 00000000..6d272b28 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.subGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.subGrid diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.subGridRegion.rst b/docs/source/generated/cdms2.grid.FileRectGrid.subGridRegion.rst new file mode 100644 index 00000000..8b2dc47a --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.subGridRegion diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.subSlice.rst b/docs/source/generated/cdms2.grid.FileRectGrid.subSlice.rst new file mode 100644 index 00000000..31ccd699 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.subSlice diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.toCurveGrid.rst b/docs/source/generated/cdms2.grid.FileRectGrid.toCurveGrid.rst new file mode 100644 index 00000000..ac9601ad --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.toCurveGrid diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.toGenericGrid.rst b/docs/source/generated/cdms2.grid.FileRectGrid.toGenericGrid.rst new file mode 100644 index 00000000..e1d466ab --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.toGenericGrid diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.transpose.rst b/docs/source/generated/cdms2.grid.FileRectGrid.transpose.rst new file mode 100644 index 00000000..483c496c --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.transpose.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.transpose diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.writeScrip.rst b/docs/source/generated/cdms2.grid.FileRectGrid.writeScrip.rst new file mode 100644 index 00000000..771ffe43 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.writeScrip diff --git a/docs/source/generated/cdms2.grid.FileRectGrid.writeToFile.rst b/docs/source/generated/cdms2.grid.FileRectGrid.writeToFile.rst new file mode 100644 index 00000000..db8fd3b4 --- /dev/null +++ b/docs/source/generated/cdms2.grid.FileRectGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.grid:FileRectGrid +======================= + +.. currentmodule:: cdms2.grid + +.. automethod:: FileRectGrid.writeToFile diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.checkAxes.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.checkAxes.rst new file mode 100644 index 00000000..6bb152c6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.checkAxes diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.classify.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.classify.rst new file mode 100644 index 00000000..6cfcea5b --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.classify.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.classify diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.classifyInFamily.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.classifyInFamily.rst new file mode 100644 index 00000000..1c35b307 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.classifyInFamily.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.classifyInFamily diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.clone.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.clone.rst new file mode 100644 index 00000000..8d95b16d --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.clone diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.dump.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.dump.rst new file mode 100644 index 00000000..8c64d0d0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.dump diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.flatAxes.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.flatAxes.rst new file mode 100644 index 00000000..bbc954d2 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.flatAxes diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.genBounds.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.genBounds.rst new file mode 100644 index 00000000..fe0a0c96 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.genBounds diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getAxis.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getAxis.rst new file mode 100644 index 00000000..f62551fb --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getAxis diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getAxisList.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getAxisList.rst new file mode 100644 index 00000000..933aff6d --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getAxisList diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getBounds.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getBounds.rst new file mode 100644 index 00000000..b2e51601 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getBounds diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getLatitude.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getLatitude.rst new file mode 100644 index 00000000..497a1a96 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getLatitude diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getLongitude.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getLongitude.rst new file mode 100644 index 00000000..1c19ac72 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getLongitude diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getMask.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getMask.rst new file mode 100644 index 00000000..9e5114d6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getMask diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getMesh.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getMesh.rst new file mode 100644 index 00000000..c419f446 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getMesh diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getOrder.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getOrder.rst new file mode 100644 index 00000000..4fc71a5a --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getOrder.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getOrder diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getType.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getType.rst new file mode 100644 index 00000000..99e95a6e --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getType.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getType diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.getWeights.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.getWeights.rst new file mode 100644 index 00000000..33552ece --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.getWeights.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.getWeights diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.hasCoordType.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.hasCoordType.rst new file mode 100644 index 00000000..413131c0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.hasCoordType diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.info.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.info.rst new file mode 100644 index 00000000..cf65ebb5 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.info diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.isClose.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.isClose.rst new file mode 100644 index 00000000..67cf9c86 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.isClose diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.matchPattern.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.matchPattern.rst new file mode 100644 index 00000000..85b911eb --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.matchPattern diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.matchone.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.matchone.rst new file mode 100644 index 00000000..9f4b1bbb --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.matchone diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.reconcile.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.reconcile.rst new file mode 100644 index 00000000..fb5113f0 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.reconcile diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.searchPattern.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.searchPattern.rst new file mode 100644 index 00000000..c8199bad --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.searchPattern diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.searchPredicate.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.searchPredicate.rst new file mode 100644 index 00000000..d97eebca --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.searchPredicate diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.searchone.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.searchone.rst new file mode 100644 index 00000000..37f1ed44 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.searchone diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.setBounds.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.setBounds.rst new file mode 100644 index 00000000..6014fc0b --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.setBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.setBounds diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.setMask.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.setMask.rst new file mode 100644 index 00000000..76df1dac --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.setMask diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.setType.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.setType.rst new file mode 100644 index 00000000..05e4ecc6 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.setType.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.setType diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.subGrid.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.subGrid.rst new file mode 100644 index 00000000..dc520ca1 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.subGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.subGrid diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.subGridRegion.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.subGridRegion.rst new file mode 100644 index 00000000..8960c10c --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.subGridRegion diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.subSlice.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.subSlice.rst new file mode 100644 index 00000000..c8dfa5e5 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.subSlice diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.toCurveGrid.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.toCurveGrid.rst new file mode 100644 index 00000000..d91741dd --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.toCurveGrid diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.toGenericGrid.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.toGenericGrid.rst new file mode 100644 index 00000000..cb9e423e --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.toGenericGrid diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.transpose.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.transpose.rst new file mode 100644 index 00000000..e515555d --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.transpose.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.transpose diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.writeScrip.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.writeScrip.rst new file mode 100644 index 00000000..f58e8011 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.writeScrip diff --git a/docs/source/generated/cdms2.grid.TransientRectGrid.writeToFile.rst b/docs/source/generated/cdms2.grid.TransientRectGrid.writeToFile.rst new file mode 100644 index 00000000..c42dcd73 --- /dev/null +++ b/docs/source/generated/cdms2.grid.TransientRectGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.grid:TransientRectGrid +============================ + +.. currentmodule:: cdms2.grid + +.. automethod:: TransientRectGrid.writeToFile diff --git a/docs/source/generated/cdms2.grid.createAxis.rst b/docs/source/generated/cdms2.grid.createAxis.rst new file mode 100644 index 00000000..a06f7ffd --- /dev/null +++ b/docs/source/generated/cdms2.grid.createAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createAxis diff --git a/docs/source/generated/cdms2.grid.createGaussianAxis.rst b/docs/source/generated/cdms2.grid.createGaussianAxis.rst new file mode 100644 index 00000000..b1958a38 --- /dev/null +++ b/docs/source/generated/cdms2.grid.createGaussianAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createGaussianAxis diff --git a/docs/source/generated/cdms2.grid.createGaussianGrid.rst b/docs/source/generated/cdms2.grid.createGaussianGrid.rst new file mode 100644 index 00000000..7f17065d --- /dev/null +++ b/docs/source/generated/cdms2.grid.createGaussianGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createGaussianGrid diff --git a/docs/source/generated/cdms2.grid.createGenericGrid.rst b/docs/source/generated/cdms2.grid.createGenericGrid.rst new file mode 100644 index 00000000..46d7c34e --- /dev/null +++ b/docs/source/generated/cdms2.grid.createGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createGenericGrid diff --git a/docs/source/generated/cdms2.grid.createGlobalMeanGrid.rst b/docs/source/generated/cdms2.grid.createGlobalMeanGrid.rst new file mode 100644 index 00000000..59485e25 --- /dev/null +++ b/docs/source/generated/cdms2.grid.createGlobalMeanGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createGlobalMeanGrid diff --git a/docs/source/generated/cdms2.grid.createRectGrid.rst b/docs/source/generated/cdms2.grid.createRectGrid.rst new file mode 100644 index 00000000..bb36afc3 --- /dev/null +++ b/docs/source/generated/cdms2.grid.createRectGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createRectGrid diff --git a/docs/source/generated/cdms2.grid.createUniformGrid.rst b/docs/source/generated/cdms2.grid.createUniformGrid.rst new file mode 100644 index 00000000..f3035bca --- /dev/null +++ b/docs/source/generated/cdms2.grid.createUniformGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createUniformGrid diff --git a/docs/source/generated/cdms2.grid.createUniformLatitudeAxis.rst b/docs/source/generated/cdms2.grid.createUniformLatitudeAxis.rst new file mode 100644 index 00000000..d739d6cf --- /dev/null +++ b/docs/source/generated/cdms2.grid.createUniformLatitudeAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createUniformLatitudeAxis diff --git a/docs/source/generated/cdms2.grid.createUniformLongitudeAxis.rst b/docs/source/generated/cdms2.grid.createUniformLongitudeAxis.rst new file mode 100644 index 00000000..7c4f6e6c --- /dev/null +++ b/docs/source/generated/cdms2.grid.createUniformLongitudeAxis.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createUniformLongitudeAxis diff --git a/docs/source/generated/cdms2.grid.createZonalGrid.rst b/docs/source/generated/cdms2.grid.createZonalGrid.rst new file mode 100644 index 00000000..38b2fe07 --- /dev/null +++ b/docs/source/generated/cdms2.grid.createZonalGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: createZonalGrid diff --git a/docs/source/generated/cdms2.grid.defaultRegion.rst b/docs/source/generated/cdms2.grid.defaultRegion.rst new file mode 100644 index 00000000..b5030da3 --- /dev/null +++ b/docs/source/generated/cdms2.grid.defaultRegion.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: defaultRegion diff --git a/docs/source/generated/cdms2.grid.getAutoBounds.rst b/docs/source/generated/cdms2.grid.getAutoBounds.rst new file mode 100644 index 00000000..e8200033 --- /dev/null +++ b/docs/source/generated/cdms2.grid.getAutoBounds.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: getAutoBounds diff --git a/docs/source/generated/cdms2.grid.isGrid.rst b/docs/source/generated/cdms2.grid.isGrid.rst new file mode 100644 index 00000000..b40bb08b --- /dev/null +++ b/docs/source/generated/cdms2.grid.isGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: isGrid diff --git a/docs/source/generated/cdms2.grid.isSubsetVector.rst b/docs/source/generated/cdms2.grid.isSubsetVector.rst new file mode 100644 index 00000000..dcc202c8 --- /dev/null +++ b/docs/source/generated/cdms2.grid.isSubsetVector.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: isSubsetVector diff --git a/docs/source/generated/cdms2.grid.lookupArray.rst b/docs/source/generated/cdms2.grid.lookupArray.rst new file mode 100644 index 00000000..0762106c --- /dev/null +++ b/docs/source/generated/cdms2.grid.lookupArray.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: lookupArray diff --git a/docs/source/generated/cdms2.grid.setClassifyGrids.rst b/docs/source/generated/cdms2.grid.setClassifyGrids.rst new file mode 100644 index 00000000..fb98ddf3 --- /dev/null +++ b/docs/source/generated/cdms2.grid.setClassifyGrids.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: setClassifyGrids diff --git a/docs/source/generated/cdms2.grid.setRegionSpecs.rst b/docs/source/generated/cdms2.grid.setRegionSpecs.rst new file mode 100644 index 00000000..b1f1ae3b --- /dev/null +++ b/docs/source/generated/cdms2.grid.setRegionSpecs.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: setRegionSpecs diff --git a/docs/source/generated/cdms2.grid.writeScripGrid.rst b/docs/source/generated/cdms2.grid.writeScripGrid.rst new file mode 100644 index 00000000..42c7bb8b --- /dev/null +++ b/docs/source/generated/cdms2.grid.writeScripGrid.rst @@ -0,0 +1,6 @@ +cdms2.grid +========== + +.. currentmodule:: cdms2.grid + +.. autofunction:: writeScripGrid diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.__init__.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.__init__.rst new file mode 100644 index 00000000..5e8d2173 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.__init__.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.__init__ diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid._getShape.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid._getShape.rst new file mode 100644 index 00000000..8473fbca --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid._getShape.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid._getShape diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkAxes.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkAxes.rst new file mode 100644 index 00000000..e359e457 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.checkAxes diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkConvex.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkConvex.rst new file mode 100644 index 00000000..dea9c972 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.checkConvex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.checkConvex diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.clone.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.clone.rst new file mode 100644 index 00000000..19e58978 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.clone diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.dump.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.dump.rst new file mode 100644 index 00000000..07e15b8c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.dump diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.fixCutCells.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.fixCutCells.rst new file mode 100644 index 00000000..798ccc53 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.fixCutCells.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.fixCutCells diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.flatAxes.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.flatAxes.rst new file mode 100644 index 00000000..8d108aaa --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.flatAxes diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.genBounds.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.genBounds.rst new file mode 100644 index 00000000..eb86437b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.genBounds diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getAxis.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getAxis.rst new file mode 100644 index 00000000..b86924fa --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getAxis diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getBounds.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getBounds.rst new file mode 100644 index 00000000..65975362 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getBounds diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getGridSlices.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getGridSlices.rst new file mode 100644 index 00000000..204fc75a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getGridSlices.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getGridSlices diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getIndex.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getIndex.rst new file mode 100644 index 00000000..2f3cc922 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getIndex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getIndex diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLatitude.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLatitude.rst new file mode 100644 index 00000000..c03b77ed --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getLatitude diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLongitude.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLongitude.rst new file mode 100644 index 00000000..a168dc18 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getLongitude diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMask.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMask.rst new file mode 100644 index 00000000..0e89c47f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getMask diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMesh.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMesh.rst new file mode 100644 index 00000000..d0a452e5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getMesh diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getWeightsArray.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getWeightsArray.rst new file mode 100644 index 00000000..f7da2d55 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.getWeightsArray.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.getWeightsArray diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.hasCoordType.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.hasCoordType.rst new file mode 100644 index 00000000..b7a77d04 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.hasCoordType diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.info.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.info.rst new file mode 100644 index 00000000..05348114 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.info diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec.rst new file mode 100644 index 00000000..2a50cc09 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.init_from_gridspec diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec_file.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec_file.rst new file mode 100644 index 00000000..19f5d6d1 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.init_from_gridspec_file.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.init_from_gridspec_file diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.intersect.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.intersect.rst new file mode 100644 index 00000000..dff719f0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.intersect.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.intersect diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.isClose.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.isClose.rst new file mode 100644 index 00000000..54631f0f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.isClose diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.listall.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.listall.rst new file mode 100644 index 00000000..a9cd5112 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.listall.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.listall diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchPattern.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchPattern.rst new file mode 100644 index 00000000..99bf39b2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.matchPattern diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchone.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchone.rst new file mode 100644 index 00000000..e4cb558a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.matchone diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.reconcile.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.reconcile.rst new file mode 100644 index 00000000..24e800a8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.reconcile diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPattern.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPattern.rst new file mode 100644 index 00000000..e8b0d7c2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.searchPattern diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPredicate.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPredicate.rst new file mode 100644 index 00000000..de63f0f0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.searchPredicate diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchone.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchone.rst new file mode 100644 index 00000000..d40616bf --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.searchone diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.setMask.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.setMask.rst new file mode 100644 index 00000000..92acda8a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.setMask diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.size.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.size.rst new file mode 100644 index 00000000..1dd946d1 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.size diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subGridRegion.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subGridRegion.rst new file mode 100644 index 00000000..c8729ef9 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.subGridRegion diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subSlice.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subSlice.rst new file mode 100644 index 00000000..ad1101ca --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.subSlice diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toCurveGrid.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toCurveGrid.rst new file mode 100644 index 00000000..3be70445 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.toCurveGrid diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toGenericGrid.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toGenericGrid.rst new file mode 100644 index 00000000..8a4d66ab --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.toGenericGrid diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeScrip.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeScrip.rst new file mode 100644 index 00000000..4e63906d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.writeScrip diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeToFile.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeToFile.rst new file mode 100644 index 00000000..fd340a41 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.writeToFile diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.write_gridspec.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.write_gridspec.rst new file mode 100644 index 00000000..3dace448 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.write_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.write_gridspec diff --git a/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeg.rst b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeg.rst new file mode 100644 index 00000000..cca80ab6 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractCurveGrid.writeg.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractCurveGrid +============================= + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractCurveGrid.writeg diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkAxes.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkAxes.rst new file mode 100644 index 00000000..f6f60289 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.checkAxes diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkConvex.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkConvex.rst new file mode 100644 index 00000000..f0cc51a3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.checkConvex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.checkConvex diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.clone.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.clone.rst new file mode 100644 index 00000000..29252441 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.clone diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.dump.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.dump.rst new file mode 100644 index 00000000..115d17ab --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.dump diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.fixCutCells.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.fixCutCells.rst new file mode 100644 index 00000000..092e45b3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.fixCutCells.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.fixCutCells diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.flatAxes.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.flatAxes.rst new file mode 100644 index 00000000..c64eb766 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.flatAxes diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.genBounds.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.genBounds.rst new file mode 100644 index 00000000..dd3bb3cc --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.genBounds diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxis.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxis.rst new file mode 100644 index 00000000..592e3bf9 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getAxis diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxisList.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxisList.rst new file mode 100644 index 00000000..47dd98d4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getAxisList.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getAxisList diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getBounds.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getBounds.rst new file mode 100644 index 00000000..3e810aab --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getBounds diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLatitude.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLatitude.rst new file mode 100644 index 00000000..b301fcc5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getLatitude diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLongitude.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLongitude.rst new file mode 100644 index 00000000..96095ae0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getLongitude diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMask.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMask.rst new file mode 100644 index 00000000..177f1a41 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getMask diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMesh.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMesh.rst new file mode 100644 index 00000000..58e61f3f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getMesh diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getWeightsArray.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getWeightsArray.rst new file mode 100644 index 00000000..999086fc --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.getWeightsArray.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.getWeightsArray diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.hasCoordType.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.hasCoordType.rst new file mode 100644 index 00000000..c13fd7e9 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.hasCoordType diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.info.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.info.rst new file mode 100644 index 00000000..cc2d36e4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.info diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.isClose.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.isClose.rst new file mode 100644 index 00000000..21d97b8d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.isClose diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.listall.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.listall.rst new file mode 100644 index 00000000..76c30307 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.listall.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.listall diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchPattern.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchPattern.rst new file mode 100644 index 00000000..1002947b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.matchPattern diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchone.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchone.rst new file mode 100644 index 00000000..83fb30df --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.matchone diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.reconcile.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.reconcile.rst new file mode 100644 index 00000000..79b908d5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.reconcile diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.rst new file mode 100644 index 00000000..7f8f3e38 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.__init__ diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPattern.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPattern.rst new file mode 100644 index 00000000..8104c2bd --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.searchPattern diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPredicate.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPredicate.rst new file mode 100644 index 00000000..3e03b7ec --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.searchPredicate diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchone.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchone.rst new file mode 100644 index 00000000..f42288f0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.searchone diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.setMask.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.setMask.rst new file mode 100644 index 00000000..b85e2c29 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.setMask diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.size.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.size.rst new file mode 100644 index 00000000..124b3c2e --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.size diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subGridRegion.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subGridRegion.rst new file mode 100644 index 00000000..f7afc6d7 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.subGridRegion diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subSlice.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subSlice.rst new file mode 100644 index 00000000..f09b7943 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.subSlice diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeScrip.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeScrip.rst new file mode 100644 index 00000000..c25e4ecb --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.writeScrip diff --git a/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeToFile.rst b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeToFile.rst new file mode 100644 index 00000000..5935aea2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.AbstractHorizontalGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:AbstractHorizontalGrid +================================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: AbstractHorizontalGrid.writeToFile diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.__init__.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.__init__.rst new file mode 100644 index 00000000..ea43049a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.__init__.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .__init__ diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid._getShape.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid._getShape.rst new file mode 100644 index 00000000..c98613ae --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid._getShape.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: ._getShape diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkAxes.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkAxes.rst new file mode 100644 index 00000000..55ae075d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .checkAxes diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkConvex.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkConvex.rst new file mode 100644 index 00000000..02ad1456 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.checkConvex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .checkConvex diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.clone.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.clone.rst new file mode 100644 index 00000000..92f4d9f0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .clone diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.dump.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.dump.rst new file mode 100644 index 00000000..3bb733f5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .dump diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.fixCutCells.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.fixCutCells.rst new file mode 100644 index 00000000..6999a3a2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.fixCutCells.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .fixCutCells diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.flatAxes.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.flatAxes.rst new file mode 100644 index 00000000..2aa682b6 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .flatAxes diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.genBounds.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.genBounds.rst new file mode 100644 index 00000000..aeac56f7 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .genBounds diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getAxis.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getAxis.rst new file mode 100644 index 00000000..024b5658 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getAxis diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getBounds.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getBounds.rst new file mode 100644 index 00000000..72a78166 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getBounds diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getGridSlices.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getGridSlices.rst new file mode 100644 index 00000000..36b13e0a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getGridSlices.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getGridSlices diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getIndex.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getIndex.rst new file mode 100644 index 00000000..1723de2d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getIndex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getIndex diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLatitude.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLatitude.rst new file mode 100644 index 00000000..30a6f497 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getLatitude diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLongitude.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLongitude.rst new file mode 100644 index 00000000..338c0206 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getLongitude diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMask.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMask.rst new file mode 100644 index 00000000..8270623c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getMask diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMesh.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMesh.rst new file mode 100644 index 00000000..4d159ba5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getMesh diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getWeightsArray.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getWeightsArray.rst new file mode 100644 index 00000000..8e35b31a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.getWeightsArray.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .getWeightsArray diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.hasCoordType.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.hasCoordType.rst new file mode 100644 index 00000000..1c24ddd5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .hasCoordType diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.info.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.info.rst new file mode 100644 index 00000000..218b04c3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .info diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec.rst new file mode 100644 index 00000000..0d3a02a8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .init_from_gridspec diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec_file.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec_file.rst new file mode 100644 index 00000000..6422feb4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.init_from_gridspec_file.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .init_from_gridspec_file diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.intersect.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.intersect.rst new file mode 100644 index 00000000..a32ba048 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.intersect.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .intersect diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.isClose.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.isClose.rst new file mode 100644 index 00000000..d74f3913 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .isClose diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.listall.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.listall.rst new file mode 100644 index 00000000..c7e077ed --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.listall.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .listall diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchPattern.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchPattern.rst new file mode 100644 index 00000000..a6c9d43a --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .matchPattern diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchone.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchone.rst new file mode 100644 index 00000000..89d6f62f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .matchone diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.reconcile.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.reconcile.rst new file mode 100644 index 00000000..b66360ef --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .reconcile diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPattern.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPattern.rst new file mode 100644 index 00000000..b9d60280 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .searchPattern diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPredicate.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPredicate.rst new file mode 100644 index 00000000..4f407aca --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .searchPredicate diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchone.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchone.rst new file mode 100644 index 00000000..aad87ec5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .searchone diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.setMask.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.setMask.rst new file mode 100644 index 00000000..5cda90d2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .setMask diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.size.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.size.rst new file mode 100644 index 00000000..b7873d6d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .size diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subGridRegion.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subGridRegion.rst new file mode 100644 index 00000000..b1ba3c6b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .subGridRegion diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subSlice.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subSlice.rst new file mode 100644 index 00000000..dc8333f8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .subSlice diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toCurveGrid.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toCurveGrid.rst new file mode 100644 index 00000000..93c12b35 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .toCurveGrid diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toGenericGrid.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toGenericGrid.rst new file mode 100644 index 00000000..6a172d1d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .toGenericGrid diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeScrip.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeScrip.rst new file mode 100644 index 00000000..434eb55d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .writeScrip diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeToFile.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeToFile.rst new file mode 100644 index 00000000..5e0b1d8c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .writeToFile diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.write_gridspec.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.write_gridspec.rst new file mode 100644 index 00000000..63081a3e --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.write_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .write_gridspec diff --git a/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeg.rst b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeg.rst new file mode 100644 index 00000000..09555c4d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.DatasetCurveGrid.writeg.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.DatasetCurveGrid +============================ + +.. currentmodule:: cdms2.hgrid.DatasetCurveGrid + +.. automethod:: .writeg diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.__init__.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.__init__.rst new file mode 100644 index 00000000..bb93716f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.__init__.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .__init__ diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid._getShape.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid._getShape.rst new file mode 100644 index 00000000..84cf7fba --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid._getShape.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: ._getShape diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkAxes.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkAxes.rst new file mode 100644 index 00000000..867e9679 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .checkAxes diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkConvex.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkConvex.rst new file mode 100644 index 00000000..617972ed --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.checkConvex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .checkConvex diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.clone.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.clone.rst new file mode 100644 index 00000000..131dd32b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .clone diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.dump.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.dump.rst new file mode 100644 index 00000000..7d505d82 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .dump diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.fixCutCells.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.fixCutCells.rst new file mode 100644 index 00000000..60f58339 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.fixCutCells.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .fixCutCells diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.flatAxes.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.flatAxes.rst new file mode 100644 index 00000000..96b9095f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .flatAxes diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.genBounds.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.genBounds.rst new file mode 100644 index 00000000..4f93b614 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .genBounds diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getAxis.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getAxis.rst new file mode 100644 index 00000000..a481f07b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getAxis diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getBounds.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getBounds.rst new file mode 100644 index 00000000..feace39c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getBounds diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getGridSlices.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getGridSlices.rst new file mode 100644 index 00000000..db6beb94 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getGridSlices.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getGridSlices diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getIndex.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getIndex.rst new file mode 100644 index 00000000..7d0eef9f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getIndex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getIndex diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLatitude.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLatitude.rst new file mode 100644 index 00000000..61dec2fc --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getLatitude diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLongitude.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLongitude.rst new file mode 100644 index 00000000..2ebfc75c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getLongitude diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMask.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMask.rst new file mode 100644 index 00000000..115d5514 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getMask diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMesh.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMesh.rst new file mode 100644 index 00000000..391209d8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getMesh diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.getWeightsArray.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getWeightsArray.rst new file mode 100644 index 00000000..ab2f2bf5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.getWeightsArray.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .getWeightsArray diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.hasCoordType.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.hasCoordType.rst new file mode 100644 index 00000000..0e4f3a0f --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .hasCoordType diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.info.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.info.rst new file mode 100644 index 00000000..d40a7210 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .info diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec.rst new file mode 100644 index 00000000..a004306e --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .init_from_gridspec diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec_file.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec_file.rst new file mode 100644 index 00000000..d73dfc1d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.init_from_gridspec_file.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .init_from_gridspec_file diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.intersect.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.intersect.rst new file mode 100644 index 00000000..d198ddc8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.intersect.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .intersect diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.isClose.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.isClose.rst new file mode 100644 index 00000000..35d114e4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .isClose diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.listall.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.listall.rst new file mode 100644 index 00000000..98f9a07d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.listall.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .listall diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchPattern.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchPattern.rst new file mode 100644 index 00000000..ef6d00c3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .matchPattern diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchone.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchone.rst new file mode 100644 index 00000000..749eaa39 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .matchone diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.reconcile.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.reconcile.rst new file mode 100644 index 00000000..656c4aa8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .reconcile diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPattern.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPattern.rst new file mode 100644 index 00000000..0fd99e2c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .searchPattern diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPredicate.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPredicate.rst new file mode 100644 index 00000000..a94eaa0b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .searchPredicate diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchone.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchone.rst new file mode 100644 index 00000000..1d20418c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .searchone diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.setMask.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.setMask.rst new file mode 100644 index 00000000..19003302 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .setMask diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.size.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.size.rst new file mode 100644 index 00000000..59079be0 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .size diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.subGridRegion.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.subGridRegion.rst new file mode 100644 index 00000000..16e3f591 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .subGridRegion diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.subSlice.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.subSlice.rst new file mode 100644 index 00000000..490bc23e --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .subSlice diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.toCurveGrid.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.toCurveGrid.rst new file mode 100644 index 00000000..e4efbbd6 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .toCurveGrid diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.toGenericGrid.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.toGenericGrid.rst new file mode 100644 index 00000000..1f4f6bdf --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .toGenericGrid diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeScrip.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeScrip.rst new file mode 100644 index 00000000..effafa81 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .writeScrip diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeToFile.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeToFile.rst new file mode 100644 index 00000000..9efdfe43 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .writeToFile diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.write_gridspec.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.write_gridspec.rst new file mode 100644 index 00000000..f99a8133 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.write_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .write_gridspec diff --git a/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeg.rst b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeg.rst new file mode 100644 index 00000000..310f006e --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.FileCurveGrid.writeg.rst @@ -0,0 +1,6 @@ +cdms2.hgrid.FileCurveGrid +========================= + +.. currentmodule:: cdms2.hgrid.FileCurveGrid + +.. automethod:: .writeg diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.__init__.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.__init__.rst new file mode 100644 index 00000000..e6fdd176 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.__init__.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.__init__ diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid._getShape.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid._getShape.rst new file mode 100644 index 00000000..76064cbf --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid._getShape.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid._getShape diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkAxes.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkAxes.rst new file mode 100644 index 00000000..acc358d7 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.checkAxes diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkConvex.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkConvex.rst new file mode 100644 index 00000000..3e71db26 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.checkConvex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.checkConvex diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.clone.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.clone.rst new file mode 100644 index 00000000..c651305d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.clone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.clone diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.dump.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.dump.rst new file mode 100644 index 00000000..59e24cd3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.dump.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.dump diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.fixCutCells.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.fixCutCells.rst new file mode 100644 index 00000000..0fb1b62b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.fixCutCells.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.fixCutCells diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.flatAxes.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.flatAxes.rst new file mode 100644 index 00000000..13ec772b --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.flatAxes.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.flatAxes diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.genBounds.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.genBounds.rst new file mode 100644 index 00000000..cb549314 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.genBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.genBounds diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getAxis.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getAxis.rst new file mode 100644 index 00000000..b6e44b01 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getAxis.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getAxis diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getBounds.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getBounds.rst new file mode 100644 index 00000000..873f37d2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getBounds diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getGridSlices.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getGridSlices.rst new file mode 100644 index 00000000..2fa14b18 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getGridSlices.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getGridSlices diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getIndex.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getIndex.rst new file mode 100644 index 00000000..0e7337fc --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getIndex.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getIndex diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLatitude.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLatitude.rst new file mode 100644 index 00000000..18211899 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLatitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getLatitude diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLongitude.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLongitude.rst new file mode 100644 index 00000000..64e08cf4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getLongitude.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getLongitude diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMask.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMask.rst new file mode 100644 index 00000000..34e8de00 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getMask diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMesh.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMesh.rst new file mode 100644 index 00000000..d62666b8 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getMesh.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getMesh diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getWeightsArray.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getWeightsArray.rst new file mode 100644 index 00000000..6481f1c4 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.getWeightsArray.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.getWeightsArray diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.hasCoordType.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.hasCoordType.rst new file mode 100644 index 00000000..c303d049 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.hasCoordType.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.hasCoordType diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.info.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.info.rst new file mode 100644 index 00000000..004f531d --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.info.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.info diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec.rst new file mode 100644 index 00000000..9ef3d1c7 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.init_from_gridspec diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec_file.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec_file.rst new file mode 100644 index 00000000..85f1a794 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.init_from_gridspec_file.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.init_from_gridspec_file diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.intersect.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.intersect.rst new file mode 100644 index 00000000..e5474437 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.intersect.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.intersect diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.isClose.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.isClose.rst new file mode 100644 index 00000000..675555f3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.isClose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.isClose diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.listall.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.listall.rst new file mode 100644 index 00000000..c9f37964 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.listall.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.listall diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchPattern.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchPattern.rst new file mode 100644 index 00000000..95a320bb --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.matchPattern diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchone.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchone.rst new file mode 100644 index 00000000..30086beb --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.matchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.matchone diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.reconcile.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.reconcile.rst new file mode 100644 index 00000000..bcaa2f67 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.reconcile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.reconcile diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPattern.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPattern.rst new file mode 100644 index 00000000..df1c762c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPattern.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.searchPattern diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPredicate.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPredicate.rst new file mode 100644 index 00000000..73dd5f09 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchPredicate.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.searchPredicate diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchone.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchone.rst new file mode 100644 index 00000000..87b2198c --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.searchone.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.searchone diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.setMask.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.setMask.rst new file mode 100644 index 00000000..d14786d3 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.setMask.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.setMask diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.size.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.size.rst new file mode 100644 index 00000000..eb7565dc --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.size.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.size diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subGridRegion.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subGridRegion.rst new file mode 100644 index 00000000..765acea2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subGridRegion.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.subGridRegion diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subSlice.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subSlice.rst new file mode 100644 index 00000000..d8f7faf5 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.subSlice.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.subSlice diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toCurveGrid.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toCurveGrid.rst new file mode 100644 index 00000000..8ee90582 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.toCurveGrid diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toGenericGrid.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toGenericGrid.rst new file mode 100644 index 00000000..93cdedee --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.toGenericGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.toGenericGrid diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeScrip.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeScrip.rst new file mode 100644 index 00000000..3009cfab --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeScrip.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.writeScrip diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeToFile.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeToFile.rst new file mode 100644 index 00000000..015d77d2 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeToFile.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.writeToFile diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.write_gridspec.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.write_gridspec.rst new file mode 100644 index 00000000..9efef985 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.write_gridspec.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.write_gridspec diff --git a/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeg.rst b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeg.rst new file mode 100644 index 00000000..8b28b6df --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.TransientCurveGrid.writeg.rst @@ -0,0 +1,6 @@ +cdms2.hgrid:TransientCurveGrid +============================== + +.. currentmodule:: cdms2.hgrid + +.. automethod:: TransientCurveGrid.writeg diff --git a/docs/source/generated/cdms2.hgrid._flatten.rst b/docs/source/generated/cdms2.hgrid._flatten.rst new file mode 100644 index 00000000..94271124 --- /dev/null +++ b/docs/source/generated/cdms2.hgrid._flatten.rst @@ -0,0 +1,6 @@ +cdms2.hgrid +=========== + +.. currentmodule:: cdms2.hgrid + +.. autofunction:: _flatten diff --git a/docs/source/generated/cdms2.hgrid.allclose.rst b/docs/source/generated/cdms2.hgrid.allclose.rst new file mode 100644 index 00000000..be791bbb --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.allclose.rst @@ -0,0 +1,6 @@ +cdms2.hgrid +=========== + +.. currentmodule:: cdms2.hgrid + +.. autofunction:: allclose diff --git a/docs/source/generated/cdms2.hgrid.getAutoBounds.rst b/docs/source/generated/cdms2.hgrid.getAutoBounds.rst new file mode 100644 index 00000000..b46326ac --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.getAutoBounds.rst @@ -0,0 +1,6 @@ +cdms2.hgrid +=========== + +.. currentmodule:: cdms2.hgrid + +.. autofunction:: getAutoBounds diff --git a/docs/source/generated/cdms2.hgrid.readScripCurveGrid.rst b/docs/source/generated/cdms2.hgrid.readScripCurveGrid.rst new file mode 100644 index 00000000..5d9b3ccd --- /dev/null +++ b/docs/source/generated/cdms2.hgrid.readScripCurveGrid.rst @@ -0,0 +1,6 @@ +cdms2.hgrid +=========== + +.. currentmodule:: cdms2.hgrid + +.. autofunction:: readScripCurveGrid From 58cadd7d0a501ab08938deb38511074139498637 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 22 Aug 2018 15:40:23 -0700 Subject: [PATCH 219/239] Changes made to API --- Lib/avariable.py | 19 +-- Lib/dataset.py | 1 + docs/source/conf.py | 1 + regrid2/Lib/crossSection.py | 222 ++++++++++++++++++++------------- regrid2/Lib/esmf.py | 69 +++++----- regrid2/Lib/horizontal.py | 26 ++-- regrid2/Lib/mvGenericRegrid.py | 15 ++- 7 files changed, 207 insertions(+), 146 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 99c33b74..04592309 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -36,17 +36,22 @@ def getMinHorizontalMask(var): """ - Get the minimum mask associated with 'x' and 'y' (i.e. with the - min number of ones) across all axes + Get the minimum mask associated with 'x' and 'y' (i.e. with the min number of ones) across all axes - Parameters - ---------- - var - CDMS variable with a mask +Parameters +---------- + + var + CDMS variable with a mask + + N/A: + None Return ------ - mask array or None if order 'x' and 'y' were not found + + mask array or None if order 'x' and 'y' were not found + """ from distarray import MultiArrayIter diff --git a/Lib/dataset.py b/Lib/dataset.py index 443fb623..02112a25 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -438,6 +438,7 @@ def createDataset(path, template=None): ---------- path: is the XML file name, or netCDF filename for simple file creation. + template: is a string template for the datafile(s), for dataset creation. diff --git a/docs/source/conf.py b/docs/source/conf.py index 46791e74..a3ef5e92 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -65,6 +65,7 @@ 'sphinx.ext.autosummary', 'sphinx.ext.graphviz', 'sphinx.ext.doctest', + 'sphinx.ext.viewcode', "numpydoc" # 'sphinx.ext.napoleon' ] diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index ec0b9135..f532f6bb 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -9,18 +9,18 @@ class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" + """ + + PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + latitude-level plane for all times + + PROCEDURE: Step One: + Make an instance of class CrossSectionRegridder passing it input and output grid information + Step Two: + Pass the input data with some descriptive parameters and get the output data + in return + + """ def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, latTypeOut=None, latSizeOut=None): @@ -555,8 +555,9 @@ def checkdimension(x, name): Parameters ---------- - x - coordinate vector - name - coordinate vector ID + x - coordinate vector + + name - coordinate vector ID Returns ------- @@ -614,31 +615,35 @@ def generic_wts_bnds(lat): def get_latitude_wts_bnds(checklatpass): """ - routine: get_latitude_wts_bnds + Routine: + + get_latitude_wts_bnds - purpose: compare the passed checklatpass with the correct geophysical - ones calculated here. After finding a match call the function - to get the bounds. + Purpose: + + Compare the passed checklatpass with the correct geophysical ones calculated here. After finding a match call the function to get the bounds. - usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + Usage: + + wts,bnds = get_latitude_wts_bnds(checklatpass) where - Parameters - ---------- - - checklatpass + Parameters + ---------- + + checklatpass: - is the grid to check + is the grid to check - None- + N/A: - N/A + None - Return - ------ + Returns + ------- - wts, bnds - tuple with weights and bounds + wts, bnds - tuple with weights and bounds """ small = 0.001 # use as tolerance in checking values @@ -719,15 +724,19 @@ def get_latitude_wts_bnds(checklatpass): def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" + """ + + Purpose: + + set up the shape and bounds for use by maparea + + Usage: + + Returns: + + tuple ( bn,bs ) + + """ latbnds = lat_bnds.astype(numpy.float32) @@ -742,20 +751,28 @@ def latitude_bounds(lat_bnds): def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" + """ + + Routine: + + get_region_latitude_wts_bnds + + Purpose: + + compare the passed latitudes, latRegion, with the global + ones calculated here and extract the wts and bounds for + the region + + Usage: + + wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + where latRegion is the regional grid to check + + Returns : + + wts, bnds - tuple with weights and bounds + + """ latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] @@ -827,15 +844,21 @@ def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" + """ + + Purpose: + + construct the mask for the input data for use by rgdlength + + Usage: + + amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + + Returns: + + amskin + + """ # Logic outline # START NO USER MASK SECTION ? # @@ -1001,16 +1024,23 @@ def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" + """ + + Purpose: + + send the same message to the screen + + Passed : + + msg - the string + + value - the number associated with the string + + Returns: + + return + + """ print('*******************************************************************') if value1 is None: @@ -1025,15 +1055,21 @@ def sendmsg(msg, value1=None, value2=None): def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" + """ + + Purpose: + + make the crossi section analytical test case + + Passed : + + the grid coordinate vectors + + Returns: + + xsection -- a temerature like cross section + + """ nlev = len(levvals) @@ -1055,15 +1091,23 @@ def section(latvals, levvals): def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" + """ + + Purpose: + + compute the rms error for two data sets having the same shape + + + Passed: + + the two data sets + + + Returns: + + rms error + + """ if data1.shape != data2.shape: print('Error in shape in rmserror') diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 756ecbe7..ffb624d8 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -78,19 +78,23 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """Set Cell connectivity -Parameters ----------- - cellIndices: - 0-based) - cellTypes: - one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - connectivityNode: - connectivity array, see below for node ordering - cellMask: - cellAreas area (volume) of each cell - - Note - ---- + Parameters + ---------- + + cellIndices: + 0-based) + + cellTypes: + one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + + connectivityNode: + connectivity array, see below for node ordering + + cellMask: + cellAreas area (volume) of each cell + + Note + ---- :: @@ -328,22 +332,21 @@ def getCoordShape(self, staggerloc): def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): """ Populate the grid with staggered coordinates (e.g. corner or center). - - + Parameters ---------- - - coords + + coords The curvilinear coordinates of the grid. List of numpy arrays. Must exist on all procs. - staggerloc + staggerloc The stagger location ESMF.StaggerLoc.CENTER (default) ESMF.StaggerLoc.CORNER - globalIndexing - if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None + globalIndexing + if True array was allocated over global index space, otherwise array was allocated + over local index space on this processor. This is only relevant if rootPe is None - Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, - hence the dimensions are reversed here. + Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. """ # allocate space for coordinates, can only add coordinates once for i in range(self.ndims): @@ -377,11 +380,11 @@ def setCellAreas(self, areas): Set the cell areas Parameters - --------- + ---------- - areas numpy array + areas numpy array - _: None + _: None """ self.grid.add_item(item=ESMF.GridItem.Area) @@ -414,7 +417,10 @@ def getMask(self, staggerloc=CENTER): Returns ------- - mask numpy array. 1 is invalid by default. This array exists on all procs + mask numpy array + 1 is invalid by default + + Note: This array exists on all procs """ try: maskPtr = self.grid.get_item( @@ -427,13 +433,16 @@ def setMask(self, mask, staggerloc=CENTER): """ Set mask array. In ESMF, the mask is applied to cells. - Parameters + Returns ---------- - mask numpy array. - 1 is invalid by default. This array exists on all procs + mask numpy array + 1 is invalid by default - _: None + + Note: This array exists on all procs + + """ self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) maskPtr = self.grid.get_item( diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index 910ad9bf..5ddbef62 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -376,18 +376,20 @@ def __init__(self, ingrid, outgrid): def input_mask(ain, type, mask, missing=None): - """ #------------------------------------------------------------------- - # - # purpose: set up the input mask including missing from ain - # - # usage: - # - # passed : - # - # returned: - # - # - #------------------------------------------------------------------------""" + """ + + Purpose: + + set up the input mask including missing from ain + + Usage: + + Passed : + + Returns: + + + """ if type != 'h' and type != 'v': raise ValueError('Mask type must be h or v') return diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 22c36127..9b39480f 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -25,11 +25,10 @@ def guessPeriodicity(srcBounds): Parameters ---------- + srcBounds + the nodal src set of coordinates - srcBounds - the nodal src set of coordinates - - _: None + _: None Returns @@ -60,8 +59,8 @@ class GenericRegrid: Constructor -Parameters ----------- + Parameters + ---------- srcGrid list of numpy arrays, source horizontal coordinates @@ -203,8 +202,8 @@ def apply(self, srcData, dstData, """ Regrid source to destination -Parameters ----------- + Parameters + ---------- srcData array (input) From 86caf8616d24750d20c045a470edc174025bf143 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 23 Aug 2018 15:47:29 -0700 Subject: [PATCH 220/239] Changes made to API --- regrid2/Lib/esmf.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index ffb624d8..b7ee85c1 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -78,8 +78,8 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """Set Cell connectivity - Parameters - ---------- + Parameters: + cellIndices: 0-based) @@ -93,8 +93,9 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask: cellAreas area (volume) of each cell - Note - ---- + + Note: + :: @@ -143,14 +144,14 @@ def setNodes(self, indices, coords, peOwners=None): Parameters ---------- - indices - Ids of the nodes (0-based) + indices - + Ids of the nodes (0-based) - coords - nodal coordinates + coords - + nodal coordinates - peOwners - processor ranks where the coordinates reside (0-based) + peOwners + processor ranks where the coordinates reside (0-based) """ n = len(indices) if not self.nodesAdded: From 4def39381a045ab98d09f8995fd81fc04f08af5f Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 28 Aug 2018 14:50:09 -0700 Subject: [PATCH 221/239] fix avariable bad location methods --- docs/source/avariable.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index 2ddbd830..52b57448 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -70,16 +70,10 @@ avariable AbstractVariable.subRegion AbstractVariable.subSlice AbstractVariable.typecode - axisMatchAxis - axisMatches - axisMatchIndex getBoundList getMinHorizontalMask getNumericCompatibility - guessPeriodicity order2index orderparse setNumericCompatibility - splitSliceExt - splitSlice From f3c72fff444eb8002cbf1f3fb0c62b00150364d3 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 29 Aug 2018 14:55:11 -0700 Subject: [PATCH 222/239] Changes to Appendix and API --- Lib/avariable.py | 74 +++++++++++++++------------- docs/source/manual/cdms_appendix.rst | 74 ++++++++++++++++++---------- regrid2/Lib/esmf.py | 2 +- 3 files changed, 87 insertions(+), 63 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 04592309..1c523585 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -36,21 +36,23 @@ def getMinHorizontalMask(var): """ - Get the minimum mask associated with 'x' and 'y' (i.e. with the min number of ones) across all axes + Get the minimum mask associated with 'x' and 'y' + (i.e. with the min number of ones) across all axes -Parameters ----------- - - var - CDMS variable with a mask + Parameters + ---------- - N/A: - None + var : + CDMS variable with a mask - Return - ------ + N/A : + None - mask array or None if order 'x' and 'y' were not found + Returns + ------- + + mask array or None : + if order 'x' and 'y' were not found """ from distarray import MultiArrayIter @@ -177,14 +179,14 @@ def __call__(self, *args, **kwargs): Parameters ---------- - raw: - if set to 1, return numpy.ma only - squeeze: - if set to 1, eliminate any dimension of length 1 - grid: - if given, result is regridded ont this grid. - order: - if given, result is permuted into this order + raw: + if set to 1, return numpy.ma only + squeeze: + if set to 1, eliminate any dimension of length 1 + grid: + if given, result is regridded ont this grid. + order: + if given, result is permuted into this order Returns ------- @@ -1846,14 +1848,15 @@ def astype(self, tc): def orderparse(order): """Parse an order string. Returns a list of axes specifiers. - Note - ---- - Order elements can be: - * Letters t, x, y, z meaning time, longitude, latitude, level - * Numbers 0-9 representing position in axes - * The letter - meaning insert the next available axis here. - * The ellipsis ... meaning fill these positions with any remaining axes. - * (name) meaning an axis whose id is name + + Note: + + Order elements can be: + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * The letter - meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name """ if not isinstance(order, string_types): raise CDMSError('order arguments must be strings.') @@ -1884,14 +1887,15 @@ def orderparse(order): def order2index(axes, order): """Find the index permutation of axes to match order. The argument order is a string. - Note - ---- - Order elements can be: - * Letters t, x, y, z meaning time, longitude, latitude, level. - * Numbers 0-9 representing position in axes - * The letter - meaning insert the next available axis here. - * The ellipsis ... meaning fill these positions with any remaining axes. - * (name) meaning an axis whose id is name. + + Note: + + Order elements can be: + * Letters t, x, y, z meaning time, longitude, latitude, level. + * Numbers 0-9 representing position in axes + * The letter - meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name. """ if isinstance(order, string_types): result = orderparse(order) diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 861efb7c..fd79b770 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -240,7 +240,9 @@ Table Slab Methods :widths: 20,50,80 :align: left - "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. ``dim`` is the dimension number, an integer in the range 0..rank- 1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. + * ``dim`` is the dimension number, an integer in the range 0..rank- 1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." @@ -262,34 +264,52 @@ Table cuDataset Methods :align: left "None", "``cleardefault()``", "Clear the default variable name." - "None", "``default_variable(vname``)", "Set the default variable name." - ,,"vname is the string variable name." - "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname." - ,,"dname is the string axis name." - ,,"vname is the string variable name. The default is the variable name set by default_variable." - "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. vname is a string variable name. The default is the variable name set by default_variable." - "Various", "``getattribute (vname, attribute``)", "Get an attribute value. vname is a string variable name. attribute is the string attribute name." - "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension." - ,,"dname is the string name of an axis." - ,,"vname is a string variable name. The default is the variable name set by default_variable." - "Various", "``getglobal (attribute)``", "Get the value of the global attribute. attribute is the string attribute name." - "Variable", "``getslab (vname, \*args)``", "Read data for a variable." - ,, "vname is the string name of the variable." - ,, "args is an argument list corresponding to the dimensions of the variable. Arguments for each dimension can be:" - ,, "- ':' or None -- select the entire dimension" - ,, "- Ellipsis -- select entire dimensions between the ones given." - ,, "- a pair of successive arguments giving an interval in world coordinates." - ,, "- a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" - "List", "``listall (vname=None, all=None)``", "Get info about data from the file." - ,, "vname is the string name of the variable." - ,, "If all is non-zero, dimension values, weights, and bounds are returned as well" - "List", "``listattribute (vname=None )``", "Return a list of attribute names. vname is the name of the variable. The default is the variable name set by default_variable." - "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. vname is the name of the variable. The default is the variable name set by default_variable." + "None", "``default_variable(vname``)", "Set the default variable name. + * ``vname`` is the string variable name." + "Array", "``dimensionarray(dname, vname=None``)", "Values of the axis named dname. + * ``dname1`` is the string axis name. + * ``vname`` is the string variable name. + **Note**: The default is the variable name set by default_variable." + "Axis", "``dimensionobject(dname, vname=None)``", "Get an axis. dname is the string name of an axis. + * ``vname`` is a string variable name. + **Note:** The default is the variable name set by default_variable." + "Various", "``getattribute (vname, attribute``)", "Get an attribute value. + * ``vname`` is a string variable name. + * ``attribute`` is the string attribute name." + "String", "``getdimensionunits (dname,vname=None``)", "Get the units for the given dimension. + * ``dname`` is the string name of an axis. + * ``vname`` is a string variable name. + **Note:** The default is the variable name set by default_variable." + "Various", "``getglobal (attribute)``", "Get the value of the global attribute. + * ``attribute`` is the string attribute name." + "Variable", "``getslab (vname, \*args)``", "Read data for a variable. + * ``vname`` is the string name of the variable. + * ``args`` is an argument list corresponding to the dimensions of the variable. + Arguments for each dimension can be: + * ':' or None -- select the entire dimension + * Ellipsis -- select entire dimensions between the ones given. + * a pair of successive arguments giving an interval in world coordinates. + * a CDMS-style tuple of world coordinates e.g. (start, stop, 'cc')" + "List", "``listall (vname=None, all=None)``", "Get info about data from the file. + * ``vname`` is the string name of the variable. + **Note:** If all is non-zero, dimension values, weights, and bounds are returned as well" + "List", "``listattribute (vname=None )``", "Return a list of attribute names. + * ``vname`` is the name of the variable. + **Note:** The default is the variable name set by default_variable." + "List", "``listdimension (vname=None)``", "Return a list of the dimension names associated with a variable. + * ``vname`` is the name of the variable. + **Note:** The default is the variable name set by default_variable." "List", "``listglobal ()``", "Return a list of the global attribute names." "List", "``listvariable ()``", "Return a list of the variables in the file." - "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. vname is the string name of the variable. If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." - "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. vname is the string name of the variable. Output is sent to device." - "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. vname is the string name of the variable. Output is sent to device." + "None", "``showall (vname=None, all=None, device=sys.stdout)``", "Print a description of the variable. + * ``vname`` is the string name of the variable. + **Note:** If all is non-zero, dimension values, weights, and bounds are returned as well. Output is sent to device." + "None", "``showattribute (vname=None, device=sys.stdout)``", "Print the attributes of a variable. + * ``vname`` is the string name of the variable. + **Note:** Output is sent to device." + "None", "``showdimension (vname=None, device=sys.stdout)``", "Print the dimension names associated with a variable. + * ``vname`` is the string name of the variable. + **Note:** Output is sent to device." "None", "``showglobal (device=sys.stdout)``", "Print the global file attributes. Output is sent to device." "None", "``showvariable (device=sys.stdout)``", "Print the list of variables in the file." diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index b7ee85c1..0cbe6307 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -142,7 +142,7 @@ def setNodes(self, indices, coords, peOwners=None): Set the nodal coordinates Parameters - ---------- + ---------- indices - Ids of the nodes (0-based) From 7ee9c2ed9869a3ffa49e20c549a9732d4e82ed05 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 30 Aug 2018 15:36:16 -0700 Subject: [PATCH 223/239] Changes to Chapter 1 and 2 --- docs/source/manual/cdms_2.rst | 164 ++++++++++++++++----------- docs/source/manual/cdms_appendix.rst | 23 ++-- 2 files changed, 111 insertions(+), 76 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index d9295d34..2c12a074 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -143,76 +143,102 @@ Table Cdms Module Functions :align: left - "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. ``s`` is a masked array, Numpy array, or Variable. If ``s`` is already a transient variable, ``s`` is returned. See also: ``isVariable``." - "``Axis``", "``createAxis(data, bounds=None)``:" - , "Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset." - , " * ``data`` is a one-dimensional, monotonic Numpy array. ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default)." - , " * See ``setAutoBounds``." - , " * Also see: ``CdmsFile.createAxis``" - "``Axis``", "``createEqualAreaAxis(nlat)``:" - , "Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. ``nlat`` is the axis length. The axis is not associated with a file or dataset." - "``Axis``", "``createGaussianAxis(nlat)``:" - , "Create a Gaussian latitude axis. Axis values range from north to south. ``nlat`` is the axis length. The axis is not associated with a file or dataset." - "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:" - , "Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. ``nlats`` is the number of latitudes. ``xorigin`` is the origin of the longitude axis. ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" - "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:" - , "Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. ``latArray`` is a NumPy array of latitude values." - , " * ``lonArray`` is a NumPy array of longitude values. " - , " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. " - , " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. " - , " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse." - , " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." - - "``RectGrid``", "``createGlobalMeanGrid(grid)``:" - , "Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. ``grid`` is a RectGrid." - - "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``:" - , "Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation." - , " * ``lat`` is a latitude axis, created by ``cdms.createAxis``." - , " * ``lon`` is a longitude axis, created by ``cdms.createAxis``." - , " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - , " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - - "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:" - , "Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``." - , " * ``deltaLat`` is the increment between latitudes. ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``." - , " * ``deltaLon`` is the increment between longitudes. ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude)." - , " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:" - , "Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis." - , " * ``startLat`` is the starting latitude value." - , " * ``nlat`` is the number of latitudes." - , " * ``deltaLat`` is the increment between latitudes." - "``RectGrid``"," ``createZonalGrid(grid)``: Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. ``grid`` is a RectGrid." - "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``:" - , "Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis." - , " * ``startLon`` is the starting longitude value." - , " * ``nlon`` is the number of longitudes." - , " * ``deltaLon`` is the increment between longitudes." + "``Variable``", "``asVariable(s)``: + Transform ``s`` into a transient variable. + * ``s`` is a masked array, Numpy array, or Variable. + * If ``s`` is already a transient variable, ``s`` is returned. + * See also: ``isVariable``." + "``Axis``", "``createAxis(data, bounds=None)``: + Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. + * ``data`` is a one-dimensional, monotonic Numpy array. + * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i`` + * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. + **Note:** If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * See ``setAutoBounds``. + * Also see: ``CdmsFile.createAxis``" + "``Axis``", "``createEqualAreaAxis(nlat)``: + Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." + "``Axis``", "``createGaussianAxis(nlat)``: + Create a Gaussian latitude axis. Axis values range from north to south. + * ``nlat`` is the axis length. + **Note:** The axis is not associated with a file or dataset." + "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: + Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + * ``nlats`` is the number of latitudes. + * ``xorigin`` is the origin of the longitude axis. + * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" + "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``: + Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + * ``latArray`` is a NumPy array of latitude values. + * ``lonArray`` is a NumPy array of longitude values. + * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. + * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. + * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. + * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." + "``RectGrid``", "``createGlobalMeanGrid(grid)``: + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + * ``grid`` is a RectGrid." + "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: + Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + * ``lat`` is a latitude axis, created by ``cdms.createAxis``. + * ``lon`` is a longitude axis, created by ``cdms.createAxis``. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: + Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. + * If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. + * ``deltaLat`` is the increment between latitudes. + * ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes. + * If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``. + * ``deltaLon`` is the increment between longitudes. + * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: + Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + * ``startLat`` is the starting latitude value. + * ``nlat`` is the number of latitudes. + * ``deltaLat`` is the increment between latitudes." + "``RectGrid``"," ``createZonalGrid(grid)``: + Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + * ``grid`` is a RectGrid." + "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: + Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + * ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes. + * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2." - , " * See ``setAutoBounds``." - "``Integer``", "``isVariable(s)``: " - , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." - "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." - , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" - , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" - , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" - "``List``", "``order2index (axes, orderstring)``:" - , "Find the index permutation of axes to match order. Return a list of indices. ``axes`` is a list of axis objects. ``orderstring`` is defined as in ``orderparse``." - "``List``", "``orderparse(orderstring)``:" - , "Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:" - - , " * Letters t, x, y, z meaning time, longitude, latitude, level" - , " * Numbers 0-9 representing position in axes" - , " * Dash (-) meaning insert the next available axis here." - , " * The ellipsis ... meaning fill these positions with any remaining axes." - , " * (name) meaning an axis whose id is name" + "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. + * See ``setAutoBounds``." + "``Integer``", "``isVariable(s)``: + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. + * See also: ``asVariable``." + "``Dataset``", "``open(url,mode='r')``: + Open or create a ``Dataset`` or ``CdmsFile``. + * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. + * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. + * If the protocol is 'file' or is omitted, a local file or dataset is opened. + * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + * **Example:** Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + * **Example:** Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + "``List``", "``order2index (axes, orderstring)``: + Find the index permutation of axes to match order. Return a list of indices. + * ``axes`` is a list of axis objects. + * ``orderstring`` is defined as in ``orderparse``." + "``List``", "``orderparse(orderstring)``: + Parse an order string. Returns a list of axes specifiers. + ``orderstring`` consists of: + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * Dash (-) meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``:" , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``:" diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index fd79b770..2b665fbf 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -241,13 +241,22 @@ Table Slab Methods :align: left "Various", "``getdimattribute(dim, field)``", "Get the value of a dimension attribute. - * ``dim`` is the dimension number, an integer in the range 0..rank- 1. - * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "Various", "``getattribute(name)``", "Get the value of an attribute.``name`` is the string name of the attribute. The following special names can always be used: 'filename', 'comments', 'grid_name', 'grid_type', 'time_statistic', 'long_name', 'units'." - "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." - "List", "``listall(all=None)``", "Print slab information. If ``all`` is nonzero, dimension values, weights, and bounds are also printed." - "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. ``dim`` is the dimension number, an integer in the range 0..rank-1. ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." - "None", "``setattribute(name, value)``", "Set an attribute. ``name`` is the string name of the attribute. ``value`` is the value of the attribute." + * ``dim`` is the dimension number, an integer in the range 0..rank- 1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "Various", "``getattribute(name)``", "Get the value of an attribute. + * ``name`` is the string name of the attribute. + The following special names can always be used: + * ``filename``, ``comments``, ``grid_name``, ``grid_type``, ``time_statistic``, ``long_name``, ``units``." + "None", "``info(flag=None, device=sys.stdout)``", "Print slab information. + * If ``flag`` is nonzero, dimension values, weights, and bounds are also printed. Output is sent to ``device``." + "List", "``listall(all=None)``", "Print slab information. + * If ``all`` is nonzero, dimension values, weights, and bounds are also printed." + "List", "``listdimattributes(dim, field)``", "List dimension attributes. Returns a list of string attribute names which can be input to ``getdimattribute``. + * ``dim`` is the dimension number, an integer in the range 0..rank-1. + * ``field`` is a string, one of: 'name', 'values', 'length', 'units', 'weights', 'bounds'." + "None", "``setattribute(name, value)``", "Set an attribute. + * ``name`` is the string name of the attribute. + * ``value`` is the value of the attribute." From eb3890304efdc55f7d128ada0929f307dd738daa Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 4 Sep 2018 15:27:12 -0700 Subject: [PATCH 224/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 175 +++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 66 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 2c12a074..488abd7f 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -239,12 +239,20 @@ Table Cdms Module Functions * Dash (-) meaning insert the next available axis here. * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" - "``None``", "``setAutoBounds(mode)``:" - , "Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. Note: In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." - "``None``", "``setClassifyGrids(mode)``:" - , "Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." - "``None``", "``writeScripGrid(path, grid, gridTitle=None)``:" - , "Write a grid to a SCRIP grid file. ``path`` is a string, the path of the SCRIP file to be created. ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." + "``None``", "``setAutoBounds(mode)``: + Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: + * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. + * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. + **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + "``None``", "``setClassifyGrids(mode)``: + Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. + * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. + * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." + "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: + Write a grid to a SCRIP grid file. + * ``path`` is a string, the path of the SCRIP file to be created. + * ``grid`` is a CDMS grid object. It may be rectangular. ``gridTitle`` is a string ID for the grid." @@ -301,10 +309,14 @@ Table Getting and Setting Attributes :header: "Type", "Definition" :widths: 20, 80 - "various", "``value = obj.attname``" - , "Get an internal or external attribute value. If the attribute is external, it is read from the database. If the attribute is not already in the database, it is created as an external attribute. Internal attributes cannot be created, only referenced." - "various", "``obj.attname = value``" - , "Set an internal or external attribute value. If the attribute is external, it is written to the database." + "various", "``value = obj.attname`` + Get an internal or external attribute value. + * If the attribute is external, it is read from the database. + * If the attribute is not already in the database, it is created as an external attribute. + **Note:** Internal attributes cannot be created, only referenced." + "various", "``obj.attname = value`` + Set an internal or external attribute value. + * If the attribute is external, it is written to the database." @@ -356,17 +368,22 @@ Table Axis Constructors "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" - "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. ``name`` is the string ``name`` of the ``Axis``. ``ar`` is a 1-D data array which defines the ``Axis`` values. It may have the value ``None`` if an unlimited axis is being defined. At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. To define an axis as unlimited, either:" - , "* A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or" - , "* B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited``" - , "``cdms.createEqualAreaAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createGaussianAxis(nlat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)``" - , "* See `A First Example`_." - , "``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)``" - , "* See `A First Example`_ ." + "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. + * ``name`` is the string ``name`` of the ``Axis``. + * ``ar`` is a 1-D data array which defines the ``Axis`` values. + * It may have the value ``None`` if an unlimited axis is being defined. + * At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length. + To define an axis as unlimited, either: + * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or + * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited`` + * ``cdms.createEqualAreaAxis(nlat)`` + * See `A First Example`_. + * ``cdms.createGaussianAxis(nlat)`` + * See `A First Example`_. + * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` + * See `A First Example`_. + * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` + * See `A First Example`_ ." Table CoordinateAxis Methods @@ -378,33 +395,52 @@ Table CoordinateAxis Methods :align: left - "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. Data is returned in the physical ordering defined in the dataset. See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." - "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. Dataset axes are read-only." - "``None``", "``assignValue(array)``", "Set the entire value of the axis. ``array`` is a Numpy array, of the same dimensionality as the axis." - "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. If copyData is 1 (the default) the data itself is copied." - "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. If persistent is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. If ``persistent`` is true, the external file or dataset (if any) is modified. By default, the designation is temporary. ``calendar`` is defined as in ``getCalendar()``." - "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis:" - ,,"* ``Axis``: ``(n,2)``" - ,,"* ``Axis2D``: ``(i,j,4)``" - ,,"* ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell." - ,,"If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." - "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are:" - ,,"* ``cdtime.GregorianCalendar``: the standard Gregorian calendar" - ,,"* ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar" - ,,"* ``cdtime.JulianCalendar``: years divisible by 4 are leap years" - ,,"* ``cdtime.NoLeapCalendar``: a year is 365 days" - ,,"* ``cdtime.Calendar360``: a year is 360 days" - ,,"* ``None``: no calendar can be identified" - ,," **Note** If the axis is not a time axis, the global, file-related calendar is returned." + "``Array``", "``array = axis[i:j]``", "Read a slice of data from the external file or dataset. + * Data is returned in the physical ordering defined in the dataset. + * See `Variable Slice Operators <#table-variable-slice-operators>`_ for a description of slice operators." + "``None``", "``axis[i:j] = array``", "Write a slice of data to the external file. + * Dataset axes are read-only." + "``None``", "``assignValue(array)``", "Set the entire value of the axis. + * ``array`` is a Numpy array, of the same dimensionality as the axis." + "``Axis``", "``clone(copyData=1)``", "Return a copy of the axis, as a transient axis. + * If copyData is 1 (the default) the data itself is copied." + "``None``", "``designateLatitude(persistent=0)``", "Designate the axis to be a latitude axis. + * If persistent is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." + "``None``", "``designateLevel(persistent=0)``", "Designate the axis to be a vertical level axis. + * If persistent is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." + "``None``", "``designateLongitude(persistent=0, modulo=360.0)``", "Designate the axis to be a longitude axis. + * ``modulo`` is the modulus value. + * Any given axis value ``x`` is treated as equivalent to ``x + modulus``. + * If ``persistent`` is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary." + "``None``", "``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``", "Designate the axis to be a time axis. + * If ``persistent`` is true, the external file or dataset (if any) is modified. + * By default, the designation is temporary. + * ``calendar`` is defined as in ``getCalendar()``." + "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: + * ``Axis``: ``(n,2)`` + * ``Axis2D``: ``(i,j,4)`` + * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. + If the boundary array of a latitude or longitude + * ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. + * Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." + "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: + * ``cdtime.GregorianCalendar``: the standard Gregorian calendar + * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar + * ``cdtime.JulianCalendar``: years divisible by 4 are leap years + * ``cdtime.NoLeapCalendar``: a year is 365 days + * ``cdtime.Calendar360``: a year is 360 days + * ``None``: no calendar can be identified + **Note** If the axis is not a time axis, the global, file-related calendar is returned." "``Array``", "``getValue()``", "Get the entire axis vector." "``Integer``", "``isLatitude()``", "Returns true iff the axis is a latitude axis." "``Integer``", "``isLevel()``", "Returns true iff the axis is a level axis." "``Integer``", "``isLongitude()``", "Returns true iff the axis is a longitude axis." "``Integer``", "``isTime()``", "Returns true iff the axis is a time axis." - "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. If multidimensional, the length of the first dimension." + "``Integer``", "``len(axis)``", "The length of the axis if one-dimensional. + * If multidimensional, the length of the first dimension." "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." @@ -419,31 +455,38 @@ Table Axis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." - "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. ``modulo`` is the modulus value. Any given axis value ``x`` is treated as equivalent to ``x + modulus``. If ``persistent`` is ``True``, the external file or dataset (if any) is modified. By default, the designation is temporary." - "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. An axis is defined as circular if:" - ,," * ``axis.topology == 'circular'``, or" - ,," * ``axis.topology`` is undefined, and the axis is a longitude. The default cycle for circular axes is 360.0" + "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. + * ``modulo`` is the modulus value. + * Any given axis value ``x`` is treated as equivalent to ``x + modulus``. + * If ``persistent`` is ``True``, the external file or dataset (if any) is modified. + * By default, the designation is temporary." + "``Integer``", "``isCircular()``", "Returns ``True`` if the axis has circular topology. + An axis is defined as circular if: + * ``axis.topology == 'circular'``, or + * ``axis.topology`` is undefined, and the axis is a longitude. + * The default cycle for circular axes is 360.0" "``Integer``", "``isLinear()``", "Returns ``True`` if the axis has a linear representation." "``Tuple``", "``mapInterval(interval)``", "Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle." - "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None or ':'``" - ,,"* where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:" - ,,"* ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis" - ,,"* ``'n'`` - select node values which are contained in the interval" - ,,"* ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval" - ,,"* ``'e'`` - same as n, but include an extra node on either side" - ,,"* ``'s'`` - select axis elements for which the cell boundary is a subset of the interval" - ,,"* The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected." - ,,"* If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``." - ,,"* An interval of ``None`` or ``':'`` returns the full index interval of the axis." - ,,"* The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty." - ,,"* for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``" - ,,"* if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint." - ,,"* otherwise the interval wraps around the axis endpoint." - ,,"* see also: ``mapinterval``, ``variable.subregion()``" + "``(i,j,k)``", "``mapIntervalExt(interval)``", "Map a coordinate interval to an index + ``interval``. ``interval`` is a tuple having one of the forms: + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None or ':'`` + where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and: + * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axis + * ``'n'`` - select node values which are contained in the interval + * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval + * ``'e'`` - same as n, but include an extra node on either side + * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval + * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * An interval of ``None`` or ``':'`` returns the full index interval of the axis. + * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. + * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` + * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. + * otherwise the interval wraps around the axis endpoint. + * see also: ``mapinterval``, ``variable.subregion()``" "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." Table Axis Slice Operators From 75c3f4165fec963d6dcb7519be63b39bcf771aac Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 5 Sep 2018 15:49:16 -0700 Subject: [PATCH 225/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 199 +++++++++++++++++++++------------- 1 file changed, 124 insertions(+), 75 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 488abd7f..63af61d2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -502,16 +502,16 @@ Table Axis Slice Operators "``[:j]``", "the beginning element through, but not including, element ``j``" "``[:]``", "the entire array" "``[i:j:k]``", "every ``kth`` element, starting at ``i``, through but not including ``j``" - "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element." - , " **Example:** a longitude axis has value" - , " * ``[0.0, 2.0, ..., 358.0]``" - , " * of length ``180``" - , " * map the coordinate interval:" - , " * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval" - , " * ``-2 <= n < 3`` wraps around, since" - , " * ``-2 < 0``, and has a stride of ``1``" - , " * this is equivalent to the two contiguous index intervals" - , " * ``2 <= n < 0`` and ``0 <= n < 3``" + "``[-i]``", "the ``ith`` element from the end. ``-1`` is the last element. + **Example:** a longitude axis has value + * ``[0.0, 2.0, ..., 358.0]`` + * of length ``180`` + * map the coordinate interval: + * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval + * ``-2 <= n < 3`` wraps around, since + * ``-2 < 0``, and has a stride of ``1`` + * this is equivalent to the two contiguous index intervals + * ``2 <= n < 0`` and ``0 <= n < 3``" Example 1 ''''''''''' @@ -556,7 +556,9 @@ Table CdmsFile Constructors :align: left "Constructor", "Description" - "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. + * ``path`` is the file pathname, a string. + * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." Table CdmsFile Methods @@ -568,42 +570,81 @@ Table CdmsFile Methods :align: left - "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile``" - ,, "object as a function reads the region of data specified by the ``selector``. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, " **Example:** The following reads data for variable 'prc', year 1980:" - ,, " * >>> f = cdms.open('test.nc')" - ,, " * >>> x = f('prc', time=('1980-1','1981-1'))" - "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable." - ,, " **Example:** The following gets the persistent variable" - ,, " * ``v``, equivalent to" - ,, " * ``v = f.variables['prc']``." - ,, " * f = cdms.open('sample.nc')" - ,, " * v = f['prc']" - ,, " **Example:** The following gets the axis named time, equivalent to" - ,, " * ``t = f.axes['time']``." - ,, " * ``t = f['time']``" + "``Transient-Variable``", "``fileobj(varname, selector)``", "Calling a ``CdmsFile`` object as a function reads the region of data specified by the ``selector``. + The result is a transient variable, unless ``raw = 1`` is specified. + See `Selectors <#selectors>`_. + **Example:** The following reads data for variable 'prc', year 1980: + >>> f = cdms.open('test.nc') + >>> x = f('prc', time=('1980-1','1981-1'))" + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. + **Example:** The following gets the persistent variable + * ``v``, equivalent to + * ``v = f.variables['prc']``. + * f = cdms.open('sample.nc') + * v = f['prc'] + **Example:** The following gets the axis named time, equivalent to + * ``t = f.axes['time']``. + * ``t = f['time']``" "``None``", "``close()``", "Close the file." - "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. ``axis`` is the axis object to be copied. ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used." - "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. The returned grid is persistent. If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. ``grid`` is the grid object to be copied. ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used." - "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. This is a persistent object which can be used to read or write axis data to the file. ``id`` is an alphanumeric string identifier, containing no blanks. ``ar`` is the one-dimensional axis array. Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." - "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. ``lat`` is a latitude axis in the file. ``lon`` is a longitude axis in the file. ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. This is a persistent object which can be used to read or write variable data to the file. ``id`` is a String name which is unique with respect to all other objects in the file. ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. ``axes`` is a list of Axis and/or Grid objects. ``fill_value`` is the missing value (optional)." - "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. An error is raised if a variable of the same name exists in the file. ``var`` is the ``Variable`` to be copied. ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``." - ,," **Note:** Unlike copyAxis, the actual data is not copied to the new variable." - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. + The returned object is persistent: it can be used to write axis data to or read axis data from the file. + * If an axis already exists in the file, having the same name and coordinate values, it is returned. + * It is an error if an axis of the same name exists, but with different coordinate values. + * ``axis`` is the axis object to be copied. + * ``newname``, if specified, is the string identifier of the new axis object. + * If not specified, the identifier of the input axis is used." + "``Grid``", "``copyGrid(grid, newname=None)``", "Copy grid values and attributes to a new grid in the file. + * The returned grid is persistent. + * If a grid already exists in the file, having the same name and axes, it is returned. + * An error is raised if a grid of the same name exists, having different axes. + * ``grid`` is the grid object to be copied. + * ``newname``, if specified is the string identifier of the new grid object. + * If unspecified, the identifier of the input grid is used." + "``Axis``", "``createAxis(id,ar, unlimited=0)``", "Create a new ``Axis``. + This is a persistent object which can be used to read or write axis data to the file. + * ``id`` is an alphanumeric string identifier, containing no blanks. + * ``ar`` is the one-dimensional axis array. + * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible." + "``RectGrid``", "``createRectGrid(id,lat, lon,order,type='generic', mask=None)``", "Create a ``RectGrid`` in the file. + This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the file. + * ``lon`` is a longitude axis in the file. + * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). + * ``type`` is one of ``'gaussian'``,\ ``'unif orm'``,\ ``'equalarea'`` , or ``'generic'``. + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "``Variable``", "``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``", "Create a new Variable. + This is a persistent object which can be used to read or write variable data to the file. + * ``id`` is a String name which is unique with respect to all other objects in the file. + * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``. + * ``axes`` is a list of Axis and/or Grid objects. + * ``fill_value`` is the missing value (optional)." + "``Variable``", "``createVariableCopy(var, newname=None)``", "Create a new ``Variable``, with the same name, axes, and attributes as the input variable. + An error is raised if a variable of the same name exists in the file. + * ``var`` is the ``Variable`` to be copied. + * ``newname``, if specified is the name of the new variable. + * If unspecified, the returned variable has the same name as ``var``. + **Note:** Unlike copyAxis, the actual data is not copied to the new variable." + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. + * Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable." - ,,"If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file. If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``." - ,,"* ``var`` is a Variable, masked array, or Numpy array." - ,,"* ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``." - ,,"* ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``." - ,,"* ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``." - ,,"* ``id`` is the variable name in the file. Default is ``var.id``." - ,,"* ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable." - ,," * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour." - ,,"* ``fill_value`` is the missing value flag." - ,,"* ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension." - ,," **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable. + * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. + * By default, the time dimension of the variable is defined as the unlimited dimension of the file. + * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. + * ``var`` is a Variable, masked array, or Numpy array. + * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``. + * ``axes`` is the list of file axes comprising the domain of the variable. + * The default is to copy ``var.getAxisList()``. + * ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``. + * ``id`` is the variable name in the file. Default is ``var.id``. + * ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable. + * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour. + * ``fill_value`` is the missing value flag. + * ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. + **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." Table CDMS Datatypes -------------------- @@ -721,9 +762,16 @@ Table Database Constructors :align: left - "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database." - ,"For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``." - ,"For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection" + "``db = cdms.connect(uri=None, user='', password='')``", "Connect to the database. + * ``uri`` is the Universal Resource Indentifier of the database. + * The form of the URI depends on the implementation of the database. + * For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``. + For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: + * ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. + * If unspecified, the URI defaults to the value of environment variable CDMSROOT. + * ``user`` is the user ID. If unspecified, an anonymous connection is made. + * ``password`` is the user password. + **Note:** A password is not required for an anonymous connection" Table Database Methods ---------------------- @@ -734,33 +782,34 @@ Table Database Methods "None", "``close()``", "Close a database" "List", "``listDatasets()``", "Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command." - "Dataset", "``open(dsetid, mode='r')``", "Open a dataset." - , "* ``dsetid``","is the string dataset identifier" - , "* ``mode``","is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create." - , "* ``openDataset``", "is a synonym for ``open``." - "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database." - ,, "``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation." - ,, - ,," **Example:**" - ,," * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'." - ,," - A formal definition of search filters is provided in the following section." - ,," - ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid')." - ,," - ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy." - ,, - ,," **Example:**" - ,," * To search only dataset 'ncep_reanalysis_mo', specify:" - ,," - ``relbase='dataset=ncep_reanalysis_mo'``" - ,," * To search only variable 'ua' in 'ncep_reanalysis_mo', use:" - ,," - ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``" - ,, - ,,"If no base is specified, the entire database is searched. See the ``scope`` argument also." - ,,"``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**)." - ,," * **Subtree** searches the base object and its descendants." - ,," * **Onelevel** searches the base object and its immediate descendants." - ,," * **Base**\ searches the base object alone." - ,," * The default is **Subtree**." - ,,"``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list." - ,,"``timeout``: integer number of seconds before timeout. The default is no timeout." + "Dataset", "``open(dsetid, mode='r')``", "Open a dataset. + * ``dsetid``is the string dataset identifier + * ``mode`` is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. + * ``openDataset`` is a synonym for ``open``." + "SearchResult","``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``","Search a CDMS database. + * ``filter`` is the string search filter. + * Simple filters have the form 'tag = value'. + * Simple filters can be combined using logical operators '&', '\|', '!' in prefix notation. + **Example:** + * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'. + * A formal definition of search filters is provided in the following section. + * ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid'). + * ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy. + **Example:** + * To search only dataset 'ncep_reanalysis_mo', specify: + * ``relbase='dataset=ncep_reanalysis_mo'`` + * To search only variable 'ua' in 'ncep_reanalysis_mo', use: + * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'`` + * If no base is specified, the entire database is searched. See the ``scope`` argument also. + * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**). + * **Subtree** searches the base object and its descendants. + * **Onelevel** searches the base object and its immediate descendants. + * **Base** searches the base object alone. + * The default is **Subtree**. + * ``attnames``: list of attribute names. Restricts the attributes returned. + * If ``None``, all attributes are returned. + * Attributes 'id' and 'objectclass' are always included in the list. + * ``timeout``: integer number of seconds before timeout. The default is no timeout." ------------ From 16c2397d2a78fcf862fc6ab23d9b7997f0c74286 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 6 Sep 2018 15:48:00 -0700 Subject: [PATCH 226/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 327 ++++++++++++++++++++-------------- 1 file changed, 196 insertions(+), 131 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 63af61d2..593fddb5 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -453,8 +453,10 @@ Table Axis Methods, Additional to CoordinateAxis :align: left - "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times." - "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times." + "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. + * Returns a ``List`` of component times." + "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. + * Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. * ``modulo`` is the modulus value. * Any given axis value ``x`` is treated as equivalent to ``x + modulus``. @@ -487,7 +489,9 @@ Table Axis Methods, Additional to CoordinateAxis * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint. * otherwise the interval wraps around the axis endpoint. * see also: ``mapinterval``, ``variable.subregion()``" - "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. the stride ``k`` can be positive or negative. wraparound is supported for longitude dimensions or those with a modulus attribute." + "``transientaxis``", "``subaxis(i,j,k=1)``", "create an axis associated with the integer range ``[i:j:k]``. + * The stride ``k`` can be positive or negative. + * Wraparound is supported for longitude dimensions or those with a modulus attribute." Table Axis Slice Operators -------------------------- @@ -696,7 +700,9 @@ Overview To access a database: -#. Open a connection. The connect method opens a database connection. Connect takes a database URI and returns a database object: +#. Open a connection. + The connect method opens a database connection. + Connect takes a database URI and returns a database object: ``db=cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US")`` #. Search the database, locating one or more datasets, variables, and/or @@ -835,11 +841,11 @@ Searching a Database (id = ncep*) (project = AMIP2) -**Note** Simple filters can be combined with the logical operators '&', '|', '!'. For example, +**Note:** Simple filters can be combined with the logical operators '&', '|', '!'. For example, * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create. - (&(id = bmrc*)(project = AMIP2)) +(&(id = bmrc*)(project = AMIP2)) * To search only dataset 'ncep_reanalysis_mo', specify: @@ -938,8 +944,10 @@ Table SearchResult Methods "ResultEntry", "``[i]``", "Return the i-th search result. Results can also be returned in a for loop: ``for entry in db.searchResult(tag='dataset'):``" "Integer", "``len()``", "Number of entries in the result." - "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. ``tag`` restricts the search to objects of the class denoted by the tag." - ,,"**Note**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." + "SearchResult", "``searchPredicate(predicate, tag=None)``", "Refine a search result, with a predicate search. + * ``predicate`` is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not. + * ``tag`` restricts the search to objects of the class denoted by the tag. + **Note:**: In the current implementation, ``searchPredicate`` is much less efficient than ``searchFilter``. For best performance, use ``searchFilter`` to narrow the scope of the search, then use ``searchPredicate`` for more general searches." A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute @@ -968,9 +976,8 @@ Table ResultEntry Methods :header: "Type", "Method", "Definition" :widths: 20, 30, 80 - "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry." - ,, "**Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." - + "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. + **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." "``CdmsObj``", "``getObject()``", "Return the CDMS object associated with this entry. **Note:** For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable." @@ -1132,34 +1139,34 @@ Table Dataset Methods :header: "Type", "Definition", "Description" :widths: 30, 30, 80 - "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'." - ,, "**Example:** The following reads data for variable 'prc', year 1980:" - ,, " * f = cdms.open('test. xml')" - ,, " * x = f('prc', time=('1980-1','1981-1'))" - "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found." - ,, "**Example:**" - ,, " * f = cdms.open('sampl e.xml')" - ,, " * v = f['prc']" - ,, " * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``." - ,, "**Example:**" - ,, "``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" + "Transient-Variable", "``datasetobj(varname, selector)``", "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless ``raw = 1`` is specified. See 'Selectors'. + **Example:** The following reads data for variable 'prc', year 1980: + * f = cdms.open('test. xml') + * x = f('prc', time=('1980-1','1981-1'))" + "Variable, Axis, or Grid", "``datasetobj['id']``", "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns ``None`` if not found. + **Example:** + * f = cdms.open('sampl e.xml') + * v = f['prc'] + * gets the persistent variable v, equivalent to ``v =f.variab les['prc']``. + **Example:** + ``t = f['time']`` gets the axis named 'time', equivalent to ``t = f.axes['time']``" "``None``", "``close()``", "Close the dataset." - "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations." - ,,"``lat`` is a latitude axis in the dataset." - ,,"``lon`` is a longitude axis in the dataset." - ,,"``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude)." - ,,"``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic'" - ,,"If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." - "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset." - ,,"``id`` is the string axis identifier." - "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset." - ,,"``id`` is the string grid identifier." + "``RectGrid``", "``createRectGrid(id, lat, lon,order, type='generic', mask=None)``", "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations. + * ``lat`` is a latitude axis in the dataset. + * ``lon`` is a longitude axis in the dataset. + * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). + * ``type`` is one of 'gaussian','uniform','eq ualarea',or 'generic' + * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." + "Axis", "``getAxis(id)``", "Get an axis object from the file or dataset. + * ``id`` is the string axis identifier." + "Grid", "``getGrid(id)``", "Get a grid object from a file or dataset. + * ``id`` is the string grid identifier." "List", "``getPaths()``", "Get a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute." - "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset." - ,,"``id`` is the string variable identifier." - "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile." - ,, "If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``." - ,, " If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "Variable", "``getVariable(id)``", "Get a variable object from a file or dataset. + * ``id`` is the string variable identifier." + "CurveGrid or GenericGrid", "``readScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1)``", "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile. + * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "None", "``sync()``", "Write any pending changes to the dataset." @@ -1357,34 +1364,55 @@ Table HorizontalGrid Methods "Horizontal-Grid", "``clone()``", "Return a transient copy of the grid." "Axis", "``getAxis(Integer n)``", "Get the n-th axis.n is either 0 or 1." - "Tuple", "``getBounds()``", "Get the grid boundary arrays." - ,,"Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:" - ,,"* for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2)." - ,,"* for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4)." - ,,"* for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell." - ,,"For rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``)." - ,,"By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. If disabled, the return value is (None,None).For rectilinear grids: The grid classification mode specifies how the grid type is to be determined. By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. If the mode is 'off' grid.getType is used instead." + "Tuple", "``getBounds()``", "Get the grid boundary arrays. + Returns a tuple ``(latitudeArray, longitudeArray)``, where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid: + * for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2). + * for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4). + * for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell. + * for rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see ``cdms.setAutoBounds``) and the grid classification mode (see ``cdms.setClassifyGrids``). + By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid. + * If disabled, the return value is (None,None).For rectilinear grids: + * The grid classification mode specifies how the grid type is to be determined. + * By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily. + * If the mode is 'off' grid.getType is used instead." "Axis", "``getLatitude()``", "Get the latitude axis of this grid." - "Axis", "``getLongitude()``", " Get the latitude axis of this grid." - "Axis", "``getMask()``", "Get the mask array of this grid, if any.Returns a 2-D Numpy array, having the same shape as the grid. If the mask is not explicitly defined, the return value is ``None``." - "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method.If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." - "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. ``lonBounds`` is defined similarly for the longitude array." - ,,"**Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." - "None", "``setMask(mask, persistent=0)``", "Set the grid mask. If ``persistent == 1``, the mask values are written to the associated file, if any. Otherwise, the mask is associated with the grid, but no I/O is generated. ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." - "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.``" - ,,"``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively." - ,,"Each interval is a tuple having one of the forms:" - ,,"* ``(x,y)``" - ,,"* ``(x,y,indicator)``" - ,,"* ``(x,y,indicator,cycle)``" - ,,"* ``None``" - ,,"where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and:" - ,,"``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co')." - ,,"If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0." - ,,"An interval of ``None`` returns the full index interval of the axis." - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges.Note: The result grid is not associated with any file or dataset." - "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. If the grid is already curvilinear, a copy of the grid object is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." - ,,"**Note:** This method does not apply to generic grids. Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. If the grid is already generic, a copy of the grid is returned. ``gridid`` is the string identifier of the resulting curvilinear grid object. If unspecified, the grid ID is copied." + "Axis", "``getLongitude()``", "Get the latitude axis of this grid." + "Axis", "``getMask()``", "Get the mask array of this grid, if any. + * Returns a 2-D Numpy array, having the same shape as the grid. + * If the mask is not explicitly defined, the return value is ``None``." + "Axis", "``getMesh(self, transpose=None)``", "Generate a mesh array for the meshfill graphics method. + * If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2)." + "None", "``setBounds(latBounds, lonBounds, persistent=0)``", "Set the grid boundaries. + * ``latBounds`` is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are ``[latBounds[k,0],latBou nds[k,1] ]``. + * ``lonBounds`` is defined similarly for the longitude array. + **Note:** By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument ``persistent`` is set to the boundary array is written to the file." + "None", "``setMask(mask, persistent=0)``", "Set the grid mask. + * If ``persistent == 1``, the mask values are written to the associated file, if any. + * Otherwise, the mask is associated with the grid, but no I/O is generated. + * ``mask`` is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid." + "Horizontal-Grid", "``subGridRegion(latInterval, lonInterval)``", "Create a new grid corresponding to the coordinate region defined by ``latInterval, lonInterv al.`` + * ``latInterval`` and ``lonInterval`` are the coordinate intervals for latitude and longitude, respectively. + * Each interval is a tuple having one of the forms: + * ``(x,y)`` + * ``(x,y,indicator)`` + * ``(x,y,indicator,cycle)`` + * ``None`` + Where ``x`` and ``y`` are coordinates indicating the interval ``[x,y)``, and: + * ``indicator`` is a two-character string, where the first character is 'c' if the interval is closed on the left, 'o' if open, and the second character has the same meaning for the right-hand point. (Default: 'co'). + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. + * By default, if ``grid.isCircular()`` is true, the axis is treated as circular with a default value of 360.0. + * An interval of ``None`` returns the full index interval of the axis. + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + **Note:** The result grid is not associated with any file or dataset." + "Transient-CurveGrid", "``toCurveGrid(gridid=None)``", "Convert to a curvilinear grid. + * If the grid is already curvilinear, a copy of the grid object is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied. + **Note:** This method does not apply to generic grids. + * Transient-GenericGrid ``toGenericGrid(gridid=None)`` Convert to a generic grid. + * If the grid is already generic, a copy of the grid is returned. + * ``gridid`` is the string identifier of the resulting curvilinear grid object. + * If unspecified, the grid ID is copied." Table RectGrid Methods, Additional to HorizontalGrid Methods @@ -1394,28 +1422,33 @@ Table RectGrid Methods, Additional to HorizontalGrid Methods :header: "Type", "Method", "Description" :widths: 30, 30, 80 - "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. String ``getType()`` Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. (Array,Array) ``getWeights()`` Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. It is assumed that the latitude and longitude axes are defined in degrees." - ,,"The latitude weights are defined as:" - ,,"``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))``" - ,," The longitude weights are defined as:" - ,,"``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0``" - ,,"For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0" - ,,"**Example:**" - ,,"Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``." - ,,"* from cdms import MV" - ,,"* latwts, lonwts = gri d.getWeights()" - ,,"* weights = MV.outerproduct(latwts, lonwts)" - ,,"Also see the function ``area_weights`` in module ``pcmdi.weighting``." - ,," " - "None", "``setType(gridtype)``", "Set the grid type. ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." - "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used." - ,,"**Example:**" - ,,"This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid." - ,,"``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))``" - ,,"If a mask is defined, the subgrid also has a mask corresponding to the index ranges." - ,,"**Note:** The result grid is not associated with any file or dataset." - "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed." - ,,"**Note:** The result grid is not associated with any file or dataset." + "String", "``getOrder()``", "Get the grid ordering, either 'yx' if latitude is the first axis, or 'xy' if longitude is the first axis. + String ``getType()`` + * Get the grid type, either 'gaussian', 'uniform', 'equalarea', or 'generic'. + * (Array,Array) ``getWeights()`` + * Get the normalized area weight arrays, as a tuple ``(latWeights, lonWeights)``. + * It is assumed that the latitude and longitude axes are defined in degrees. + The latitude weights are defined as: + * ``latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))`` + The longitude weights are defined as: + * ``lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0`` + For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0 + **Example:** + * Generate the 2-D weights array, such that ``weights[i.j]`` is the fractional area of grid zone ``[i,j]``. + * from cdms import MV + * latwts, lonwts = gri d.getWeights() + * weights = MV.outerproduct(latwts, lonwts) + * Also see the function ``area_weights`` in module ``pcmdi.weighting``." + "None", "``setType(gridtype)``", "Set the grid type. + * ``gridtype`` is one of 'gaussian', 'uniform', 'equalarea', or 'generic'." + "RectGrid", "``subGrid((latStart,latStop),(lonStart,lonStop))``", "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used. + **Example:** + * This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid. + * ``newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))`` + * If a mask is defined, the subgrid also has a mask corresponding to the index ranges. + **Note:** The result grid is not associated with any file or dataset." + "RectGrid", "``transpose()``", "Create a new grid, with axis order reversed. The grid mask is also transposed. + **Note:** The result grid is not associated with any file or dataset." Variable @@ -1470,9 +1503,22 @@ Table Variable Constructors "``Dataset.createVariable(String id, String datatype, List axes)``", "Create a Variable in a Dataset. This function is not yet implemented." - "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile." - ,"``id`` is the name of the variable. ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. \*\*Note:\*\* this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." - "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. ``array`` is the data values: a Variable, masked array, or Numpy array. ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. ``grid`` is a rectilinear grid object. ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." + "``CdmsFile.createVariable(String id, String datatype, List axes or Grids)``", "Create a Variable in a CdmsFile. + * ``id`` is the name of the variable. + * ``datatype`` is the MV2 or Numpy | typecode, for example, MV2.Float. + * ``axesOrGrids`` is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid. + **Note:** this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: ``(axisobj,)``." + "``cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None)``", "Create a transient variable, not associated with a file or dataset. + * ``array`` is the data values: a Variable, masked array, or Numpy array. + * ``typecode`` is the MV2 typecode of the array. Defaults to the typecode of array. + * ``copy`` is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array. + * ``savespace`` is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting. + * ``mask`` is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None. + * ``fill_value`` is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables. + * ``grid`` is a rectilinear grid object. + * ``axes`` is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., ..., double(n)]. + * ``attributes`` is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty. + * ``id`` is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to 'variable\_n' for some integer." @@ -1485,55 +1531,74 @@ Table Variable Methods :align: left - "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. Singleton dimensions are 'squeezed' out. Data is returned in the physical ordering defined in the dataset. The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " - "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" - "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. The result is a transient variable, unless raw=1 keyword is specified. See 'Selectors'." + "Variable", "``tvar = var[ i:j, m:n]``", "Read a slice of data from the file or dataset, resulting in a transient variable. + * Singleton dimensions are 'squeezed' out. + * Data is returned in the physical ordering defined in the dataset. + * The forms of the slice operator are listed in `Variable Slice Operators <#table-variable-slice-operators>`_ " + "None", "``var[ i:j, m:n] = array``", "Write a slice of data to the external dataset. + * The forms of the slice operator are listed in `Result Entry Methods <#table-resultentry-methods>`_ . (Variables in CdmsFiles only)" + "Variable", "``tvar = var(selector)``", "Calling a variable as a function reads the region of data defined by the selector. + * The result is a transient variable, unless raw=1 keyword is specified. + * See `Selectors' <#selectors>`_ ." "None", "``assignValue(Array ar)``", "Write the entire data array. Equivalent to ``var[:] = ar``. (Variables in CdmsFiles only)." - "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. Typecodes are as for MV, MV2, and Numpy modules." - "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable." - ,,"If copyData is 1 (the default) the variable data is copied as well. If copyData is 0, the result transient variable shares the original transient variables data array." - "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. The variable should be a function of latitude, level, and (optionally) time." - ,,"* ``newLevel`` is an axis of the result pressure levels." - ,,"* ``newLatitude`` is an axis of the result latitudes." - ,,"* ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,,"* ``missing`` is a missing data value. The default is ``var.getMissing()``" - ,,"* ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``." - ,,"*See also:* ``regrid``, ``pressureRegrid``." - "Axis", "``getAxis(n)``", "Get the n-th axis." - ,,"``n`` is an integer." + "Variable", "``astype(typecode)``", "Cast the variable to a new datatype. + * Typecodes are as for MV, MV2, and Numpy modules." + "Variable", "``clone(copyData=1)``", "Return a copy of a transient variable. + * If copyData is 1 (the default) the variable data is copied as well. + * If copyData is 0, the result transient variable shares the original transient variables data array." + "Transient Variable", "``crossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None)``", "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel. + * The variable should be a function of latitude, level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``newLatitude`` is an axis of the result latitudes. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzy' or 'zy'. The default is ``var.getOrder()``. + * See also: ``regrid``, ``pressureRegrid``." + "Axis", "``getAxis(n)``", "Get the n-th axis. + * ``n`` is an integer." "List", "``getAxisIds()``", "Get a list of axis identifiers." - "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match." - ,,"``axis_spec`` is a specification as defined for getAxisList" - "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable." - ,,"If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given." - ,,"If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below." - ,,"``order`` is an optional string determining the output order." - ,,"Specifications for the axes or omit keywords are a list, each element having one of the following forms:" - ,,"* an integer dimension index, starting at 0." - ,,"* a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'." - ,,"* a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches." - ,,"* an axis object; will match if it is the same object as axis." - ,,"``order`` can be a string containing the characters t,x,y,z, or * ." - ,,"If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." + "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match. + * ``axis_spec`` is a specification as defined for getAxisList" + "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable. + * If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given. + * If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below. + * ``order`` is an optional string determining the output order. + Specifications for the axes or omit keywords are a list, each element having one of the following forms: + * an integer dimension index, starting at 0. + * a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'. + * a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches. + * an axis object; will match if it is the same object as axis. + * ``order`` can be a string containing the characters t,x,y,z, or * . + * If a dash ('-') is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates." "List", "``getAxisListIndex(axes=None, omit=None, order=None)``", "Return a list of indices of axis objects. Arguments are as for getAxisList." - "List", "``getDomain()``", "Get the domain. Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` where axis is an axis object, start is the start index of the domain relative to the axis object, length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. *See also:* ``getAxisList``." + "List", "``getDomain()``", "Get the domain. + Each element of the list is itself a tuple of the form ``(axis,start,length,tru e_length)`` + * where axis is an axis object, + * start is the start index of the domain relative to the axis object, + * length is the length of the axis, and true\_length is the actual number of (defined) points in the domain. + * See also: ``getAxisList``." "Horizontal-Grid", "``getGrid()``", "Return the associated grid, or ``None`` if the variable is not gridded." "Axis", "``getLatitude()``", "Get the latitude axis, or ``None`` if not found." "Axis", "``getLevel()``", "Get the vertical level axis, or ``None`` if not found." "Axis", "``getLongitude()``", "Get the longitude axis, or ``None`` if not found." - "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found." - ,, "String ``getOrder()`` Get the order string of a spatio-temporal variable. The order string specifies the physical ordering of the data. It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. Each character is one of:" - ,, "* 't': time" - ,, "* 'z': vertical level" - ,, "* 'y': latitude" - ,, "* 'x': longitude" - ,, "* '-': the axis is not spatio-temporal." - ,, "**Example:**" - ,, "A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude)." - ,, "**Note:** The order string is of the form required for the order argument of a regridder function." - ,,"``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. If no ``argument(s)`` are present, all file paths associated with the variable are returned." - ,," Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals." - ,, "**Note:** This function is not defined for transient variables." + "Various", "``getMissing()``", "Get the missing data value, or ``None`` if not found. + String ``getOrder()`` Get the order string of a spatio-temporal variable. + * The order string specifies the physical ordering of the data. + * It is a string of characters with length equal to the rank of the variable, indicating the order of the variable's time, level, latitude, and/or longitude axes. + Each character is one of: + * 't': time + * 'z': vertical level + * 'y': latitude + * 'x': longitude + * '-': the axis is not spatio-temporal. + **Example:** + * A variable with ordering 'tzyx' is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude). + + **Note:** The order string is of the form required for the order argument of a regridder function. + * ``intervals`` is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses. + * If no ``argument(s)`` are present, all file paths associated with the variable are returned. + * Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals. + **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." From 8753cc2ed95bd9a2fba2d462a84a3f482fba07ed Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 10 Sep 2018 15:17:47 -0700 Subject: [PATCH 227/239] Changes to sections 1, 2, 3 and 4 --- docs/source/manual/cdms_2.rst | 163 ++++++++++++++++++++-------------- docs/source/manual/cdms_3.rst | 35 ++++---- docs/source/manual/cdms_4.rst | 26 +++--- 3 files changed, 128 insertions(+), 96 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 593fddb5..bd686638 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -144,7 +144,7 @@ Table Cdms Module Functions "``Variable``", "``asVariable(s)``: - Transform ``s`` into a transient variable. + Transform ``s`` into a transient variable. * ``s`` is a masked array, Numpy array, or Variable. * If ``s`` is already a transient variable, ``s`` is returned. * See also: ``isVariable``." @@ -154,23 +154,23 @@ Table Cdms Module Functions * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i`` * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. **Note:** If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). - * See ``setAutoBounds``. + * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``: - Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: - Create a Gaussian latitude axis. Axis values range from north to south. + Create a Gaussian latitude axis. Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: - Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. + Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. * ``xorigin`` is the origin of the longitude axis. * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``: - Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. @@ -178,17 +178,17 @@ Table Cdms Module Functions * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``: - Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: - Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. * ``lon`` is a longitude axis, created by ``cdms.createAxis``. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: - Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. @@ -200,12 +200,12 @@ Table Cdms Module Functions * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: - Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." - "``RectGrid``"," ``createZonalGrid(grid)``: - Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + "``RectGrid``","``createZonalGrid(grid)``: + Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. @@ -240,11 +240,12 @@ Table Cdms Module Functions * The ellipsis ... meaning fill these positions with any remaining axes. * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``: - Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: - * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. - * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. - * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. - **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." + Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. + The autobounds mode determines how this is done: + * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. + * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. + * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. + **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``: Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. @@ -366,7 +367,8 @@ Table Axis Constructors :header: "Constructor", "Description" :widths: 20, 80 - "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_." + "``cdms.createAxis(data, bounds=None)``", "Create an axis which is not associated with a dataset or file. + * See `A First Example <#a-first-example>`_." "``Dataset.createAxis(name,ar)``", "Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)" "``CdmsFile.createAxis(name,ar,unlimited=0)``", "Create an Axis in a ``CdmsFile``. * ``name`` is the string ``name`` of the ``Axis``. @@ -456,7 +458,7 @@ Table Axis Methods, Additional to CoordinateAxis "``List`` of component times", "``asComponentTime(calendar=None)``", "``Array`` version of ``cdtime tocomp``. * Returns a ``List`` of component times." "``List`` of relative times", "``asRelativeTime()``", "``Array`` version of ``cdtime torel``. - * Returns a ``List`` of relative times." + * Returns a ``List`` of relative times." "``None``", "``designateCircular(modulo, persistent=0)``", "Designate the axis to be circular. * ``modulo`` is the modulus value. * Any given axis value ``x`` is treated as equivalent to ``x + modulus``. @@ -562,7 +564,7 @@ Table CdmsFile Constructors "Constructor", "Description" "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. * ``path`` is the file pathname, a string. - * ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." + * ``mode`` is the open mode indicator, as listed in `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." Table CdmsFile Methods @@ -1263,9 +1265,16 @@ Table MV Functions :align: left "``argsort(x, axis=-1, fill_value=None)``", "Return a Numpy array of indices for sorting along a given axis." - "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. Also see the variable ``astype()`` function." - "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` In computing these sums, elements that correspond to those that are masked in x or weights are ignored." - "``choose(condition, t)``", "Has a result shaped like array condition. ``t`` must be a tuple of two arrays ``t1`` and ``t2``. Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. The result is masked where ``condition`` is masked or where the selected element is masked." + "``asarray(data, typecode=None)``", "Same as ``cdms.createVariable(data, typecode, copy=0)``. + * This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in ``data = asarray(data)``. + * Also see the variable ``astype()`` function." + "``average(a, axis=0, weights=None)``", "Computes the average value of the non-masked elements of x along the selected axis. + * If weights is given, it must match the size and shape of x, and the value returned is: ``sum(a*weights)/sum(weights)`` + * In computing these sums, elements that correspond to those that are masked in x or weights are ignored." + "``choose(condition, t)``", "Has a result shaped like array condition. + * ``t`` must be a tuple of two arrays ``t1`` and ``t2``. + * Each element of the result is the corresponding element of ``t1``\ where ``condition`` is true, and the corresponding element of ``t2`` where ``condition`` is false. + * The result is masked where ``condition`` is masked or where the selected element is masked." "``concatenate(arrays, axis=0, axisid=None, axisattributes=None)``", "Concatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array." "``count(a, axis=None)``", "Count of the non-masked elements in ``a``, or along a certain axis." "``isMaskedVariable(x)``", "Return true if ``x`` is an instance of a variable." @@ -1276,14 +1285,18 @@ Table MV Functions "``masked_less_equal(x, value)``", "``x`` masked where ``x ≤ value``" "``masked_not_equal(x, value)``", "``x`` masked where ``x != value``" "``masked_outside(x, v1, v2)``", "``x`` with mask of all values of ``x`` that are outside ``[v1,v2]``" - "``masked_where(condition, x, copy=1)``", "Return ``x`` as a variable masked where condition is true. Also masked where ``x`` or ``condition`` masked. ``condition`` is a masked array having the same shape as ``x``." + "``masked_where(condition, x, copy=1)``", "Return ``x`` as a variable masked where condition is true. + * Also masked where ``x`` or ``condition`` masked. + * ``condition`` is a masked array having the same shape as ``x``." "``maximum(a, b=None)``", "Compute the maximum valid values of ``x`` if ``y`` is ``None``; with two arguments, return the element-wise larger of valid values, and mask the result where either ``x`` or ``y`` is masked." "``minimum(a, b=None)``", "Compute the minimum valid values of ``x`` if ``y`` is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either ``x`` or ``y`` is masked." "``outerproduct(a, b)``", "Return a variable such that ``result[i, j] = a[i] * b[j]``. The result will be masked where ``a[i]`` or ``b[j]`` is masked." "``power(a, b)``", "``a**b``" "``product(a, axis=0, fill_value=1)``", "Product of elements along axis using ``fill_value`` for missing elements." "``repeat(ar, repeats, axis=0)``", "Return ``ar`` repeated ``repeats`` times along ``axis``. ``repeats`` is a sequence of length ``ar.shape[axis]`` telling how many times to repeat each element." - "``set_default_fill_value(value_type, value)``", "Set the default fill value for ``value_type`` to ``value``. ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. ``value`` should be a scalar or single-element array." + "``set_default_fill_value(value_type, value)``", "Set the default fill value for ``value_type`` to ``value``. + * ``value_type`` is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’. + * ``value`` should be a scalar or single-element array." "``sort(ar, axis=-1)``", "Sort array ``ar`` elementwise along the specified axis. The corresponding axis in the result has dummy values." "``sum(a, axis=0, fill_value=0)``", "Sum of elements along a certain axis using ``fill_value`` for missing." "``take(a, indices, axis=0)``", "Return a selection of items from ``a``. See the documentation in the Numpy manual." @@ -1601,41 +1614,55 @@ Table Variable Methods **Note:** This function is not defined for transient variables." "Axis", "``getTime()``", "Get the time axis, or ``None`` if not found." "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." - "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned." - ,,"**Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time." - ,, "``newLevel`` is an axis of the result pressure levels." - ,, "``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation." - ,, "``missing`` is a missing data value. The default is ``var.getMissing()``" - ,, "``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()``" - ,, "See also: ``regrid``, ``crossSectionRegrid``." + "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. + **Note:** ``size()`` returns the total number of elements." + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time. + * ``newLevel`` is an axis of the result pressure levels. + * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. + * ``missing`` is a missing data value. The default is ``var.getMissing()`` + * ``order`` is an order string such as 'tzyx' or 'zyx'. The default is ``var.getOrder()`` + * See also: ``regrid``, ``crossSectionRegrid``." "Integer", "``rank()``", "The number of dimensions of the variable." - "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid." - ,, "``missing`` is a Float specifying the missing data value. The default is 1.0e20." - ,, "``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of array match the input grid." - ,, "``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any." - ,, "See also: ``crossSectionRegrid``, ``pressureRegrid``." + "Transient", "``regrid (togrid, missing=None, order=None, Variable mask=None)``","Return the variable regridded to the horizontal grid togrid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder()``. + * For example, the string 'tzyx' indicates that the dimension order of array is (time, level, latitude, longitude). + * If unspecified, the function assumes that the last two dimensions of array match the input grid. + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding. + * If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. + * If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored. + * Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither missing or mask is set, the default mask is obtained from the mask of the array if any. + See also: ``crossSectionRegrid``, ``pressureRegrid``." "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." - "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space." - ,,"``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. If trailing dimensions are omitted, all values of those dimensions are retrieved. If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. Only one axis may be read with wraparound. A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . Also see ``axis.mapIntervalExt``." - ,,"The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. An exception is raised if a keyword argument conflicts with a positional region argument." - ,,"The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'." - ,,"The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off." - ,,"``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form:" - ,,"* a single integer n, meaning ``slice(n, n+1)``" - ,,"* an instance of the slice class" - ,,"* a tuple, which will be used as arguments to create a slice" - ,,"* ':', which means a slice covering that entire dimension" - ,,"* Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments" - ,,"* a Python slice object, of the form ``slice(i,j,k)``" - ,,"If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read." - ,,"The keyword arguments are defined as in subRegion." - ,,"There must be no conflict between the positional arguments and the keywords." - ,,"In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing." - ,,"String ``typecode()`` The Numpy datatype identifier." + "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. + * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. + * If trailing dimensions are omitted, all values of those dimensions are retrieved. + * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. + * Only one axis may be read with wraparound. + * A coordinate interval has one of the forms listed in `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ . + * Also see ``axis.mapIntervalExt``. + * The optional keyword arguments ``time``, ``level``, ``latitude``, and ``longitude`` may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance. + * An exception is raised if a keyword argument conflicts with a positional region argument. + * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. + * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. + * By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." + "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off. + * ``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. + There can be zero or more positional arguments, each of the form: + * a single integer n, meaning ``slice(n, n+1)`` + * an instance of the slice class + * a tuple, which will be used as arguments to create a slice + * ':', which means a slice covering that entire dimension + * Ellipsis (...), which means to fill the slice list with ':' leaving only enough room at the end for the remaining positional arguments + * a Python slice object, of the form ``slice(i,j,k)`` + * If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read. + * The keyword arguments are defined as in subRegion. + * There must be no conflict between the positional arguments and the keywords. + * In ``(a)-(c)`` and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing. + * String ``typecode()`` The Numpy datatype identifier." Example Get a Region of Data. ----------------------------- @@ -1689,15 +1716,15 @@ Table Index and Coordinate Intervals :header: "Interval Definition", "Example Interval Definition", "Example" :widths: 30, 80, 80 - "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0``" - ,,"``cdtime.reltime(48,'hour s since 1980-1')``" - ,,"``'1980-1-3'``" + "``x``", "single point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted.", "``180.0`` + ``cdtime.reltime(48,'hour s since 1980-1')`` + ``'1980-1-3'``" "``(x,y)``", "indices i such that x ≤ axis[i] ≤ y", "``(-180,180)``" "``(x,y,'co')``", "``x ≤ axis[i] < y``. The third item is defined as in mapInterval.", "``(-90,90,'cc')``" - "``(x,y,'co',cycle)``", "``x ≤ axis[i]< y``, with wraparound", "``( 180, 180, 'co', 360.0)``" - "","**Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true.", - "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)``" - ,,"``slice(,,-1)`` reverses the direction of the axis." + "``(x,y,'co',cycle)``", "``x ≤ axis[i]< y``, with wraparound", "``( 180, 180, 'co', 360.0)`` + **Note:** It is not necesary to specify the cycle of a circular longitude axis, that is, for which ``axis.isCircular()`` is true." + "``slice(i,j,k)``", " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.","``slice(1,10)`` + ``slice(,,-1)`` reverses the direction of the axis." "``':'``", "all axis values of one dimension", "``Ellipsis``", "all values of all intermediate axes", @@ -1775,14 +1802,14 @@ Table Selector Keywords :widths: 30, 80, 80 "``axisid``", "Restrict the axis with ID axisid to a value or range of values.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``grid``", "Regrid the result to the grid.", " Grid object" + "``grid``", "Regrid the result to the grid.", "Grid object" "``latitude``", "Restrict latitude values to a value or range. Short form: lat", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``level``", "Restrict vertical levels to a value or range. Short form: lev",See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ "``longitude``", "Restrict longitude values to a value or range. Short form: lon", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ - "``order``", "Reorder the result.", " Order string, e.g., 'tzyx'" - "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." - "``required``", "Require that the axis IDs be present.", " List of axis identifiers." - "``squeeze``", "Remove singleton dimensions from the result.", " 0: leave singleton dimensions (default); 1: remove singleton dimensions." + "``order``", "Reorder the result.", "Order string, e.g., 'tzyx'" + "``raw``", "Return a masked array (MV2.array) rather than a transient variable.", "0: return a transient variable (default); =1: return a masked array." + "``required``", "Require that the axis IDs be present.", "List of axis identifiers." + "``squeeze``", "Remove singleton dimensions from the result.", "0: leave singleton dimensions (default); 1: remove singleton dimensions." "``time``", "Restrict time values to a value or range.", See `Index and Coordinate Intervals <#table-index-and-coordinate-intervals>`_ Another form of selector components is the positional form, where the diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index c7def749..0d384683 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -107,12 +107,12 @@ Table Component Time :header: "Type", "Name", "Summary" :widths: 15, 15, 50 - * "Integer", "year", "Year value" - * "Integer", "month", "Month, in the range 1..12" - * "Integer", "day", "Day of month, in the range 1 .. 31" - * "Integer", "hour", "Hour, in the range 0 .. 23" - * "Integer", "minute", "Minute, in the range 0 .. 59" - * "Float", "second", "Seconds, in the range 0.0 .. 60.0" + "Integer", "year", "Year value" + "Integer", "month", "Month, in the range 1..12" + "Integer", "day", "Day of month, in the range 1 .. 31" + "Integer", "hour", "Hour, in the range 0 .. 23" + "Integer", "minute", "Minute, in the range 0 .. 59" + "Float", "second", "Seconds, in the range 0.0 .. 60.0" Time Methods ^^^^^^^^^^^^ @@ -126,17 +126,18 @@ Table Time Methods :widths: 20, 75, 80 :align: left - "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``" - ,, "``calendar`` is the calendar type." - "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively." - ,, "``t2`` is the time to compare." - ,, "``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time." - ,, "``value`` is the Float number of interval units." - ,, "``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]" - ,, "``calendar`` is the calendar type. " + "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is ``cdtime. + * [Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]`` + * ``calendar`` is the calendar type." + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively. + * ``t2`` is the time to compare. + * ``calendar`` is the calendar type." + "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time. + * ``value`` is the Float number of interval units. + * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)] + * ``calendar`` is the calendar type. " "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." ,, "``calendar`` is the calendar type." "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index d84a5941..8a1b52a3 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -308,7 +308,10 @@ Table CDMS Regridder Constructor :widths: 50, 90 :align: left - "``regridFunction = Regridder(inputGrid, outputGrid)``", "reate a regridder function which interpolates a data array from input to output grid. `CDMS regridder functions`_ describes the calling sequence of this function. ``inputGrid`` and ``outputGrid`` are CDMS grid objects. **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." + "``regridFunction = Regridder(inputGrid, outputGrid)``", "Create a regridder function which interpolates a data array from input to output grid. + * `CDMS regridder functions`_ describes the calling sequence of this function. + * ``inputGrid`` and ``outputGrid`` are CDMS grid objects. + **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function." SCRIP Regridder ^^^^^^^^^^^^^^^ @@ -324,16 +327,17 @@ Table SCRIP Regridder Constructor :widths: 80, 90 :align: left - "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object." - "", "``fileobj`` is a CDMS file object, as returned from ``cdms.open``." - "", "``mapMethod`` is one of:" - "", "- ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved." - "", "- ``'bilinear'``: bilinear interpolation" - "", "- ``'bicubic'``: bicubic interpolation" - "", "- ``'distwgt'``: distance-weighted interpolation." - "", "It is only necessary to specify the map method if it is not defined in the file." - "", "" - "", "If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees." + "``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``", "Read a regridder from an open CDMS file object. + * ``fileobj`` is a CDMS file object, as returned from ``cdms.open``. + * ``mapMethod`` is one of: + * ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved. + * ``'bilinear'``: bilinear interpolation + * ``'bicubic'``: bicubic interpolation + * ``'distwgt'``: distance-weighted interpolation. + * It is only necessary to specify the map method if it is not defined in the file. + * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. + * Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. + * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." Regridder Functions ^^^^^^^^^^^^^^^^^^^ From eb9ee844bee39c431a6f6550202dcf6782206377 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 11 Sep 2018 14:41:50 -0700 Subject: [PATCH 228/239] Changes to section 2 --- docs/source/manual/cdms_4.rst | 56 ++++++++++++++++++++++------------- docs/source/manual/cdms_5.rst | 56 ++++++++++++++++++++++------------- regrid2/Lib/esmf.py | 6 ++-- 3 files changed, 75 insertions(+), 43 deletions(-) diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 8a1b52a3..ffe4dd83 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -411,17 +411,21 @@ Table CDMS Regridder Function :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned." - , , "``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4." - , , - , , "For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid." - , , "- ``missing`` is a Float specifying the missing data value. The default is 1.0e20." - , , "- ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``" - , , "- ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument." - , , "If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. Note: If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." - "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``)." - , , "``dataArray`` is the result data array." - , , "``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. + * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). + * If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. + * ``missing`` is a Float specifying the missing data value. The default is 1.0e20. + * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().`` + * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1. + * A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding. + * A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module. + * A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument. + * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid. If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time. + **Note:** If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any." + "Array, Array", "``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``", "If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``). + * ``dataArray`` is the result data array. + * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid." SCRIP Regridder Functions ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,17 +476,29 @@ Table SCRIP Regridder Functions :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. The return value is the regridded data variable. ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable." - ,,"``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." - ,,"``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``." - ,,"``gradientLon``: df/dj. Same shape as ``array``." - ,,"``gradientLatLon``: d(df)/(di)(dj). Same shape as array." - "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. The array is 1-D, with length equal to the number of cells in the output grid." - "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the output grid." + "Array or Transient-Variable", "[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``", "Interpolate a gridded data array to a new grid. + The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. + * The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. + * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. + * Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length." + "Array or Transient-Variable", "[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``", "Interpolate a gridded data array to a new grid, using a bicubic regridder. + The return value is the regridded data variable. + * ``array`` is a Variable, MaskedArray, or Numpy array. + * The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. + * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. + * Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length. + * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``. + * ``gradientLon``: df/dj. Same shape as ``array``. + * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array." + "Numpy array", "``getDestinationArea()`` [conservative regridders only]", "Return the area of the destination (output) grid cell. + * The array is 1-D, with length equal to the number of cells in the output grid." + "Numpy array", "``getDestinationFraction()``", "Return the area fraction of the destination (output) grid cell that participates in the regridding. + * The array is 1-D, with length equal to the number of cells in the output grid." "CurveGrid or Generic-Grid", "``getInputGrid()``", "Return the input grid, or None if no input grid is associated with the regridder." "CurveGrid or Generic-Grid", "``getOutputGrid()``", "Return the output grid." - "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid" + "Numpy array", "``getSourceFraction()``", "Return the area fraction of the source (input) grid cell that participates in the regridding. + * The array is 1-D, with length equal to the number of cells in the input grid" Examples ^^^^^^^^ diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index c74a2124..efa8c964 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -195,27 +195,43 @@ Table Plot Keywords "``continents``", "0 or 1", "if ``1``, plot continental outlines (default:plot if * ``xaxis`` is longitude, * ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'" - "``file_comment``", "string", "Comment, defaults to ``variable.parent.comment``" - "``grid``", "CDMS grid object", "Grid associated with the data. Defaults to ``variable.getGrid()``" + "``file_comment``", "string", "Comment, + * Defaults to ``variable.parent.comment``" + "``grid``", "CDMS grid object", "Grid associated with the data. + * Defaults to ``variable.getGrid()``" "``hms``", "string", "Hour, minute, second" - "``long_name``", "string", "Descriptive variable name, defaults to ``variable.long_name``." - "``missing_value``", "same type as array", "Missing data value, defaults to ``variable.getMissing()``" - "``name``", "string", "Variable name, defaults to ``variable.id``" - "``time``", "cdtime relative or absolute", "Time associated with the data." - ,,"Example:" - ,,"- ``cdtime.reltime(30.0, 'days since 1978-1-1').``" - "``units``", "string", "Data units. Defaults to ``variable.units``" - "``variable``", "CDMS variable object", "Variable associated with the data. The variable grid must have the same shape as the data array." - "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. Array of coordinate values, having the same length as the corresponding dimension. Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" - "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. Axis object. ``xaxis`` defaults to ``grid.getAxis(0)``, ``yaxis`` defaults to ``grid.getAxis(1)``" - "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. Boundary array of shape ``(n,2)`` where ``n`` is the axis length. Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." - - "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. Axis name. Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" - "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. Defaults to 0, with the following exceptions:" - ,,"- If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1" - ,,"- If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." - - "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." + "``long_name``", "string", "Descriptive variable name, + * Defaults to ``variable.long_name``." + "``missing_value``", "same type as array", "Missing data value, + * Defaults to ``variable.getMissing()``" + "``name``", "string", "Variable name, + * Defaults to ``variable.id``" + "``time``", "cdtime relative or absolute", "Time associated with the data. + Example: + * ``cdtime.reltime(30.0, 'days since 1978-1-1').``" + "``units``", "string", "Data units. + * Defaults to ``variable.units``" + "``variable``", "CDMS variable object", "Variable associated with the data. + * The variable grid must have the same shape as the data array." + "``xarray`` (``[y|z|t|w]array``)", "1-D Numpy array", "*Rectangular grids only*. + * Array of coordinate values, having the same length as the corresponding dimension. + * Defaults to ``xaxis[:\] (y|z|t|waxis[:])``" + "``xaxis`` (``[y|z|t|w]axis``)", "CDMS axis object", "*Rectangular grids only*. + Axis object. + * ``xaxis`` defaults to ``grid.getAxis(0)`` + * ``yaxis`` defaults to ``grid.getAxis(1)``" + "``xbounds`` (``ybounds``)", "2-D Numpy array", "*Rectangular grids only*. + * Boundary array of shape ``(n,2)`` where ``n`` is the axis length. + * Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()`` if ``None``, similarly for ``ybounds``." + "``xname`` (``[y|z|t|w]name``)", "string", "*Rectangular grids only*. + Axis name. + * Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)" + "``xrev`` (``yrev``)", "0 or 1", "If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. + * Defaults to 0, with the following exceptions: + * If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1 + * If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1." + "``xunits`` (``[y|z|t|w]units``)", "string", "*Rectangular grids only*. Axis units. + * Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``)." diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 0cbe6307..50a408a2 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -39,7 +39,7 @@ class EsmfUnstructGrid: """ Constructor - Parameters + Parameters ---------- numTopoDims @@ -274,8 +274,8 @@ def getLocalSlab(self, staggerloc): Parameters ---------- - - staggerloc + : + staggerloc (e.g. ESMF.StaggerLoc.CENTER) _: None From b39bb62e1bd35a7f0048d55322f6036e6647569a Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 17 Sep 2018 15:08:13 -0700 Subject: [PATCH 229/239] Changes made to entire docuemnt --- Lib/avariable.py | 10 +- docs/source/manual/cdms_2.rst | 168 ++++++++++++++++++++------------- docs/source/manual/cdms_3.rst | 8 +- docs/source/manual/cdms_4.rst | 3 +- docs/source/manual/cdms_7.rst | 4 +- regrid2/Lib/crossSection.py | 70 ++++++-------- regrid2/Lib/esmf.py | 159 ++++++++++++------------------- regrid2/Lib/horizontal.py | 8 +- regrid2/Lib/mvESMFRegrid.py | 5 +- regrid2/Lib/mvGenericRegrid.py | 29 ++---- regrid2/Lib/pressure.py | 60 +++++++----- regrid2/Lib/scrip.py | 18 ++-- 12 files changed, 269 insertions(+), 273 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 1c523585..0135b514 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -177,8 +177,8 @@ def __call__(self, *args, **kwargs): """ Selection of a subregion using selectors. - Parameters - ---------- + **Parameters:** + raw: if set to 1, return numpy.ma only squeeze: @@ -188,9 +188,9 @@ def __call__(self, *args, **kwargs): order: if given, result is permuted into this order - Returns - ------- - Subregion selected + **Returns:** + + Subregion selected """ # separate options from selector specs d = kwargs.copy() diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index bd686638..f4881530 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -102,12 +102,21 @@ latitude, longitude). "2,3", "Makes the CDMS and MV modules available. MV defines arithmetic functions." "4", "Opens a netCDF file read-only. The result jones is a dataset object." "5", "Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data." - "6", "Read all January monthly mean data into a variable jans. Variables can be sliced like arrays. The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. Note that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array." + "6", "Read all January monthly mean data into a variable jans. + * Variables can be sliced like arrays. + * The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. + **Note:** that the variable is actually 3-dimensional. + * Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. + * The slice operation could also have been written [0::12, : , :]. + * Also note that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array." "7", "Reads all July data into a masked array julys." "8", "Calculate the average January value for each grid zone. Any missing data is handled automatically." "9,10", "Set the variable id and long\_name attributes. The id is used as the name of the variable when plotted or written to a file." "14", "Create a new netCDF output file named ‘janjuly.nc’ to hold the results." - "15", "Write the January average values to the output file. The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. A more general method of data output is first to create a variable, then set a slice of the variable. Note that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." + "15", "Write the January average values to the output file. + * The variable will have id “tas\_jan” in the file. ``write`` is a utility function which creates the variable in the file, then writes data to the variable. + * A more general method of data output is first to create a variable, then set a slice of the variable. + **Note:** that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations." "17", "Set the global attribute ‘comment’." "18", "Close the output file." @@ -145,25 +154,26 @@ Table Cdms Module Functions "``Variable``", "``asVariable(s)``: Transform ``s`` into a transient variable. - * ``s`` is a masked array, Numpy array, or Variable. - * If ``s`` is already a transient variable, ``s`` is returned. - * See also: ``isVariable``." + * ``s`` is a masked array, Numpy array, or Variable. + * If ``s`` is already a transient variable, ``s`` is returned. + * See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``: - Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. - * ``data`` is a one-dimensional, monotonic Numpy array. - * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i`` - * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. - **Note:** If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). - * See ``setAutoBounds``. - * Also see: ``CdmsFile.createAxis``" + Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. + This is useful for creating a grid which is not contained in a file or dataset. + * ``data`` is a one-dimensional, monotonic Numpy array. + * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i`` + * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``. + **Note:** If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). + * See ``setAutoBounds``. + * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``: Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. - **Note:** The axis is not associated with a file or dataset." + **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: Create a Gaussian latitude axis. Axis values range from north to south. * ``nlat`` is the axis length. - **Note:** The axis is not associated with a file or dataset." + **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. * ``nlats`` is the number of latitudes. @@ -178,17 +188,21 @@ Table Cdms Module Functions * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``: - Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of he input grid. + Generate a grid for calculating the global mean via a regridding operation. + * The return grid is a single zone covering the range of he input grid. * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: - Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. + Create a rectilinear grid, not associated with a file or dataset. + * This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. * ``lon`` is a longitude axis, created by ``cdms.createAxis``. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: - Create a uniform rectilinear grid. The grid is not associated with a file or dataset. The grid boundaries are at the midpoints of the axis values. + Create a uniform rectilinear grid. + * The grid is not associated with a file or dataset. + * The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. @@ -200,56 +214,71 @@ Table Cdms Module Functions * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: - Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular latitude axis. + Create a uniform latitude axis. + * The axis boundaries are at the midpoints of the axis values. + * The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``: - Create a zonal grid. The output grid has the same latitude as the input grid, and a single longitude. This may be used to calculate zonal averages via a regridding operation. + Create a zonal grid. + * The output grid has the same latitude as the input grid, and a single longitude. + * This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: - Create a uniform longitude axis. The axis boundaries are at the midpoints of the axis values. The axis is designated as a circular longitude axis. + Create a uniform longitude axis. + * The axis boundaries are at the midpoints of the axis values. + * The axis is designated as a circular longitude axis. * ``startLon`` is the starting longitude value. * ``nlon`` is the number of longitudes. * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" - "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. Returns 0, 1, or 2. + "``Integer``", "``getAutoBounds()``: + Get the current autobounds mode. + * Returns 0, 1, or 2. * See ``setAutoBounds``." "``Integer``", "``isVariable(s)``: - * Return ``1`` if ``s`` is a variable, ``0`` otherwise. - * See also: ``asVariable``." + * Return ``1`` if ``s`` is a variable, ``0`` otherwise. + * See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: - Open or create a ``Dataset`` or ``CdmsFile``. - * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. - * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. - * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. - * If the protocol is 'file' or is omitted, a local file or dataset is opened. - * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ - * **Example:** Open an existing dataset: ``f = cdms.open('sampleset.xml')`` - * **Example:** Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" + Open or create a ``Dataset`` or ``CdmsFile``. + * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. + * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. + * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. + * If the protocol is 'file' or is omitted, a local file or dataset is opened. + * ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__ + **Example:** + Open an existing dataset: ``f = cdms.open('sampleset.xml')`` + + **Example:** + Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``: - Find the index permutation of axes to match order. Return a list of indices. - * ``axes`` is a list of axis objects. - * ``orderstring`` is defined as in ``orderparse``." + Find the index permutation of axes to match order. + * Return a list of indices. + * ``axes`` is a list of axis objects. + * ``orderstring`` is defined as in ``orderparse``." "``List``", "``orderparse(orderstring)``: - Parse an order string. Returns a list of axes specifiers. + Parse an order string. + * Returns a list of axes specifiers. ``orderstring`` consists of: - * Letters t, x, y, z meaning time, longitude, latitude, level - * Numbers 0-9 representing position in axes - * Dash (-) meaning insert the next available axis here. - * The ellipsis ... meaning fill these positions with any remaining axes. - * (name) meaning an axis whose id is name" + * Letters t, x, y, z meaning time, longitude, latitude, level + * Numbers 0-9 representing position in axes + * Dash (-) meaning insert the next available axis here. + * The ellipsis ... meaning fill these positions with any remaining axes. + * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``: - Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. + Set autobounds mode. + In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``." "``None``", "``setClassifyGrids(mode)``: - Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries. - * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. - * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." + Set the grid classification mode. + This affects how grid type is determined, for the purpose of generating grid boundaries. + * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. + * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type." "``None``", "``writeScripGrid(path, grid, gridTitle=None)``: Write a grid to a SCRIP grid file. * ``path`` is a string, the path of the SCRIP file to be created. @@ -344,9 +373,17 @@ Table CoordinateAxis Types :widths: 20, 80 "``CoordinateAxis``", "A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``." - "``Axis``", "A one-dimensional coordinate axis whose values are strictly monotonic. Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. May be an index axis, mapping a range of integers to the equivalent floating point value. If a latitude or longitude axis, may be associated with a ``RectGrid``." - "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." - "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``. Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. There can be at most one unlimited axis associated with a ``CdmsFile``." + "``Axis``", "A one-dimensional coordinate axis whose values are strictly monotonic. + * Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. + * May be an index axis, mapping a range of integers to the equivalent floating point value. + * If a latitude or longitude axis, may be associated with a ``RectGrid``." + "``Axis2D``", "A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. + * Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``." + "``AuxAxis1D``", "A one-dimensional coordinate axis whose values need not be monotonic. + * Typically a latitude or longitude axis associated with a ``GenericGrid``. + * Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. + * An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. + * There can be at most one unlimited axis associated with a ``CdmsFile``." Table CoordinateAxis Internal Attributes ---------------------------------------- @@ -582,7 +619,8 @@ Table CdmsFile Methods **Example:** The following reads data for variable 'prc', year 1980: >>> f = cdms.open('test.nc') >>> x = f('prc', time=('1980-1','1981-1'))" - "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. + "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. + This does not read the data for a variable. **Example:** The following gets the persistent variable * ``v``, equivalent to * ``v = f.variables['prc']``. @@ -630,13 +668,15 @@ Table CdmsFile Methods * ``newname``, if specified is the name of the new variable. * If unspecified, the returned variable has the same name as ``var``. **Note:** Unlike copyAxis, the actual data is not copied to the new variable." - "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. The file can be a SCRIP grid file or remapping file. + "``CurveGrid`` or ``Generic-Grid``", "``readScripGrid(self,whichGrid='destination',check-Grid=1)``", "Read a curvilinear or generic grid from a SCRIP netCDF file. + The file can be a SCRIP grid file or remapping file. * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``. * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. * Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. * The repair consists of shifting the cell vertices to the same side modulo 360 degrees." "``None``", "``sync()``", "Writes any pending changes to the file." - "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. The return value is the associated file variable. + "``Variable``", "``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``","Write a variable or array to the file. + The return value is the associated file variable. * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. * By default, the time dimension of the variable is defined as the unlimited dimension of the file. * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``. @@ -804,20 +844,20 @@ Table Database Methods * ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid'). * ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy. **Example:** - * To search only dataset 'ncep_reanalysis_mo', specify: - * ``relbase='dataset=ncep_reanalysis_mo'`` - * To search only variable 'ua' in 'ncep_reanalysis_mo', use: - * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'`` - * If no base is specified, the entire database is searched. See the ``scope`` argument also. - * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**). - * **Subtree** searches the base object and its descendants. - * **Onelevel** searches the base object and its immediate descendants. - * **Base** searches the base object alone. - * The default is **Subtree**. - * ``attnames``: list of attribute names. Restricts the attributes returned. - * If ``None``, all attributes are returned. - * Attributes 'id' and 'objectclass' are always included in the list. - * ``timeout``: integer number of seconds before timeout. The default is no timeout." + To search only dataset 'ncep_reanalysis_mo', specify: + * ``relbase='dataset=ncep_reanalysis_mo'`` + o search only variable 'ua' in 'ncep_reanalysis_mo', use: + * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'`` + If no base is specified, the entire database is searched. See the ``scope`` argument also. + * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**). + * **Subtree** searches the base object and its descendants. + * **Onelevel** searches the base object and its immediate descendants. + * **Base** searches the base object alone. + * The default is **Subtree**. + * ``attnames``: list of attribute names. Restricts the attributes returned. + * If ``None``, all attributes are returned. + * Attributes 'id' and 'objectclass' are always included in the list. + * ``timeout``: integer number of seconds before timeout. The default is no timeout." ------------ diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 0d384683..4af4e7a7 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -138,9 +138,11 @@ Table Time Methods * ``value`` is the Float number of interval units. * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)] * ``calendar`` is the calendar type. " - "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. Returns the equivalent component time." - ,, "``calendar`` is the calendar type." - "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. Returns the equivalent relative time." + "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. + * Returns the equivalent component time. + * ``calendar`` is the calendar type." + "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. + * Returns the equivalent relative time." Examples diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index ffe4dd83..51322ea9 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -411,7 +411,8 @@ Table CDMS Regridder Function :widths: 40, 40, 80 :align: left - "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. The interpolation preservesthe area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. + "Array or Transient-Variable", "``regridFunction(array, missing=None, order=None, mask=None)``", "Interpolate a gridded data array to a new grid. + The interpolation preserves the area-weighted mean on each horizontal slice. If array is a Variable, a TransientVariable of the same rank as the inputarrayisreturned, otherwiseamaskedarray is returned. * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). * If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid. diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index c366849b..709e12c1 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -120,7 +120,7 @@ Table CDScan Command Options "``-r time_units``", "Time units of the form ``units since yyyy-mm-dd hh:mi:ss``, where: * ``units`` is one of 'year', 'month', 'day', 'hour', 'minute', 'second'." "``-s suffix_file``", "Append a suffix to variable names, depending on the directory containing the data file. - - This can be used to distinguish variables having the same name but generated by different models or ensemble runs. + This can be used to distinguish variables having the same name but generated by different models or ensemble runs. * ``suffix_file`` is the name of a file describing a mapping between directories and suffixes. * Each line consists of two blank-separated fields: ``directory suffix``. * Each file path is compared to the directories in the suffix file. @@ -131,7 +131,7 @@ Table CDScan Command Options * The default is the name of the time dimension as determined by CDMS. * See Note 1." "``--time-linear tzero,delta,units[,calendar]``", "Override the time dimensions(s) with a linear time dimension. - - The arguments are comma-separated list: + The arguments are comma-separated list: * zero is the initial time point, a floating-point value. * delta is the time delta, floating-point. * units are time units as specified in the [-r] option. diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index f532f6bb..6a63d2ea 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -545,23 +545,21 @@ def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', def checkdimension(x, name): """ - Purpose + **Purpose:** dimension checks 1. has a len method 2. data type is float32 3. monotonically increasing vectors - Parameters - ---------- + **Parameters:** x - coordinate vector name - coordinate vector ID - Returns - ------- - + **Returns:** + x, xsize -- dimension vector and its size """ @@ -615,34 +613,28 @@ def generic_wts_bnds(lat): def get_latitude_wts_bnds(checklatpass): """ - Routine: + **Routine:** get_latitude_wts_bnds - Purpose: + **Purpose:** Compare the passed checklatpass with the correct geophysical ones calculated here. After finding a match call the function to get the bounds. - Usage: + **Usage:** wts,bnds = get_latitude_wts_bnds(checklatpass) where - Parameters - ---------- - + **Parameters:** + checklatpass: is the grid to check + - N/A: - - None - - - Returns - ------- - + **Returns:** + wts, bnds - tuple with weights and bounds """ @@ -726,13 +718,13 @@ def get_latitude_wts_bnds(checklatpass): def latitude_bounds(lat_bnds): """ - Purpose: + **Purpose:** set up the shape and bounds for use by maparea - Usage: + **Usage:** - Returns: + **Returns:** tuple ( bn,bs ) @@ -753,22 +745,22 @@ def latitude_bounds(lat_bnds): def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): """ - Routine: + **Routine:** get_region_latitude_wts_bnds - Purpose: + **Purpose:** compare the passed latitudes, latRegion, with the global ones calculated here and extract the wts and bounds for the region - Usage: + **Usage:** wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) where latRegion is the regional grid to check - Returns : + **Returns:** wts, bnds - tuple with weights and bounds @@ -846,15 +838,15 @@ def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): """ - Purpose: + **Purpose:** construct the mask for the input data for use by rgdlength - Usage: + **Usage:** amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - Returns: + **Returns:** amskin @@ -1026,17 +1018,17 @@ def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): def sendmsg(msg, value1=None, value2=None): """ - Purpose: + **Purpose:** send the same message to the screen - Passed : + **Passed:** msg - the string value - the number associated with the string - Returns: + **Returns:** return @@ -1057,15 +1049,15 @@ def sendmsg(msg, value1=None, value2=None): def section(latvals, levvals): """ - Purpose: + **Purpose:** make the crossi section analytical test case - Passed : + **Passed:** the grid coordinate vectors - Returns: + **Returns:** xsection -- a temerature like cross section @@ -1093,17 +1085,17 @@ def section(latvals, levvals): def rmserror(data1, data2): """ - Purpose: + **Purpose:** compute the rms error for two data sets having the same shape - Passed: + **Passed:** the two data sets - Returns: + **Returns:** rms error diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 50a408a2..24524a21 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -78,7 +78,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """Set Cell connectivity - Parameters: + **Parameters:** cellIndices: @@ -94,7 +94,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellAreas area (volume) of each cell - Note: + **Note:** :: @@ -141,9 +141,8 @@ def setNodes(self, indices, coords, peOwners=None): """ Set the nodal coordinates - Parameters - ---------- - + **Parameters:** + indices - Ids of the nodes (0-based) @@ -166,14 +165,11 @@ def toVTK(self, filename): """ Write grid to VTK file format - Parameters - ---------- - + **Parameters:** + filename VTK file name - _: None - """ self.grid.write(filename) @@ -272,16 +268,13 @@ def getLocalSlab(self, staggerloc): Get the local slab (ellipsis). You can use this to grab the data local to this processor - Parameters - ---------- - : + **Parameters:** + staggerloc (e.g. ESMF.StaggerLoc.CENTER) - _: None - - Returns - ------- + + **Returns:** tuple of slices """ @@ -293,16 +286,13 @@ def getLoHiBounds(self, staggerloc): """ Get the local lo/hi index values for the coordinates (per processor) (hi is not inclusive, lo <= index < hi) - Parameters - ---------- - + **Parameters:** + staggerloc (e.g. ESMF.StaggerLoc.CENTER) - _: None - - Returns - ------- + + **Returns:** lo, hi lists """ @@ -314,16 +304,13 @@ def getCoordShape(self, staggerloc): """ Get the local coordinate shape (may be different on each processor) - Parameters - ---------- - + **Parameters:** + staggerloc (e.g. ESMF.StaggerLoc.CENTER) - _: None - - Returns - ------- + + **Returns:** tuple """ @@ -334,9 +321,8 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): """ Populate the grid with staggered coordinates (e.g. corner or center). - Parameters - ---------- - + **Parameters:** + coords The curvilinear coordinates of the grid. List of numpy arrays. Must exist on all procs. @@ -347,7 +333,7 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None - Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. + **Note:** coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. """ # allocate space for coordinates, can only add coordinates once for i in range(self.ndims): @@ -363,9 +349,8 @@ def getCoords(self, dim, staggerloc): """ Return the coordinates for a dimension - Parameters - --------- - + **Parameters:** + dim desired dimension (zero based indexing) @@ -380,13 +365,10 @@ def setCellAreas(self, areas): """ Set the cell areas - Parameters - ---------- - + **Parameters:** + areas numpy array - _: None - """ self.grid.add_item(item=ESMF.GridItem.Area) areaPtr = self.grid.get_item( @@ -398,9 +380,8 @@ def setCellAreas(self, areas): def getCellAreas(self): """ - Returns - ------- - + **Returns:** + cell areas or None if setCellAreas was not called """ if self.cellAreasSet: @@ -415,13 +396,13 @@ def getMask(self, staggerloc=CENTER): """ Get mask array. In ESMF, the mask is applied to cells. - Returns - ------- + **Returns:** + mask numpy array 1 is invalid by default - Note: This array exists on all procs + **Note:** This array exists on all procs """ try: maskPtr = self.grid.get_item( @@ -434,14 +415,13 @@ def setMask(self, mask, staggerloc=CENTER): """ Set mask array. In ESMF, the mask is applied to cells. - Returns - ---------- - + **Returns:** + mask numpy array 1 is invalid by default - Note: This array exists on all procs + **Note:** This array exists on all procs """ @@ -531,9 +511,8 @@ def getPointer(self): """ Get field data as a flat array - Returns - ------- - + **Returns:** + pointer """ return numpy.ravel(self.field.data) @@ -542,17 +521,14 @@ def getData(self, rootPe): """ Get field data as a numpy array - Parameters - ---------- - + **Parameters:** + rootPe if None then local data will be fetched, otherwise gather the data on processor "rootPe" (all other procs will return None). - _: None - - Returns - ------- - + + **Returns:** + numpy array or None """ ptr = self.getPointer() @@ -598,9 +574,8 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): """ Set local field data - Parameters - ---------- - + **Parameters:** + data full numpy array, this method will take care of setting a the subset of the data that reside on the local processor @@ -735,17 +710,14 @@ def getSrcAreas(self, rootPe): """ Get the src grid areas as used by conservative interpolation - Parameters - ---------- - + **Parameters:** + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - _: None - - Returns - ------- - + + **Returns:** + numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: @@ -756,17 +728,14 @@ def getDstAreas(self, rootPe): """ Get the dst grid areas as used by conservative interpolation - Parameters - ---------- - + **Parameters:** + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - _: None - - Returns - ------- - + + **Returns:** + numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: @@ -777,17 +746,14 @@ def getSrcAreaFractions(self, rootPe): """ Get the source grid fraction areas as used by conservative interpolation - Parameters - ---------- - + **Parameters:** + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered + - _: None - - Returns - ------- - + **Returns:** + numpy array """ if self.srcFracField is not None: @@ -799,17 +765,14 @@ def getDstAreaFractions(self, rootPe): """ Get the destination grid fraction areas as used by conservative interpolation - Parameters - ---------- - + **Parameters:** + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - _: None - - Returns - ------- + **Returns:** + numpy array """ if self.dstFracField is not None: diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index 5ddbef62..87f12047 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -378,15 +378,15 @@ def __init__(self, ingrid, outgrid): def input_mask(ain, type, mask, missing=None): """ - Purpose: + **Purpose:** set up the input mask including missing from ain - Usage: + **Usage:** - Passed : + **Passed:** - Returns: + **Returns:** """ diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 18c86989..1e388a91 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -222,9 +222,8 @@ def setCoords(self, srcGrid, dstGrid, """ Populator of grids, bounds and masks - Parameters - ---------- - + **Parameters:** + srcGrid list [[z], y, x] of source grid arrays diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 9b39480f..d5da987d 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -22,18 +22,12 @@ def guessPeriodicity(srcBounds): """ Guess if a src grid is periodic - Parameters - ---------- - + **Parameters:** + srcBounds - the nodal src set of coordinates - - _: None - - - Returns - ------- + the nodal src set of coordinates + **Returns:** 1 if periodic, warp around, 0 otherwise """ @@ -202,9 +196,8 @@ def apply(self, srcData, dstData, """ Regrid source to destination - Parameters - ---------- - + **Parameters:** + srcData array (input) @@ -350,9 +343,8 @@ def getDstGrid(self): Return the destination grid, may be different from the dst grid provided to the constructor due to domain decomposition - Returns - ------- - + **Returns:** + local grid on this processor """ return self.tool.getDstGrid() @@ -361,9 +353,8 @@ def fillInDiagnosticData(self, diag, rootPe=None): """ Fill in diagnostic data - Parameters - ---------- - + **Parameters:** + diag a dictionary whose entries, if present, will be filled entries are tool dependent diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py index a94fa3a7..2984148e 100644 --- a/regrid2/Lib/pressure.py +++ b/regrid2/Lib/pressure.py @@ -424,20 +424,26 @@ def rgrd(self, dataIn, missingValueIn, missingMatch, def checkorder(positionIn): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the tuples for transposing the data to standard dimension order and the - # inverse for transposing it back to the original dimension order - # - # usage: newOrder, inverseOrder = checkorder(positionIn) - # - # passed: positionIn -- array with location of longitude, latitude. level and time respectively - # in the sense of the python shape of the data - # - # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) - # inverseOrder -- tuple to transpose data to back to the original order - # - #----------------------------------------------------------------------------------------------""" + """ + **Purpose:** + + construct the tuples for transposing the data to standard dimension order and the inverse for transposing it back to the original dimension order + + **Usage:** + + newOrder, inverseOrder = checkorder(positionIn) + + **Passed:** + + positionIn -- array with location of longitude, latitude. level and time respectively in the sense of the python shape of the data + + **Returns:** + + newOrder -- tuple to transpose data to the order (t,z,y,x) + + inverseOrder -- tuple to transpose data to back to the original order + + """ # remove the None values from positionIn and reverse the order @@ -467,16 +473,22 @@ def checkorder(positionIn): def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" + """ + **Purpose:** + + send the same message to the screen + + **Passed:** + + msg - the string + + value - the number associated with the string + + **Returns:** + + return + + """ print('*******************************************************************') if value1 is None: diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 81c89a71..ccb37a5a 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -371,19 +371,15 @@ def regrid(self, input): def readRegridder(fileobj, mapMethod=None, checkGrid=1): """Read a regridder from an open fileobj. - Parameters - ---------- - - mapMethod - - is one of "conservative", "bilinear", "bicubic", or "distwgt". - - If unspecified, it defaults to the method defined in the file. + **Parameters:** + + mapMethod + is one of "conservative", "bilinear", "bicubic", or "distwgt". - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. + If unspecified, it defaults to the method defined in the file. - _: None + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. + """ if isinstance(fileobj, str): From 96cd85db483b001fb4c78d3b38723f2b23a61a09 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 18 Sep 2018 15:34:06 -0700 Subject: [PATCH 230/239] Changes to Section 1 and 2 --- docs/source/manual/cdms_2.rst | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index f4881530..59b23233 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -104,7 +104,8 @@ latitude, longitude). "5", "Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. This does not actually read the data." "6", "Read all January monthly mean data into a variable jans. * Variables can be sliced like arrays. - * The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. If the stride 12 were omitted, it would default to 1. + * The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. + * If the stride 12 were omitted, it would default to 1. **Note:** that the variable is actually 3-dimensional. * Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. * The slice operation could also have been written [0::12, : , :]. @@ -158,7 +159,7 @@ Table Cdms Module Functions * If ``s`` is already a transient variable, ``s`` is returned. * See also: ``isVariable``." "``Axis``", "``createAxis(data, bounds=None)``: - Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. + Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset. * ``data`` is a one-dimensional, monotonic Numpy array. * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i`` @@ -167,7 +168,8 @@ Table Cdms Module Functions * See ``setAutoBounds``. * Also see: ``CdmsFile.createAxis``" "``Axis``", "``createEqualAreaAxis(nlat)``: - Create an equal-area latitude axis. The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. + Create an equal-area latitude axis. + The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: @@ -180,7 +182,8 @@ Table Cdms Module Functions * ``xorigin`` is the origin of the longitude axis. * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)" "``RectGrid``", "``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``: - Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. + Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. + The grid is not associated with a file or dataset. * ``latArray`` is a NumPy array of latitude values. * ``lonArray`` is a NumPy array of longitude values. * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. @@ -188,12 +191,12 @@ Table Cdms Module Functions * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse. * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid." "``RectGrid``", "``createGlobalMeanGrid(grid)``: - Generate a grid for calculating the global mean via a regridding operation. - * The return grid is a single zone covering the range of he input grid. + Generate a grid for calculating the global mean via a regridding operation. + The return grid is a single zone covering the range of he input grid. * ``grid`` is a RectGrid." "``RectGrid``", "``createRectGrid(lat, lon, order, type='generic', mask=None)``: - Create a rectilinear grid, not associated with a file or dataset. - * This might be used as the target grid for a regridding operation. + Create a rectilinear grid, not associated with a file or dataset. + This might be used as the target grid for a regridding operation. * ``lat`` is a latitude axis, created by ``cdms.createAxis``. * ``lon`` is a longitude axis, created by ``cdms.createAxis``. * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). @@ -201,8 +204,8 @@ Table Cdms Module Functions * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``RectGrid``", "``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``: Create a uniform rectilinear grid. - * The grid is not associated with a file or dataset. - * The grid boundaries are at the midpoints of the axis values. + The grid is not associated with a file or dataset. + The grid boundaries are at the midpoints of the axis values. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``. @@ -214,16 +217,16 @@ Table Cdms Module Functions * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude). * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid." "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: - Create a uniform latitude axis. - * The axis boundaries are at the midpoints of the axis values. + Create a uniform latitude axis. + The axis boundaries are at the midpoints of the axis values. * The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." "``RectGrid``","``createZonalGrid(grid)``: - Create a zonal grid. - * The output grid has the same latitude as the input grid, and a single longitude. - * This may be used to calculate zonal averages via a regridding operation. + Create a zonal grid. + The output grid has the same latitude as the input grid, and a single longitude. + This may be used to calculate zonal averages via a regridding operation. * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: Create a uniform longitude axis. From 6de4bf7ef1d013ad0ef5cf31b00a4ebf6da86240 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 20 Sep 2018 15:23:16 -0700 Subject: [PATCH 231/239] Changes made to Section 2 --- docs/source/manual/cdms_2.rst | 39 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 59b23233..bf55624d 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -173,7 +173,7 @@ Table Cdms Module Functions * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: - Create a Gaussian latitude axis. Axis values range from north to south. + Create a Gaussian latitude axis. Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: @@ -219,7 +219,7 @@ Table Cdms Module Functions "``Axis``", "``createUniformLatitudeAxis(startLat , nlat, deltaLat)``: Create a uniform latitude axis. The axis boundaries are at the midpoints of the axis values. - * The axis is designated as a circular latitude axis. + The axis is designated as a circular latitude axis. * ``startLat`` is the starting latitude value. * ``nlat`` is the number of latitudes. * ``deltaLat`` is the increment between latitudes." @@ -230,11 +230,11 @@ Table Cdms Module Functions * ``grid`` is a RectGrid." "``Axis``", "``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: Create a uniform longitude axis. - * The axis boundaries are at the midpoints of the axis values. - * The axis is designated as a circular longitude axis. - * ``startLon`` is the starting longitude value. - * ``nlon`` is the number of longitudes. - * ``deltaLon`` is the increment between longitudes." + The axis boundaries are at the midpoints of the axis values. + The axis is designated as a circular longitude axis. + * ``startLon`` is the starting longitude value. + * ``nlon`` is the number of longitudes. + * ``deltaLon`` is the increment between longitudes." "``Variable``", "``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:" "``Integer``", "``getAutoBounds()``: Get the current autobounds mode. @@ -271,8 +271,8 @@ Table Cdms Module Functions * (name) meaning an axis whose id is name" "``None``", "``setAutoBounds(mode)``: Set autobounds mode. - In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. - The autobounds mode determines how this is done: + In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. + The autobounds mode determines how this is done: * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined. * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries. @@ -375,7 +375,8 @@ Table CoordinateAxis Types :header: "Type", "Definition" :widths: 20, 80 - "``CoordinateAxis``", "A variable that represents coordinate information. Has subtypes ``Axis2D`` and ``AuxAxis1D``." + "``CoordinateAxis``", "A variable that represents coordinate information. + * Has subtypes ``Axis2D`` and ``AuxAxis1D``." "``Axis``", "A one-dimensional coordinate axis whose values are strictly monotonic. * Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``. * May be an index axis, mapping a range of integers to the equivalent floating point value. @@ -461,14 +462,16 @@ Table CoordinateAxis Methods * If ``persistent`` is true, the external file or dataset (if any) is modified. * By default, the designation is temporary. * ``calendar`` is defined as in ``getCalendar()``." - "``Array``", "``getBounds()``", "Get the associated boundary array. The shape of the return array depends on the type of axis: + "``Array``", "``getBounds()``", "Get the associated boundary array. + The shape of the return array depends on the type of axis: * ``Axis``: ``(n,2)`` * ``Axis2D``: ``(i,j,4)`` * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell. If the boundary array of a latitude or longitude * ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. * Otherwise if auto-Bounds mode is off, the return value is ``None``. See ``setAutoBounds``." - "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. Possible return values, as defined in the ``cdtime`` module, are: + "``Integer``", "``getCalendar()``", "Returns the calendar associated with the ``(time)``\ axis. + Possible return values, as defined in the ``cdtime`` module, are: * ``cdtime.GregorianCalendar``: the standard Gregorian calendar * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar * ``cdtime.JulianCalendar``: years divisible by 4 are leap years @@ -524,7 +527,8 @@ Table Axis Methods, Additional to CoordinateAxis * ``'e'`` - same as n, but include an extra node on either side * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected. - * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. + * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. + * By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``. * An interval of ``None`` or ``':'`` returns the full index interval of the axis. * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty. * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)`` @@ -1659,7 +1663,8 @@ Table Variable Methods "List", "``getPaths(*intervals)``", "Get the file paths associated with the index region specified by intervals." "Integer", "``len(var)``", "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned. **Note:** ``size()`` returns the total number of elements." - "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. The variable must be a function of latitude, longitude, pressure level, and (optionally) time. + "Transient Variable", "``pressureRegrid (newLevel, method='log', missin=None, order=None)``", "Return the variable regridded to a new set of pressure levels newLevel. + The variable must be a function of latitude, longitude, pressure level, and (optionally) time. * ``newLevel`` is an axis of the result pressure levels. * ``method`` is optional, either 'log' to interpolate in the log of pressure (default), or 'linear' for linear interpolation. * ``missing`` is a missing data value. The default is ``var.getMissing()`` @@ -1680,7 +1685,8 @@ Table Variable Methods "``None``", "``setAxis(n, axis)``", "Set the n-th axis (0-origin index) of to a copy of axis." "``None``", "``setAxisList(axislist)``", "Set all axes of the variable. axislist is a list of axis objects." "``None``", "``setMissing(value)``", "Set the missing value. Integer ``size()`` Number of elements of the variable." - "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. A region is a hyperrectangle in coordinate space. + "Variable", "``subRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a coordinate region of data, returning a transient variable. + A region is a hyperrectangle in coordinate space. * ``region`` is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes. * If trailing dimensions are omitted, all values of those dimensions are retrieved. * If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension. @@ -1692,7 +1698,8 @@ Table Variable Methods * The optional keyword argument ``squeeze`` determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not 'squeezed out'. * The optional keyword argument ``raw`` specifies whether the return object is a variable or a masked array. * By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information." - "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. This is a functional form of the slice operator [] with the squeeze option turned off. + "Variable", "``subSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0)``", "Read a slice of data, returning a transient variable. + This is a functional form of the slice operator [] with the squeeze option turned off. * ``specs`` is an argument list, each element of which specifies a slice of the corresponding dimension. There can be zero or more positional arguments, each of the form: * a single integer n, meaning ``slice(n, n+1)`` From 241ff9fa7230222c2a3cf1ccc8741b4caf8e01fa Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 27 Sep 2018 15:25:53 -0700 Subject: [PATCH 232/239] Changes made to Sections 2 thru 6 --- docs/source/manual/cdms_2.rst | 497 +++++++++++++++++----------------- docs/source/manual/cdms_3.rst | 2 +- docs/source/manual/cdms_4.rst | 74 ++--- docs/source/manual/cdms_5.rst | 4 +- docs/source/manual/cdms_6.rst | 112 ++++---- 5 files changed, 345 insertions(+), 344 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index bf55624d..020bc748 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -55,7 +55,7 @@ Table PythonTypes used in CDMS "Array", "Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules." "Comptime", "Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime" - "Dictionary","An unordered 2,3collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" + "Dictionary","An unordered 2,3 collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``" "Float", "Floating-point value." "Integer", "Integer value." "List", "An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']``" @@ -173,7 +173,8 @@ Table Cdms Module Functions * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``Axis``", "``createGaussianAxis(nlat)``: - Create a Gaussian latitude axis. Axis values range from north to south. + Create a Gaussian latitude axis. + Axis values range from north to south. * ``nlat`` is the axis length. **Note:** The axis is not associated with a file or dataset." "``RectGrid``", "``createGaussianGrid(nlats, xorigin=0.0, order='yx')``: @@ -556,7 +557,7 @@ Table Axis Slice Operators **Example:** a longitude axis has value * ``[0.0, 2.0, ..., 358.0]`` * of length ``180`` - * map the coordinate interval: + Map the coordinate interval: * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval * ``-2 <= n < 3`` wraps around, since * ``-2 < 0``, and has a stride of ``1`` @@ -565,12 +566,12 @@ Table Axis Slice Operators Example 1 ''''''''''' -.. doctest:: +:: >>> axis.isCircular() - 1 + >>> 1 >>> axis.mapIntervalExt((-5.0,5.0,'co')) - (-2,3,1) + >>> (-2,3,1) @@ -629,13 +630,13 @@ Table CdmsFile Methods "``Variable``, ``Axis``, or ``Grid``", "``fileobj['id']``", "Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. **Example:** The following gets the persistent variable - * ``v``, equivalent to - * ``v = f.variables['prc']``. - * f = cdms.open('sample.nc') - * v = f['prc'] + >>> ``v``, equivalent to + >>> ``v = f.variables['prc']``. + >>> f = cdms.open('sample.nc') + >>> v = f['prc'] **Example:** The following gets the axis named time, equivalent to - * ``t = f.axes['time']``. - * ``t = f['time']``" + >>> ``t = f.axes['time']``. + >>> ``t = f['time']``" "``None``", "``close()``", "Close the file." "``Axis``", "``copyAxis(axis, newname=None)``", "Copy ``axis`` values and attributes to a new axis in the file. The returned object is persistent: it can be used to write axis data to or read axis data from the file. @@ -917,7 +918,7 @@ Searching a Database >>> (&(id = bmrc*)(project = AMIP2)) -matches all objects with id starting with bmrc, and a project attribute +Matches all objects with id starting with bmrc, and a project attribute with value ‘AMIP2’. Formally, search filters are strings defined as follows: @@ -953,9 +954,9 @@ several ways: :: - result = db.searchFilter('(&(category=obs*)(id=ncep*))') - for entry in result: - print entry.name + >>> result = db.searchFilter('(&(category=obs*)(id=ncep*))') + >>> for entry in result: + >>> print entry.name Search results can be narrowed using ``searchPredicate``. In the following example, the result of one search is itself searched for all @@ -1044,9 +1045,9 @@ In the next example, a portion of variable ‘ua’ is read from dataset :: - dset = db.open('ncep_reanalysis_mo') - ua = dset.variables['ua'] - data = ua[0,0] + >>> dset = db.open('ncep_reanalysis_mo') + >>> ua = dset.variables['ua'] + >>> data = ua[0,0] Examples of Database Searches @@ -1056,7 +1057,7 @@ In the following examples, db is the database opened with: :: - db = cdms.connect() + >>> db = cdms.connect() This defaults to the database defined in environment variable ``CDMSROOT``. @@ -1065,22 +1066,20 @@ This defaults to the database defined in environment variable :: - for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): - print entry.name + >>> for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): + >>> print entry.name **Example:** Find all axes with bounds defined: -:: - **Example:** Locate all GDT datasets: :: - for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): - print entry.name + >>> for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): + >>> print entry.name **Example:** Find all variables with missing time values, in observed datasets: @@ -1240,7 +1239,7 @@ MV can be imported with the command: :: - import MV + >>> import MV The command @@ -1620,9 +1619,9 @@ Table Variable Methods "Integer", "``getAxisIndex(axis_spec)``", "Return the index of the axis specificed by axis\_spec. Return -1 if no match. * ``axis_spec`` is a specification as defined for getAxisList" "List", "``getAxisList(axes=None, omit=None, order=None)``", "Get an ordered list of axis objects in the domain of the variable. - * If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given. - * If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below. - * ``order`` is an optional string determining the output order. + * If ``axes`` is not ``None``, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given. + * If ``omit`` is not ``None``, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below. + * ``order`` is an optional string determining the output order. Specifications for the axes or omit keywords are a list, each element having one of the following forms: * an integer dimension index, starting at 0. * a string representing an axis id or one of the strings 'time', 'latitude', 'lat', 'longitude', 'lon', 'lev' or 'level'. @@ -1723,7 +1722,7 @@ including+45.0, longitudes 0.0 through and including longitude 180.0: :: - data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) + >>> data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0)) or equivalently: @@ -1736,7 +1735,7 @@ Read all data for March, 1980: :: - data = ta.subRegion(time=('1980-3','1980-4','co')) + >>> data = ta.subRegion(time=('1980-3','1980-4','co')) @@ -1788,7 +1787,7 @@ variable. For example, the statement: :: - x = v(time='1979-1-1', level=(1000.0,100.0)) + >>> x = v(time='1979-1-1', level=(1000.0,100.0)) means ‘select the values of variable v for time ‘1979-1-1’ and levels @@ -1800,7 +1799,7 @@ The form for using a selector is: :: - result = v(s) + >>> result = v(s) where v is a variable and s is the selector. An equivalent form is: @@ -1819,7 +1818,7 @@ selector: :: - time='1979-1-1', level=(1000.0,100.0) + >>> time='1979-1-1', level=(1000.0,100.0) has two components: time=’1979-1-1’, and level=(1000.0,100.0). This @@ -1829,7 +1828,7 @@ the form: :: - keyword=value + >>> keyword=value Note that for the keywords time, level, latitude, and longitude, the @@ -1869,7 +1868,7 @@ example: :: - x9 = hus(('1979-1-1','1979-2-1'),1000.0) + >>> x9 = hus(('1979-1-1','1979-2-1'),1000.0) reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and @@ -1891,10 +1890,10 @@ takes an argument list of selector components. For example: >>> x1 = v1(sel) >>> x2 = v2(sel) - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x1 = v1(sel) - x2 = v2(sel) + >>> from cdms.selectors import Selector + >>> sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + >>> x1 = v1(sel) + >>> x2 = v2(sel) For convenience CDMS provides several predefined selectors, which can be @@ -1905,8 +1904,8 @@ to their keyword counterparts. For example: :: - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + >>> from cdms import time, level + >>> x = hus(time('1979-1-1','1979-2-1'), level(1000.)) and @@ -1932,12 +1931,12 @@ Finally, a collection of selectors is defined in module cdutil.region: :: - from cdutil.region import * - NH=NorthernHemisphere=domain(latitude=(0.,90.) - SH=SouthernHemisphere=domain(latitude=(-90.,0.)) - Tropics=domain(latitude=(-23.4,23.4)) - NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) - SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) + >>> from cdutil.region import * + >>> NH=NorthernHemisphere=domain(latitude=(0.,90.) + >>> SH=SouthernHemisphere=domain(latitude=(-90.,0.)) + >>> Tropics=domain(latitude=(-23.4,23.4)) + >>> NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.)) + >>> SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6)) Selectors can be combined using the & operator, or by refining them in @@ -1945,12 +1944,12 @@ the call: :: - from cdms.selectors import Selector - from cdms import level - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x1 = hus(sel3) - x2 = hus(sel2, level=1000.0) + >>> from cdms.selectors import Selector + >>> from cdms import level + >>> sel2 = Selector(time=('1979-1-1','1979-2-1')) + >>> sel3 = sel2 & level(1000.0) + >>> x1 = hus(sel3) + >>> x2 = hus(sel2, level=1000.0) @@ -1967,50 +1966,50 @@ remove the singleton level dimension from the result array. :: - import cdms - f = cdms.open('sample.nc') - hus = f.variables['hus'] - - # Keyword selection - x = hus(time=('1979-1-1','1979-2-1'), level=1000.) - - # Interval indicator (see mapIntervalExt) - x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) - - # Axis ID (plev) as a keyword - x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) - - # Positional - x9 = hus(('1979-1-1','1979-2-1'),1000.0) - - # Predefined selectors - from cdms import time, level - x = hus(time('1979-1-1','1979-2-1'), level(1000.)) - - from cdms import timeslice, levelslice - x = hus(timeslice(0,2), levelslice(16,17)) - - # Call file as a function - x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) - - # Python slices - x = hus(time=slice(0,2), level=slice(16,17)) - - # Selector objects - from cdms.selectors import Selector - sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) - x = hus(sel) - - sel2 = Selector(time=('1979-1-1','1979-2-1')) - sel3 = sel2 & level(1000.0) - x = hus(sel3) - x = hus(sel2, level=1000.0) - - # Squeeze singleton dimension (level) - x = hus[0:2,16] - x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) - - f.close() + >>> import cdms + >>> f = cdms.open('sample.nc') + >>> hus = f.variables['hus'] + >>> + >>> # Keyword selection + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000.) + >>> + >>> # Interval indicator (see mapIntervalExt) + >>> x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.) + >>> + >>> # Axis ID (plev) as a keyword + >>> x = hus(time=('1979-1-1','1979-2-1'), plev=1000.) + >>> + >>> # Positional + >>> x9 = hus(('1979-1-1','1979-2-1'),1000.0) + >>> + >>> # Predefined selectors + >>> from cdms import time, level + >>> x = hus(time('1979-1-1','1979-2-1'), level(1000.)) + >>> + >>> from cdms import timeslice, levelslice + >>> x = hus(timeslice(0,2), levelslice(16,17)) + >>> + >>> # Call file as a function + >>> x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.) + >>> + >>> # Python slices + >>> x = hus(time=slice(0,2), level=slice(16,17)) + >>> + >>> # Selector objects + >>> from cdms.selectors import Selector + >>> sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) + >>> x = hus(sel) + >>> + >>> sel2 = Selector(time=('1979-1-1','1979-2-1')) + >>> sel3 = sel2 & level(1000.0) + >>> x = hus(sel3) + >>> x = hus(sel2, level=1000.0) + >>> + >>> # Squeeze singleton dimension (level) + >>> x = hus[0:2,16] + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1) + >>> + >>> f.close() Examples @@ -2035,60 +2034,60 @@ results are written to a netCDF file. For brevity, the functions :: - 1. import cdms - import MV - - # Calculate variance, slope, and correlation of - # surface air temperature with upper air temperature - # by level, and save to a netCDF file. 'pathTa' is the location of - # the file containing 'ta', 'pathTas' is the file with contains 'tas'. - # Data is extracted from January of year1 through December of year2. - def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): - - # Open the files for ta and tas - fta = cdms.open(pathTa) - ftas = cdms.open(pathTas) - - 2. #Get upper air temperature - taObj = fta['ta'] - levs = taObj.getLevel() - - #Get the surface temperature for the closed interval [time1,time2] - tas = ftas('tas', time=(month1,month2,'cc')) - - # Allocate result arrays - newaxes = taObj.getAxisList(omit='time') - newshape = tuple([len(a) for a in newaxes]) - cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') - b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') - v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') - - # Remove seasonal cycle from surface air temperature - tas = removeSeasonalCycle(tas) - - # For each level of air temperature, remove seasonal cycle - # from upper air temperature, and calculate statistics - 5. for ilev in range(len(levs)): - - ta = taObj(time=(month1,month2,'cc'), \ - level=slice(ilev, ilev+1), squeeze=1) - ta = removeSeasonalCycle(ta) - cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) - v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) - - # Write slope, correlation, and variance variables - 6. f = cdms.open('CC_B_V_ALL.nc','w') - f.title = filtered - f.write(b) - f.write(cc) - f.write(v) - f.close() - - 7. if __name__=='__main__': - pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' - pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' - # Process Jan80 through Dec81 - ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') + >>> 1. import cdms + >>> import MV + >>> + >>> # Calculate variance, slope, and correlation of + >>> # surface air temperature with upper air temperature + >>> # by level, and save to a netCDF file. 'pathTa' is the location of + >>> # the file containing 'ta', 'pathTas' is the file with contains 'tas'. + >>> # Data is extracted from January of year1 through December of year2. + >>> def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2): + >>> + >>> # Open the files for ta and tas + >>> fta = cdms.open(pathTa) + >>> ftas = cdms.open(pathTas) + >>> + >>> 2. #Get upper air temperature + >>> taObj = fta['ta'] + >>> levs = taObj.getLevel() + >>> + >>> #Get the surface temperature for the closed interval [time1,time2] + >>> tas = ftas('tas', time=(month1,month2,'cc')) + >>> + >>> # Allocate result arrays + >>> newaxes = taObj.getAxisList(omit='time') + >>> newshape = tuple([len(a) for a in newaxes]) + >>> cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation') + >>> b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope') + >>> v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance') + >>> + >>> # Remove seasonal cycle from surface air temperature + >>> tas = removeSeasonalCycle(tas) + >>> + >>> # For each level of air temperature, remove seasonal cycle + >>> # from upper air temperature, and calculate statistics + >>> 5. for ilev in range(len(levs)): + >>> + >>> ta = taObj(time=(month1,month2,'cc'), \ + >>> level=slice(ilev, ilev+1), squeeze=1) + >>> ta = removeSeasonalCycle(ta) + >>> cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + >>> v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + >>> + >>> # Write slope, correlation, and variance variables + >>> 6. f = cdms.open('CC_B_V_ALL.nc','w') + >>> f.title = filtered + >>> f.write(b) + >>> f.write(cc) + >>> f.write(v) + >>> f.close() + >>> + >>> 7. if __name__=='__main__': + >>> pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' + >>> pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' + >>> # Process Jan80 through Dec81 + >>> ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12') **Notes:** @@ -2123,108 +2122,108 @@ the vcs module. :: - #!/usr/bin/env python - # - # Calculates gridpoint total variance - # from an array of interest - # - - import cdms - from MV import * - - # Wait for return in an interactive window - - def pause(): - print Hit return to continue: , - line = sys.stdin.readline() - - 1. # Calculate pointwise variance of variable over time - # Returns the variance and the number of points - # for which the data is defined, for each grid point - def calcVar(x): - # Check that the first axis is a time axis - firstaxis = x.getAxis(0) - if not firstaxis.isTime(): - raise 'First axis is not time, variable:', x.id - - n = count(x,0) - sumxx = sum(x*x) - sumx = sum(x) - variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) - - return variance, n - - if __name__=='__main__': - import vcs, sys - - print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', - path = string.strip(sys.stdin.readline()) - if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' - - 2. # Open the dataset - dataset = cdms.open(path) - - # Select a variable from the dataset - print 'Variables in file:',path - varnames = dataset.variables.keys() - varnames.sort() - for varname in varnames: - - var = dataset.variables[varname] - if hasattr(var,'long_name'): - long_name = var.long_name - elif hasattr(var,'title'): - long_name = var.title - else: - long_name = '?' - - print '%-10s: %s'%(varname,long_name) - print 'Select a variable: ', - 3. varname = string.strip(sys.stdin.readline()) - var = dataset(varname) - dataset.close() - - # Calculate variance, count, and set attributes - variance,n = calcVar(var) - variance.id = 'variance_%s'%var.id - n.id = 'count_%s'%var.id - if hasattr(var,'units'): - variance.units = '(%s)^2'%var.units - - # Plot variance - w=vcs.init() - 4. w.plot(variance) - pause() - w.clear() - w.plot(n) - pause() - w.clear() + >>> #!/usr/bin/env python + >>> # + >>> # Calculates gridpoint total variance + >>> # from an array of interest + >>> # + >>> + >>> import cdms + >>> from MV import * + >>> + >>> # Wait for return in an interactive window + >>> + >>> def pause(): + >>> print Hit return to continue: , + >>> line = sys.stdin.readline() + >>> + >>> 1. # Calculate pointwise variance of variable over time + >>> # Returns the variance and the number of points + >>> # for which the data is defined, for each grid point + >>> def calcVar(x): + >>> # Check that the first axis is a time axis + >>> firstaxis = x.getAxis(0) + >>> if not firstaxis.isTime(): + >>> raise 'First axis is not time, variable:', x.id + >>> + >>> n = count(x,0) + >>> sumxx = sum(x*x) + >>> sumx = sum(x) + >>> variance = (n*sumxx -(sumx * sumx))/(n * (n-1.)) + >>> + >>> return variance, n + >>> + >>> if __name__=='__main__': + >>> import vcs, sys + >>> + >>> print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ', + >>> path = string.strip(sys.stdin.readline()) + >>> if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml' + >>> + >>> 2. # Open the dataset + >>> dataset = cdms.open(path) + >>> + >>> # Select a variable from the dataset + >>> print 'Variables in file:',path + >>> varnames = dataset.variables.keys() + >>> varnames.sort() + >>> for varname in varnames: + >>> + >>> var = dataset.variables[varname] + >>> if hasattr(var,'long_name'): + >>> long_name = var.long_name + >>> elif hasattr(var,'title'): + >>> long_name = var.title + >>> else: + >>> long_name = '?' + >>> + >>> print '%-10s: %s'%(varname,long_name) + >>> print 'Select a variable: ', + >>> 3. varname = string.strip(sys.stdin.readline()) + >>> var = dataset(varname) + >>> dataset.close() + >>> + >>> # Calculate variance, count, and set attributes + >>> variance,n = calcVar(var) + >>> variance.id = 'variance_%s'%var.id + >>> n.id = 'count_%s'%var.id + >>> if hasattr(var,'units'): + >>> variance.units = '(%s)^2'%var.units + >>> + >>> # Plot variance + >>> w=vcs.init() + >>> 4. w.plot(variance) + >>> pause() + >>> w.clear() + >>> w.plot(n) + >>> pause() + >>> w.clear() The result of running this script is as follows: :: - % calcVar.py - Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: - - Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml - albt : Albedo TOA [%] - albtcs : Albedo TOA clear sky [%] - rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] - rlut : LW radiation TOA (OLR) [W/m^2] - rlutcs : LW radiation upward TOA clear sky [W/m^2] - rscrft : SW Cloud Radiation Forcing TOA [W/m^2] - rsdt : SW radiation downward TOA [W/m^2] - rsut : SW radiation upward TOA [W/m^2] - rsutcs : SW radiation upward TOA clear sky [W/m^2] - Select a variable: albt - - - - Hit return to continue: - - + >>> % calcVar.py + >>> Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]: + >>> + >>> Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml + >>> albt : Albedo TOA [%] + >>> albtcs : Albedo TOA clear sky [%] + >>> rlcrft : LW Cloud Radiation Forcing TOA [W/m^2] + >>> rlut : LW radiation TOA (OLR) [W/m^2] + >>> rlutcs : LW radiation upward TOA clear sky [W/m^2] + >>> rscrft : SW Cloud Radiation Forcing TOA [W/m^2] + >>> rsdt : SW radiation downward TOA [W/m^2] + >>> rsut : SW radiation upward TOA [W/m^2] + >>> rsutcs : SW radiation upward TOA clear sky [W/m^2] + >>> Select a variable: albt + >>> + >>> + >>> + >>> Hit return to continue: + >>> + >>> **Notes:** diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index 4af4e7a7..b1da3c40 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -147,7 +147,7 @@ Table Time Methods Examples ^^^^^^^^ -.. doctest:: +:: >>> from cdtime import * >>> c = comptime(1996,2,28) diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 51322ea9..7b8c0883 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -39,7 +39,7 @@ grid to another is to use the regrid function defined for variables. This function takes the target grid as an argument, and returns the variable regridded to the target grid: -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" @@ -72,7 +72,7 @@ of an MV2.MaskedArray. The steps in this process are: The following example illustrates this process. The regridder function is generated at line 9, and the regridding is performed at line 10: -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" @@ -157,22 +157,22 @@ In this example: :: - &remap_inputs - num_maps = 1 - - grid1_file = 'remap_grid_T42.nc' - grid2_file = 'remap_grid_POP43.nc' - interp_file1 = 'rmp_T42_to_POP43_conserv.nc' - interp_file2 = 'rmp_POP43_to_T42_conserv.nc' - map1_name = 'T42 to POP43 Conservative Mapping' - map2_name = 'POP43 to T42 Conservative Mapping' - map_method = 'conservative' - normalize_opt = 'frac' - output_opt = 'scrip' - restrict_type = 'latitude' - num_srch_bins = 90 - luse_grid1_area = .false. - luse_grid2_area = .false. + >>> &remap_inputs + >>> num_maps = 1 + >>> + >>> grid1_file = 'remap_grid_T42.nc' + >>> grid2_file = 'remap_grid_POP43.nc' + >>> interp_file1 = 'rmp_T42_to_POP43_conserv.nc' + >>> interp_file2 = 'rmp_POP43_to_T42_conserv.nc' + >>> map1_name = 'T42 to POP43 Conservative Mapping' + >>> map2_name = 'POP43 to T42 Conservative Mapping' + >>> map_method = 'conservative' + >>> normalize_opt = 'frac' + >>> output_opt = 'scrip' + >>> restrict_type = 'latitude' + >>> num_srch_bins = 90 + >>> luse_grid1_area = .false. + >>> luse_grid2_area = .false. ``num_maps`` specifies the number of mappings generated, either 1 or 2. @@ -188,20 +188,20 @@ generate the remapping file ‘rmp\_T42\_to\_POP43\_conserv.nc’ :: - % scrip - Using latitude bins to restrict search. - Computing remappings between: - T42 Gaussian Grid - and - POP 4/3 Displaced-Pole T grid - grid1 sweep - grid2 sweep - Total number of links = 63112 + >>> % scrip + >>> Using latitude bins to restrict search. + >>> Computing remappings between: + >>> T42 Gaussian Grid + >>> and + >>> POP 4/3 Displaced-Pole T grid + >>> grid1 sweep + >>> grid2 sweep + >>> Total number of links = 63112 Next, run CDAT and create the regridder: -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" @@ -217,7 +217,7 @@ Next, run CDAT and create the regridder: Then read the input data and regrid: -.. doctest:: +:: >>> # Get the source variable >>> f = cdms2.open('xieArkin-T42.nc') @@ -241,7 +241,7 @@ use the ``pressureRegrid`` function defined for variables. This function takes an axis representing the target set of pressure levels, and returns a new variable ``d`` regridded to that dimension. -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") @@ -587,13 +587,13 @@ Generate an array of zonal mean values. .. doctest:: - >>> f = cdms.open(‘rls_ccc_per.nc’) - >>> rlsf = f.variables[‘rls’] - >>> ingrid = rlsf.getGrid() - >>> outgrid = cdms.createZonalGrid(ingrid) - >>> regridFunc = Regridder(ingrid,outgrid) - >>> mean = regridFunc(rlsf) - >>> f.close() + >>> f = cdms.open(‘rls_ccc_per.nc’) + >>> rlsf = f.variables[‘rls’] + >>> ingrid = rlsf.getGrid() + >>> outgrid = cdms.createZonalGrid(ingrid) + >>> regridFunc = Regridder(ingrid,outgrid) + >>> mean = regridFunc(rlsf) + >>> f.close() diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index efa8c964..0edffd37 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -42,8 +42,10 @@ Plotting a Gridded Variable os.remove(file) +**Example:** + Plotting a gridded variable -.. doctest:: Example: plotting a gridded variable +.. doctest:: >>> import cdms2, vcs >>> f = cdms2.open("clt.nc") diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 49579fd9..59cbf22e 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -448,62 +448,62 @@ Dataset "sample" has two variables, and six axes. :: - - - [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. - - 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 - - 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 - - 303.75 315. 326.25 337.5 348.75] - - - - - [ 0. 366. 731.] - - - - - - - - - - - - - - - - - - - {% endhighlight %} + >>> >> id ="longitude" + >>> length="32" + >>> units="degrees_east" + >>> datatype="Double" + >>> > + >>> + >>> [ 0. 11.25 22.5 33.75 45. 56.25 67.5 78.75 90. + >>> + >>> 101.25 112.5 123.75 135. 146.25 157.5 168.75 180. 191.25 + >>> + >>> 202.5 213.75 225. 236.25 247.5 258.75 270. 281.25 292.5 + >>> + >>> 303.75 315. 326.25 337.5 348.75] + >>> + >>> + >>> >> id ="time" + >>> partition="[0 1 1 2 2 3]" + >>> calendar="gregorian" + >>> units="days since 2000-1-1" + >>> datatype="Double" + >>> length="3" + >>> name_in_file="time" + >>> > + >>> + >>> [ 0. 366. 731.] + >>> + >>> + >>> >> id ="u" + >>> missing_value="-99.9" + >>> units="m/s" + >>> datatype="Double" + >>> > + >>> + >>> + >>> + >>> + >>> + >>> + >>> + >>> >> id ="v" + >>> missing_value="-99.9" + >>> units="m/s" + >>> datatype="Double" + >>> > + >>> + >>> + >>> + >>> + >>> + >>> + >>> + >>> {% endhighlight %} From 085b28cc033ce91230903e196006f77d1fde0985 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 4 Oct 2018 15:24:21 -0700 Subject: [PATCH 233/239] Changes made to Chapters 3 and 6 --- docs/source/manual/cdms_3.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index b1da3c40..cd5680e9 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -126,23 +126,26 @@ Table Time Methods :widths: 20, 75, 80 :align: left - "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. Returns the same type of time. + "Comptime or Reltime", "``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``", "Add an interval of time to a time type t. + Returns the same type of time. * ``value`` is the Float number of interval units. * ``intervalUnits`` is ``cdtime. * [Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]`` * ``calendar`` is the calendar type." - "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively. + "Integer", "``t.cmp(t2, calendar=cdtime.DefaultCalendar)``", "Compare time values t and t2. + Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively. * ``t2`` is the time to compare. * ``calendar`` is the calendar type." - "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. Returns the same type of time. + "Comptime or Reltime", "``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``", "Subtract an interval of time from a time type t. + Returns the same type of time. * ``value`` is the Float number of interval units. * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)] * ``calendar`` is the calendar type. " "Comptime", "``t.tocomp(calendar = cdtime.DefaultCalendar)``", "Convert to component time. - * Returns the equivalent component time. + Returns the equivalent component time. * ``calendar`` is the calendar type." "Reltime", "``t.torel(units, calendar=cdtime.DefaultCalendar)``", "Convert to relative time. - * Returns the equivalent relative time." + Returns the equivalent relative time." Examples From 451a012591ecaf459b0ed8d18a89bb658fe0e671 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 18 Oct 2018 15:16:50 -0700 Subject: [PATCH 234/239] add jupyter notebook --- chapter1.ipynb | 1977 +++++++++++++++++++++ chapter2.ipynb | 3017 +++++++++++++++++++++++++++++++++ chapter3.ipynb | 392 +++++ chapter4.ipynb | 1029 +++++++++++ chapter5.ipynb | 320 ++++ docs/source/manual/cdms_1.rst | 2 +- 6 files changed, 6736 insertions(+), 1 deletion(-) create mode 100644 chapter1.ipynb create mode 100644 chapter2.ipynb create mode 100644 chapter3.ipynb create mode 100644 chapter4.ipynb create mode 100644 chapter5.ipynb diff --git a/chapter1.ipynb b/chapter1.ipynb new file mode 100644 index 00000000..c4c4ee9b --- /dev/null +++ b/chapter1.ipynb @@ -0,0 +1,1977 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Overview\n", + "\n", + "The Community Data Management System is an object-oriented data management\n", + "system, specialized for organizing multidimensional, gridded data used\n", + "in climate analysis and simulation. \n", + "\n", + "CDMS is implemented as part of the Climate Data\n", + "Analysis Tool (CDAT), which uses the Python language. The examples in\n", + "this chapter assume some familiarity with the language and the Python\n", + "Numpy module (https://www.numpy.org). A number of excellent tutorials\n", + "on Python are available in books or on the Internet. For example, see\n", + "the `Python Foundation's homepage `__.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Variables\n", + "\n", + "The basic unit of computation in CDMS is the variable. A variable is essentially a multidimensional data array, augmented with a domain, a set of attributes, and optionally a spatial and/or temporal coordinate system [(see Coordinate Axes)](https://cdms.readthedocs.io/en/readthedocstest/manual/cdms_1.html#coordinate-axes). As a data array, a variable can\n", + "be sliced to obtain a portion of the data, and can be used in arithmetic\n", + "computations. For example, if ``u`` and ``v`` are variables representing\n", + "the eastward and northward components of wind speed, respectively, and\n", + "both variables are functions of time, latitude, and longitude, then the\n", + "velocity for time 0 (first index) can be calculated as:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2\n", + "from cdms2 import MV" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "# wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "f1=cdms2.open(\"clt.nc\")\n", + "u = f1('u')\n", + "v = f1('v')\n", + "from cdms2 import MV" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2018-10-17 10:40:26-- https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 1718908 (1.6M) [application/x-netcdf]\n", + "Saving to: “clt.nc.10”\n", + "\n", + "100%[======================================>] 1,718,908 --.-K/s in 0.02s \n", + "\n", + "2018-10-17 10:40:26 (84.3 MB/s) - “clt.nc.10” saved [1718908/1718908]\n", + "\n", + "[[[3.6092278957366943 3.548424005508423 3.4843790531158447 ...\n", + " 3.7187933921813965 3.6662113666534424 3.6092278957366943]\n", + " [4.482813358306885 4.336821556091309 4.194543838500977 ...\n", + " 4.773476600646973 4.629714488983154 4.482813358306885]\n", + " [4.675872802734375 4.467889785766602 4.299487590789795 ...\n", + " 5.208128452301025 4.9245829582214355 4.675872802734375]\n", + " ...\n", + " [14.2416353225708 14.323187828063965 14.379049301147461 ...\n", + " 14.00051212310791 14.134027481079102 14.2416353225708]\n", + " [12.480237007141113 12.524213790893555 12.552382469177246 ...\n", + " 12.346633911132812 12.420877456665039 12.480237007141113]\n", + " [10.413312911987305 10.42257308959961 10.425800323486328 ...\n", + " 10.377242088317871 10.39814567565918 10.413312911987305]]\n", + "\n", + " [[-- -- -- ... -- -- --]\n", + " [-- -- -- ... -- -- --]\n", + " [2.4196360111236572 2.2428698539733887 2.099884510040283 ... -- --\n", + " 2.4196360111236572]\n", + " ...\n", + " [2.685023307800293 2.349280834197998 2.100950002670288 ...\n", + " 3.5292885303497314 3.0855724811553955 2.685023307800293]\n", + " [3.2643380165100098 3.098647117614746 2.9637553691864014 ...\n", + " 3.6760590076446533 3.4581825733184814 3.2643380165100098]\n", + " [3.7221627235412598 3.6456055641174316 3.5727615356445312 ...\n", + " 3.8849072456359863 3.8020851612091064 3.7221627235412598]]]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3169: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " dout = self.data[indx]\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3201: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " mout = _mask[indx]\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:6652: RuntimeWarning: overflow encountered in power\n", + " result = np.where(m, fa, umath.power(fa, fb)).view(basetype)\n" + ] + } + ], + "source": [ + "!wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "f1= cdms2.open(\"clt.nc\")\n", + "u = f1('u')\n", + "v = f1('v')\n", + "\n", + "vel = MV.sqrt(u[0]**2 + v[0]**2)\n", + "print vel\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This illustrates several points:\n", + "\n", + "- Square brackets represent the slice operator. Indexing starts at 0,\n", + " so ``u[0]`` selects from variable ``u`` for the first timepoint. The\n", + " result of this slice operation is another variable. The slice\n", + " operator can be multidimensional, and follows the syntax of Numpy\n", + " Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data\n", + " for the first ten timepoints, at all latitudes, for the second\n", + " longitude.\n", + "- Variables can be used in computation. ``**`` is the Python\n", + " exponentiation operator.\n", + "- Arithmetic functions are defined in the ``cdms2.MV2`` module.\n", + "- Operations on variables carry along the corresponding metadata where\n", + " applicable. In the above example, ``vel`` has the same latitude and\n", + " longitude coordinates as ``u`` and ``v``, and the time coordinate is\n", + " the first time of ``u`` and ``v``." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "File I/O\n", + "\n", + "\n", + "A variable can be obtained from a file or collection of files, or can be\n", + "generated as the result of a computation. Files can be in any of the\n", + "self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS\n", + "control file), or PCMDI DRS. (HDF and DRS support is optional, and is\n", + "configured at the time CDAT is installed.) For instance, to read data\n", + "from file sample.nc into variable u:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "# wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "f = cdms2.open('clt.nc')\n", + "u = f('u')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Data can be read by index or by world coordinate values. The following reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k such that i <= k < j):" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "n = 0\n", + "u0 = f('u',time=slice(n,n+1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To read u at time 1.:" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "can't assign to literal (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1 = f('u',time=1.)\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to literal\n" + ] + } + ], + "source": [ + "1 = f('u',time=1.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A variable can be written to a file with the write function:" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "g = cdms2.open('sample2.nc','w')\n", + "g.write(u) \n", + "\n", + "g.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Coordinate Axes\n", + "\n", + "\n", + "A coordinate axis is a variable that represents coordinate information.\n", + "Typically an axis is associated with one or more variables in a file or\n", + "dataset, to represent the indexing and/or spatiotemporal coordinate\n", + "system(s) of the variable(s).\n", + "\n", + "Often in climate applications an axis is a one-dimensional variable\n", + "whose values are floating-point and strictly monotonic. In some cases an\n", + "axis can be multidimensional (see `Grids <#grids>`__). If an axis is\n", + "associated with one of the canonical types latitude, longitude, level,\n", + "or time, then the axis is called temporal .\n", + "\n", + "The shape and physical ordering of a variable is represented by the\n", + "variables domain , an ordered tuple of one-dimensional axes. In the\n", + "previous example, the domain of the variable u is the tuple (time,\n", + "latitude, longitude). This indicates the order of the dimensions, with\n", + "the slowest-varying dimension listed first (time). The domain may be\n", + "accessed with the ``getAxisList()`` method:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ id: time1\n", + " Designated a time axis.\n", + " units: months since 1978-12\n", + " Length: 1\n", + " First: 1.0\n", + " Last: 1.0\n", + " Other axis attributes:\n", + " calendar: gregorian\n", + " axis: T\n", + " Python id: 0x7f1067d00510, id: plev\n", + " Designated a level axis.\n", + " units: hPa\n", + " Length: 2\n", + " First: 200.0\n", + " Last: 850.0\n", + " Other axis attributes:\n", + " axis: Z\n", + " realtopology: linear\n", + " Python id: 0x7f108452bd90, id: latitude1\n", + " Designated a latitude axis.\n", + " units: degrees_north\n", + " Length: 80\n", + " First: -88.2884\n", + " Last: 88.2884\n", + " Other axis attributes:\n", + " axis: Y\n", + " realtopology: linear\n", + " Python id: 0x7f108452bc10, id: longitude1\n", + " Designated a longitude axis.\n", + " units: degrees_east\n", + " Length: 97\n", + " First: -180.0\n", + " Last: 180.0\n", + " Other axis attributes:\n", + " axis: X\n", + " topology: circular\n", + " modulo: 360.0\n", + " realtopology: linear\n", + " Python id: 0x7f108452bed0]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u.getAxisList() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above example, the domain elements are axes that are also\n", + "spatiotemporal. In general it is not always the case that an element of\n", + "a domain is spatiotemporal:\n", + "\n", + "- An axis in the domain of a variable need not be spatiotemporal. For\n", + " example, it may represent a range of indices, an index coordinate\n", + " system.\n", + "- The latitude and/or longitude coordinate axes associated with a\n", + " variable need not be elements of the domain. In particular this will\n", + " be true if the variable is defined on a non-rectangular grid (see `Grids <#grids>`__).\n", + "\n", + "As previously noted, a spatial and/or temporal coordinate system may be\n", + "associated with a variable. The methods getLatitude, getLongitude,\n", + "getLevel, and getTime return the associated coordinate axes. For\n", + "example:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1.]\n", + "months since 1978-12\n" + ] + } + ], + "source": [ + "t = u.getTime()\n", + "print t[:]\n", + "\n", + "print t.units" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Attributes\n", + "\n", + "As mentioned above, variables can have associated attributes ,\n", + "name-value pairs. In fact, nearly all CDMS objects can have associated\n", + "attributes, which are accessed using the Python dot notation:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "m/s\n" + ] + } + ], + "source": [ + "u.units='m/s'\n", + "print u.units" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Attribute values can be strings, scalars, or 1-D Numpy arrays.\n", + "\n", + "When a variable is written to a file, not all the attributes are\n", + "written. Some attributes, called internal attributes, are used for\n", + "bookkeeping, and are not intended to be part of the external file\n", + "representation of the variable. In contrast, external attributes are\n", + "written to an output file along with the variable. By default, when an\n", + "attribute is set, it is treated as external. Every variable has a field\n", + "attributes, a Python dictionary that defines the external attributes:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type']\n" + ] + } + ], + "source": [ + "print u.attributes.keys()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Python dir command lists the internal attribute names:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['T',\n", + " '_FillValue',\n", + " '_TransientVariable__domain',\n", + " '_TransientVariable__getMPIType',\n", + " '_TransientVariable__getSlab',\n", + " '_TransientVariable__mpiComm',\n", + " '_TransientVariable__mpiType',\n", + " '_TransientVariable__mpiWindows',\n", + " '___cdms_internals__',\n", + " '__abs__',\n", + " '__add__',\n", + " '__and__',\n", + " '__array__',\n", + " '__array_finalize__',\n", + " '__array_interface__',\n", + " '__array_prepare__',\n", + " '__array_priority__',\n", + " '__array_struct__',\n", + " '__array_ufunc__',\n", + " '__array_wrap__',\n", + " '__call__',\n", + " '__cdms_internals__',\n", + " '__class__',\n", + " '__complex__',\n", + " '__contains__',\n", + " '__copy__',\n", + " '__deepcopy__',\n", + " '__delattr__',\n", + " '__delitem__',\n", + " '__dict__',\n", + " '__div__',\n", + " '__divmod__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__float__',\n", + " '__floordiv__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getitem__',\n", + " '__getslice__',\n", + " '__getstate__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__hex__',\n", + " '__iadd__',\n", + " '__iand__',\n", + " '__idiv__',\n", + " '__ifloordiv__',\n", + " '__ilshift__',\n", + " '__imod__',\n", + " '__imul__',\n", + " '__index__',\n", + " '__init__',\n", + " '__int__',\n", + " '__invert__',\n", + " '__ior__',\n", + " '__ipow__',\n", + " '__irshift__',\n", + " '__isub__',\n", + " '__iter__',\n", + " '__itruediv__',\n", + " '__ixor__',\n", + " '__le__',\n", + " '__len__',\n", + " '__long__',\n", + " '__lshift__',\n", + " '__lt__',\n", + " '__mod__',\n", + " '__module__',\n", + " '__mul__',\n", + " '__ne__',\n", + " '__neg__',\n", + " '__new__',\n", + " '__nonzero__',\n", + " '__oct__',\n", + " '__or__',\n", + " '__pos__',\n", + " '__pow__',\n", + " '__radd__',\n", + " '__rand__',\n", + " '__rdiv__',\n", + " '__rdivmod__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__rfloordiv__',\n", + " '__rlshift__',\n", + " '__rmod__',\n", + " '__rmul__',\n", + " '__ror__',\n", + " '__rpow__',\n", + " '__rrshift__',\n", + " '__rshift__',\n", + " '__rsub__',\n", + " '__rtruediv__',\n", + " '__rxor__',\n", + " '__setattr__',\n", + " '__setitem__',\n", + " '__setmask__',\n", + " '__setslice__',\n", + " '__setstate__',\n", + " '__sizeof__',\n", + " '__sqrt__',\n", + " '__str__',\n", + " '__sub__',\n", + " '__subclasshook__',\n", + " '__truediv__',\n", + " '__unicode__',\n", + " '__weakref__',\n", + " '__xor__',\n", + " '_baseclass',\n", + " '_basedict',\n", + " '_comparison',\n", + " '_data',\n", + " '_decodedType',\n", + " '_defaulthardmask',\n", + " '_defaultmask',\n", + " '_delegate_binop',\n", + " '_fill_value',\n", + " '_getShape',\n", + " '_get_data',\n", + " '_get_flat',\n", + " '_get_mask',\n", + " '_get_recordmask',\n", + " '_getinternals',\n", + " '_getmissing',\n", + " '_grid_',\n", + " '_hardmask',\n", + " '_insert_masked_print',\n", + " '_isfield',\n", + " '_listatts',\n", + " '_mask',\n", + " '_missing',\n", + " '_node_',\n", + " '_optinfo',\n", + " '_print_width',\n", + " '_print_width_1d',\n", + " '_process_specs',\n", + " '_returnArray',\n", + " '_set_flat',\n", + " '_set_mask',\n", + " '_set_recordmask',\n", + " '_setatts',\n", + " '_setinternals',\n", + " '_setmissing',\n", + " '_sharedmask',\n", + " '_single_specs',\n", + " '_update_from',\n", + " 'all',\n", + " 'anom',\n", + " 'any',\n", + " 'argmax',\n", + " 'argmin',\n", + " 'argpartition',\n", + " 'argsort',\n", + " 'ascontiguous',\n", + " 'ascontiguousarray',\n", + " 'asma',\n", + " 'assignValue',\n", + " 'astype',\n", + " 'attributes',\n", + " 'base',\n", + " 'baseclass',\n", + " 'byteswap',\n", + " 'choose',\n", + " 'clip',\n", + " 'clone',\n", + " 'compress',\n", + " 'compressed',\n", + " 'conj',\n", + " 'conjugate',\n", + " 'copy',\n", + " 'copyAxis',\n", + " 'copyDomain',\n", + " 'copydimension',\n", + " 'count',\n", + " 'createattribute',\n", + " 'crossSectionRegrid',\n", + " 'ctypes',\n", + " 'cumprod',\n", + " 'cumsum',\n", + " 'data',\n", + " 'date',\n", + " 'decode',\n", + " 'deleteattribute',\n", + " 'diagonal',\n", + " 'dot',\n", + " 'dtype',\n", + " 'dump',\n", + " 'dumps',\n", + " 'expertSlice',\n", + " 'exposeHalo',\n", + " 'fetchHaloData',\n", + " 'fill',\n", + " 'fill_value',\n", + " 'filled',\n", + " 'flags',\n", + " 'flat',\n", + " 'flatten',\n", + " 'freeHalo',\n", + " 'generateGridkey',\n", + " 'generateRectGridkey',\n", + " 'getAxis',\n", + " 'getAxisIds',\n", + " 'getAxisIndex',\n", + " 'getAxisList',\n", + " 'getAxisListIndex',\n", + " 'getConvention',\n", + " 'getDomain',\n", + " 'getForecast',\n", + " 'getForecastTime',\n", + " 'getGrid',\n", + " 'getGridIndices',\n", + " 'getHaloEllipsis',\n", + " 'getLatitude',\n", + " 'getLevel',\n", + " 'getLongitude',\n", + " 'getMPIRank',\n", + " 'getMPISize',\n", + " 'getMissing',\n", + " 'getOrder',\n", + " 'getRegion',\n", + " 'getSlice',\n", + " 'getTileIndex',\n", + " 'getTime',\n", + " 'getValue',\n", + " 'get_fill_value',\n", + " 'get_imag',\n", + " 'get_real',\n", + " 'getattribute',\n", + " 'getdimattribute',\n", + " 'getfield',\n", + " 'harden_mask',\n", + " 'hardmask',\n", + " 'hasCellData',\n", + " 'id',\n", + " 'ids',\n", + " 'imag',\n", + " 'info',\n", + " 'initDomain',\n", + " 'isAbstractCoordinate',\n", + " 'isEncoded',\n", + " 'iscontiguous',\n", + " 'item',\n", + " 'itemset',\n", + " 'itemsize',\n", + " 'listall',\n", + " 'listattributes',\n", + " 'listdimattributes',\n", + " 'listdimnames',\n", + " 'mask',\n", + " 'matchPattern',\n", + " 'matchone',\n", + " 'max',\n", + " 'mean',\n", + " 'min',\n", + " 'mini',\n", + " 'missing',\n", + " 'missing_value',\n", + " 'name',\n", + " 'nbytes',\n", + " 'ndim',\n", + " 'newbyteorder',\n", + " 'nonzero',\n", + " 'parent',\n", + " 'partition',\n", + " 'pressureRegrid',\n", + " 'prod',\n", + " 'product',\n", + " 'ptp',\n", + " 'put',\n", + " 'rank',\n", + " 'ravel',\n", + " 'real',\n", + " 'recordmask',\n", + " 'reg_specs2slices',\n", + " 'regrid',\n", + " 'reorder',\n", + " 'repeat',\n", + " 'reshape',\n", + " 'resize',\n", + " 'round',\n", + " 'searchPattern',\n", + " 'searchPredicate',\n", + " 'searchone',\n", + " 'searchsorted',\n", + " 'select',\n", + " 'setAxis',\n", + " 'setAxisList',\n", + " 'setGrid',\n", + " 'setMPIComm',\n", + " 'setMaskFromGridMask',\n", + " 'setMissing',\n", + " 'setTileIndex',\n", + " 'set_fill_value',\n", + " 'setattribute',\n", + " 'setdimattribute',\n", + " 'setfield',\n", + " 'setflags',\n", + " 'shape',\n", + " 'sharedmask',\n", + " 'showdim',\n", + " 'shrink_mask',\n", + " 'size',\n", + " 'soften_mask',\n", + " 'sort',\n", + " 'source',\n", + " 'specs2slices',\n", + " 'squeeze',\n", + " 'std',\n", + " 'std_slab_atts',\n", + " 'strides',\n", + " 'subRegion',\n", + " 'subSlice',\n", + " 'sum',\n", + " 'swapaxes',\n", + " 'take',\n", + " 'tileIndex',\n", + " 'time',\n", + " 'title',\n", + " 'toVisit',\n", + " 'tobytes',\n", + " 'tofile',\n", + " 'toflex',\n", + " 'tolist',\n", + " 'torecords',\n", + " 'tostring',\n", + " 'trace',\n", + " 'transpose',\n", + " 'type',\n", + " 'typecode',\n", + " 'units',\n", + " 'unshare_mask',\n", + " 'var',\n", + " 'variable_count',\n", + " 'view']" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dir(u)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In general internal attributes should not be modified directly. One\n", + "exception is the id attribute, the name of the variable. It is used in\n", + "plotting and I/O, and can be set directly." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Masked values\n", + "\n", + "Optionally, variables have a mask that represents where data are\n", + "missing. If present, the mask is an array of ones and zeros having the\n", + "shape of the data array. A mask value of one indicates that the\n", + "corresponding data array element is missing or invalid.\n", + "\n", + "Arithmetic operations in CDMS take missing data into account. The same\n", + "is true of the functions defined in the cdms2.MV2 module. For example:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'MV2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Create array a, with no mask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Same for b\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mb\u001b[0m \u001b[0;31m# variable_... array([5,7,9,])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'MV2' is not defined" + ] + } + ], + "source": [ + "a = MV2.array([1,2,3]) # Create array a, with no mask\n", + "b = MV2.array([4,5,6]) # Same for b\n", + "a+b # variable_... array([5,7,9,]) \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "a[1]=MV2.masked # Mask the second value of a a.mask()\n", + "a.mask\n", + "\n", + "a+b # The sum is masked also " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When data is read from a file, the result variable is masked if the file\n", + "variable has a missing_value attribute. The mask is set to one for\n", + "those elements equal to the missing value, zero elsewhere. If no such\n", + "attribute is present in the file, the result variable is not masked.\n", + "\n", + "When a variable with masked values is written to a file, data values\n", + "with a corresponding mask value of one are set to the value of the\n", + "variables ``missing_value`` attribute. The data and ``missing_value``\n", + "attribute are then written to the file.\n", + "\n", + "Masking is covered in `Section 2.9 `__. See also the\n", + "documentation of the Python Numpy and MA modules, on which ``cdms.MV``\n", + "is based, at\n", + "\n", + "`https://www.numpy.org/ `__." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "File Variables\n", + "\n", + "A variable can be obtained either from a file, a collection of files, or\n", + "as the result of computation. Correspondingly there are three types of\n", + "variables in CDMS:\n", + "\n", + "- *file variable* is a variable associated with a single data file.\n", + " Setting or referencing a file variable generates I/O operations.\n", + "- A *dataset variable* is a variable associated with a collection of\n", + " files. Reference to a dataset variable reads data, possibly from\n", + " multiple files. Dataset variables are read-only.\n", + "- *transient variable* is an in-memory object not associated with a\n", + " file or dataset. Transient variables result from a computation or I/O\n", + " operation.\n", + "\n", + "Typical use of a file variables is to inquire information about the\n", + "variable in a file without actually reading the data for the variables.\n", + "A file variable is obtained by applying the slice operator [] to a file,\n", + "passing the name of the variable, or by calling the getVariable\n", + "function. Note that obtaining a file variable does not actually read the\n", + "data array:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 2, 80, 97)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u = f.getVariable('u') # or u=f['u']\n", + "u.shape \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "File variables are also useful for fine-grained I/O. They behave like\n", + "transient variables, but operations on them also affect the associated\n", + "file. Specifically:\n", + "\n", + "- slicing a file variable reads data,\n", + "- setting a slice writes data,\n", + "- referencing an attribute reads the attribute,\n", + "- setting an attribute writes the attribute,\n", + "- and calling a file variable like a function reads data associated\n", + " with the variable:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.system(\"cp clt.nc /tmp\")\n", + "\n", + "f = cdms2.open('/tmp/clt.nc','a') # Open read/write\n", + "uvar = f['u'] # Note square brackets\n", + "uvar.shape\n", + "\n", + "u0 = uvar[0] # Reads data from sample.nc\n", + "u0.shape\n", + "\n", + "uvar[1]=u0 # Writes data to sample.nc\n", + "uvar.units # Reads the attribute 'm/s'\n", + "\n", + "u24 = uvar(time=1.0) # Calling a variable like a function reads data\n", + "f.close() # Save changes to clt.nc (I/O may be buffered)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For transient variables, the data is printed only if the size of the array is less\n", + "than the print limit . This value can be set with the function\n", + "MV.set_print_limit to force the data to be printed:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'MV2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_print_limit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Current limit 1000\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msmallvar\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'MV2' is not defined" + ] + } + ], + "source": [ + "MV2.get_print_limit() # Current limit 1000\n", + "\n", + "smallvar \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "MV2.set_print_limit(100)\n", + "largevar " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The datatype of the variable is determined with the typecode function:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'f'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "u.typecode()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dataset Variables\n", + "\n", + "The third type of variable, a *dataset variable*, is associated with a\n", + "*dataset*, a collection of files that is treated as a single file. A\n", + "dataset is created with the ``cdscan`` utility. This generates an XML\n", + "metafile that describes how the files are organized and what metadata\n", + "are contained in the files. In a climate simulation application, a\n", + "dataset typically represents the data generated by one run of a general\n", + "circulation or coupled ocean-atmosphere model.\n", + "\n", + "For example, suppose data for variables u and v are stored in six files:\n", + "\n", + "1. u_2000.nc,\n", + "2. u_2001.nc,\n", + "3. u_2002.nc,\n", + "4. v_2000.nc,\n", + "5. v_2001.nc,\n", + "6. v_2002.nc.\n", + "\n", + "A metafile can be generated with the command:\n", + "\n", + "**$ cdscan -x cdsample.xml [uv]*.nc**\n", + "\n", + "The metafile **cdsample.xml** is then used like an ordinary data file:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "ename": "IOError", + "evalue": "[Errno 2] No such file or directory: '/export/reshel3/cdms/cdsample.xml'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIOError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cdscan -x cdsample.xml [uv]*.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'cdsample.xml'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mu\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mu\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 488\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;34m'r'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 489\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mModeNotSupported\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 490\u001b[0;31m \u001b[0mdatanode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 491\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 492\u001b[0m \u001b[0;31m# If the doesn't exist allow it to be created\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mload\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 402\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 403\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 404\u001b[0;31m \u001b[0mfd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 405\u001b[0m \u001b[0mtext\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 406\u001b[0m \u001b[0mfd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mIOError\u001b[0m: [Errno 2] No such file or directory: '/export/reshel3/cdms/cdsample.xml'" + ] + } + ], + "source": [ + "import os\n", + "os.system(\"cdscan -x cdsample.xml [uv]*.nc\")\n", + "\n", + "f = cdms2.open('cdsample.xml')\n", + "u = f('u')\n", + "u.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Grids\n", + "\n", + "A latitude-longitude grid represents the coordinate information\n", + "associated with a variable. A grid encapsulates:\n", + "\n", + "- latitude, longitude coordinates\n", + "- grid cell boundaries\n", + "- area weights\n", + "\n", + "CDMS defines a rich set of grid types to represent the variety of\n", + "coordinate systems used in climate model applications. Grids can be\n", + "categorized as rectangular or nonrectangular.\n", + "\n", + "A rectangular grid has latitude and longitude axes that are\n", + "one-dimensional, with strictly monotonic values. The grid is essentially\n", + "the Cartesian product of the axes. If either criterion is not met, the\n", + "grid is nonrectangular .\n", + "\n", + "CDMS supports two types of nonrectangular grid:\n", + "\n", + "- A curvilinear grid consists of a latitude and longitude axis, each of\n", + " which is a two-dimensional coordinate axis. Curvilinear grids are\n", + " often used in ocean model applications.\n", + "- A generic grid consists of a latitude and longitude axis, each of\n", + " which is an auxiliary one-dimensional coordinate axis. An auxiliary\n", + " axis has values that are not necessarily monotonic. As the name\n", + " suggests, generic grids can represent virtually any type of grid.\n", + " However, it is more difficult to determine adjacency relationships\n", + " between grid points." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: A Curvilinear Grid\n", + "\n", + "In this example, variable sample is defined on a 128x192 curvilinear\n", + "grid. Note that:\n", + "\n", + "- The domain of variable sample is ( y , x ) where y and x are index\n", + " coordinate axes.\n", + "- The curvilinear grid associated with sample consists of axes ( lat ,\n", + " lon ), each a two-dimensional coordinate axis.\n", + "- lat and lon each have domain ( y , x )" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/sampleCurveGrid4.nc (Variable not found)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sampleCurveGrid4.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# lat and lon are coordinate axes, but are grouped with data variables\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/sampleCurveGrid4.nc (Variable not found)" + ] + } + ], + "source": [ + "f = cdms2.open('sampleCurveGrid4.nc')\n", + "\n", + "\n", + "# lat and lon are coordinate axes, but are grouped with data variables\n", + "f.variables.keys()\n", + "\n", + "\n", + "# y and x are index coordinate axes\n", + "f.axes.keys()\n", + "\n", + "\n", + "# Read data for variable sample\n", + "sample = f('sample')\n", + "\n", + "# The associated grid g is curvilinear\n", + "g = sample.getGrid()\n", + "\n", + "# The domain of the variable consfigists of index axes\n", + "sample.getAxisIds()\n", + "\n", + "\n", + "# Get the coordinate axes associated with the grid\n", + "lat = g.getLatitude() # or sample.getLatitude()\n", + "lon = g.getLongitude() # or sample.getLongitude()\n", + "\n", + "# lat and lon have the same domain, a subset of the domain of 'sample'\n", + "lat.getAxisIds()\n", + "\n", + "\n", + "# lat and lon are variables ...\n", + "lat.shape\n", + "\n", + "\n", + "lat \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lat_in_radians = lat*MV2.pi/180.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: A Generic Grid\n", + "\n", + "In this example variable zs is defined on a generic grid. Figure 2\n", + "illustrates the grid, in this case a geodesic grid:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "No such variable, sample", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maxes\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mzs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sample'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mzs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetGrid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/cudsinterface.pyc\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, id, *args, **kwargs)\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No such variable or grid, \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mAttributeError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 33\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No such variable, \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 34\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: No such variable, sample" + ] + } + ], + "source": [ + "f.variables.keys()\n", + "\n", + "f.axes.keys()\n", + "\n", + "zs = f('sample')\n", + "g = zs.getGrid()\n", + "g\n", + "\n", + "lat = g.getLatitude()\n", + "lon = g.getLongitude()\n", + "lat.shape\n", + "\n", + "lon.shape # variable zs is defined in terms of a single index coordinate\n", + "\n", + "# axis, 'cell'\n", + "zs.shape\n", + "\n", + "zs.getAxisIds()\n", + "\n", + "\n", + "# lat and lon are also defined in terms of the cell axis\n", + "lat.getAxisIds()\n", + "\n", + "\n", + "# lat and lon are one-dimensional, 'auxiliary' coordinate\n", + "# axes: values are not monotonic\n", + "lat.__class__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Figure 2: Generic Grid\n", + "\n", + "Generic grids can be used to represent any of the grid types. The method\n", + "toGenericGrid can be applied to any grid to convert it to a generic\n", + "representation. Similarly, a rectangular grid can be represented as\n", + "curvilinear. The method toCurveGrid is used to convert a non-generic\n", + "grid to curvilinear representation:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdat_info' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m'/clt.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mclt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'clt'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mrectgrid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mclt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetGrid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mrectgrid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" + ] + } + ], + "source": [ + "f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc')\n", + "clt = f('clt')\n", + "rectgrid = clt.getGrid()\n", + "rectgrid.shape\n", + "\n", + "curvegrid = rectgrid.toCurveGrid()\n", + "curvegrid\n", + "\n", + "genericgrid = curvegrid.toGenericGrid()\n", + "genericgrid" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regridding\n", + "\n", + "Regridding is the process of mapping variables from one grid to another.\n", + "CDMS supports two forms of regridding. Which one you use depends on the\n", + "class of grids being transformed:\n", + "\n", + "- To interpolate from one rectangular grid to another, use the built-in\n", + " CDMS regridder. CDMS also has built-in regridders to interpolate from\n", + " one set of pressure levels to another, or from one vertical\n", + " cross-section to another.\n", + "- To interpolate from any lat-lon grid, rectangular or non-rectangular,\n", + " use the SCRIP regridder." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CDMS Regridder\n", + "\n", + "The built-in CDMS regridder is used to transform data from one\n", + "rectangular grid to another. For example, to regrid variable ``u`` (from\n", + "a rectangular grid) to a 96x192 rectangular Gaussian grid:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1341: Warning: \n", + "avariable.regrid: We chose regridTool = esmf for you among the following choices:\n", + " Tools -> 'regrid2' (old behavior)\n", + " 'esmf' (conserve, patch, linear) or\n", + " 'libcf' (linear)\n", + " warnings.warn(message, Warning)\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1348: Warning: \n", + "avariable.regrid: We chose regridMethod = linear for you among the following choices:\n", + " 'conserve' or 'linear' or 'patch'\n", + " warnings.warn(message, Warning)\n" + ] + }, + { + "data": { + "text/plain": [ + "(1, 2, 96, 192)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f = cdms2.open('clt.nc')\n", + "u = f('u')\n", + "u.shape\n", + "\n", + "t63_grid = cdms2.createGaussianGrid(96)\n", + "u63 = u.regrid(t63_grid)\n", + "u63.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To regrid a variable ``uold`` to the same grid as variable ``vnew``:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'f2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'clt.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0muold\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0munew\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'uwnd'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0muold\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'f2' is not defined" + ] + } + ], + "source": [ + "f = cdms2.open('clt.nc')\n", + "uold = f('u')\n", + "unew = f2('uwnd')\n", + "uold.shape\n", + "\n", + "unew.shape\n", + "\n", + "t63_grid = unew.getGrid() # Obtain the grid for vnew\n", + "u63 = uold.regrid(t63_grid)\n", + "u63.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder\n", + "\n", + "To interpolate between any lat-lon grid types, the SCRIP regridder may\n", + "be used. The SCRIP package was developed at [Los Alamos National\n", + "Laboratory] (https://oceans11.lanl.gov/drupal/Models/OtherSoftware).\n", + "SCRIP is written in Fortran 90, and must be built and installed\n", + "separately from the CDAT/CDMS installation.\n", + "\n", + "The steps to regrid a variable are:\n", + "\n", + "(external to CDMS)\n", + "\n", + "1. Obtain or generate the grids, in SCRIP netCDF format.\n", + "2. Run SCRIP to generate a *remapping* file.\n", + "\n", + "(in CDMS)\n", + "\n", + "1. Read the regridder from the SCRIP remapping file.\n", + "2. Call the regridder with the source data, returning data on the target\n", + " grid.\n", + "\n", + "Steps 1 and 2 need only be done once. The regridder can be used as often\n", + "as necessary.\n", + "\n", + "#For example, suppose the source data on a T42 grid is to be mapped to a\n", + "#POP curvilinear grid. Assume that SCRIP generated a remapping file named\n", + "#rmp_T42_to_POP43_conserv.nc:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/sampleT42Grid.nc (Variable not found)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# Get the source variable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sampleT42Grid.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0mdat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'src_array'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/sampleT42Grid.nc (Variable not found)" + ] + } + ], + "source": [ + "# Import regrid package for regridder functions\n", + "import regrid2, cdms2\n", + "\n", + "# Get the source variable\n", + "f = cdms2.open('sampleT42Grid.nc')\n", + "dat = f('src_array')\n", + "f.close()\n", + "\n", + "# Read the regridder from the remapper file\n", + "remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc')\n", + "regridf = regrid2.readRegridder(remapf)\n", + "remapf.close()\n", + "\n", + "# Regrid the source variable\n", + "popdat = regridf(dat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regridding is discussed in `Chapter 4 `__." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time types\n", + "\n", + "CDMS provides extensive support for time values in the cdtime module.\n", + "cdtime also defines a set of calendars , specifying the number of days\n", + "in a given month.\n", + "\n", + "Two time types are available: relative time and component time .\n", + "Relative time is time relative to a fixed base time. It consists of:\n", + "\n", + "- a ``units`` string, of the form ``\"units since basetime\"`` , and\n", + "- a floating-point ``value``\n", + "\n", + "For example, the time \"28.0 days since 1996-1-1\" has value= 28.0 , and\n", + "units=\" days since 1996-1-1\". To create a relative time type:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'days since 1996-1-1'" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import cdtime\n", + "rt = cdtime.reltime(28.0, \"days since 1996-1-1\")\n", + "rt\n", + "\n", + "rt.value\n", + "\n", + "rt.units" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A component time consists of the integer fields year, month, day, hour,\n", + "minute , and the floating-point field second . For example:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ct = cdtime.comptime(1996,2,28,12,10,30)\n", + "ct\n", + "\n", + "ct.year\n", + "\n", + "ct.month" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The conversion functions tocomp and torel convert between the two\n", + "representations. For instance, suppose that the time axis of a variable\n", + "is represented in units \" days since 1979\" . To find the coordinate\n", + "value corresponding to January 1, 1990:" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4018.0" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ct = cdtime.comptime(1990,1)\n", + "rt = ct.torel(\"days since 1979\")\n", + "rt.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time values can be used to specify intervals of time to read. The syntax\n", + "time=(c1,c2) specifies that data should be read for times t such that\n", + "c1<=t<=c2:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdat_info' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_6h.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mc1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1980\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mc2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1980\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mtas\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tas'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mtas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" + ] + } + ], + "source": [ + "fh = cdms2.open(cdat_info.get_sampledata_path() + \"/tas_6h.nc\")\n", + "c1 = cdtime.comptime(1980,1)\n", + "c2 = cdtime.comptime(1980,2)\n", + "tas = fh['tas']\n", + "tas.shape\n", + "\n", + "x = tas.subRegion(time=(c1,c2))\n", + "x.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or string representations can be used:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdat_info' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_6h.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mtas\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tas'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubRegion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1980-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1980-2'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" + ] + } + ], + "source": [ + "fh = cdms2.open(cdat_info.get_sampledata_path() + \"/tas_6h.nc\")\n", + "tas = fh['tas']\n", + "x = tas.subRegion(time=('1980-1','1980-2'))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time types are described in Chapter 3." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting data\n", + "\n", + "Data read via the CDMS Python interface can be plotted using the vcs\n", + "module. This module, part of the Climate Data Analysis Tool (CDAT) is documented in the VCS reference manual. The\n", + "vcs module provides access to the functionality of the VCS visualization\n", + "program.\n", + "\n", + "To generate a plot:\n", + "\n", + "- Initialize a canvas with the ``vcs init`` routine.\n", + "- Plot the data using the canvas ``plot`` routine.\n", + "\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_cru_1979.nc (Variable not found)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvcs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcdat_info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mfh\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_cru_1979.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'time'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# Print the time coordinates\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_cru_1979.nc (Variable not found)" + ] + } + ], + "source": [ + "import cdms2, vcs, cdat_info\n", + "fh=cdms2.open(cdat_info.get_sampledata_path() + \"/tas_cru_1979.nc\")\n", + "fh['time'][:] # Print the time coordinates\n", + "\n", + "\n", + "\n", + "tas = fh('tas', time=1479)\n", + "tas.shape\n", + "\n", + "w = vcs.init() # Initialize a canvas\n", + "w.plot(tas) # Generate a plot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default for rectangular grids, a boxfill plot of the lat-lon slice is\n", + "produced. Since variable precip includes information on time, latitude,\n", + "and longitude, the continental outlines and time information are also\n", + "plotted. If the variable were on a non-rectangular grid, the plot would\n", + "be a meshfill plot.\n", + "\n", + "The plot routine has a number of options for producing different types\n", + "of plots, such as isofill and x-y plots. See `Chapter 5 `__\n", + "for details." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Databases\n", + "\n", + "Datasets can be aggregated together into hierarchical collections,\n", + "called databases . In typical usage, a program:\n", + "\n", + "- connects to a database\n", + "- searches for data opens a dataset\n", + "- accesses data\n", + "\n", + "Databases add the ability to search for data and metadata in a\n", + "distributed computing environment. At present CDMS supports one\n", + "particular type of database, based on the Lightweight Directory Access\n", + "Protocol (LDAP).\n", + "\n", + ".. Here is an example of accessing data via a database:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m .. >>> db = cdms.connect() # Connect to the default database.\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + ".. >>> db = cdms.connect() # Connect to the default database.\n", + ".. >>> f = db.open('ncep_reanalysis_mo') # Open a dataset.\n", + ".. >>> f.variables.keys() # List the variables in the dataset.\n", + ".. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va']\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Databases are discussed further in `Section 2.7 `__." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Open file and retrieve u and v variable" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/clt.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf1\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"clt.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mu\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'v'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 515\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 516\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 517\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1299\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1300\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1301\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1302\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/clt.nc (No error)" + ] + } + ], + "source": [ + "f1=cdms2.open(\"clt.nc\")\n", + "u = f1('u')\n", + "v = f1('v')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Compute wind velocity" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "vel = MV.sqrt(u[0]**2 + v[0]**2)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2, 80, 97)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vel.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Display wind velocity" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "import vcs" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "plot=vcs.init()" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAJeCAIAAADdhMaJAAAFsUlEQVR4Xu3BMQEAAADCoPVPbQdvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAxmFQAAQLiEWwAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot.isofill(vel[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "u1 = f1('u',time=1.)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAJeCAIAAADdhMaJAAAFsUlEQVR4Xu3BMQEAAADCoPVPbQdvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAxmFQAAQLiEWwAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plot.isofill(u1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/chapter2.ipynb b/chapter2.ipynb new file mode 100644 index 00000000..29c11114 --- /dev/null +++ b/chapter2.ipynb @@ -0,0 +1,3017 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CDMS Python Application Programming Interface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "OVERVIEW\n", + "=============\n", + "\n", + "\n", + "\n", + "This chapter describes the CDMS Python application programming interface\n", + "(API). Python is a popular public-domain, object-oriented language. Its\n", + "features include support for object-oriented development, a rich set of\n", + "programming constructs, and an extensible architecture. CDMS itself is\n", + "implemented in a mixture of C and Python. In this chapter the assumption\n", + "is made that the reader is familiar with the basic features of the\n", + "Python language.\n", + "\n", + "Python supports the notion of a module, which groups together associated\n", + "classes and methods. The import command makes the module accessible to\n", + "an application. This chapter documents the cdms, cdtime, and regrid\n", + "modules.\n", + "\n", + "The chapter sections correspond to the CDMS classes. Each section\n", + "contains table\n", + "s base. If no parent, the datapath is absolute.describing\n", + "the class internal (non-persistent) attributes, constructors (functions\n", + "for creating an object), and class methods (functions). A method can\n", + "return an instance of a CDMS class, or one of the Python types:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"Array\", \"Numpy or masked multidimensional data array. All elements of the array are of the same type. Defined in the Numpy and MV2 modules.\"\n", + " \"Comptime\", \"Absolute time value, a time with representation (year, month, day, hour, minute, second). Defined in the cdtime module. cf. reltime\" \n", + " \"Dictionary\",\"An unordered 2,3 collection of objects, indexed by key. All dictionaries in CDMS are indexed by strings, e.g.: ``axes['time']``\"\n", + " \"Float\", \"Floating-point value.\"\n", + " \"Integer\", \"Integer value.\"\n", + " \"List\", \"An ordered sequence of objects, which need not be of the same type. New members can be inserted or appended. Lists are denoted with square brackets, e.g., ``[1, 2.0, 'x', 'y']``\"\n", + " \"None\", \"No value returned.\"\n", + " \"Reltime\", \"Relative time value, a time with representation (value, units since basetime). Defined in the cdtime module. cf. comptime\"\n", + " \"Tuple\", \"An ordered sequence of objects, which need not be of the same type. Unlike lists, tuples elements cannot be inserted or appended. Tuples are denoted with parentheses, e.g., ``(1, 2.0, 'x', 'y')``\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A First Example\n", + "\n", + "\n", + "The following Python script reads January and July monthly temperature\n", + "data from an input dataset, averages over time, and writes the results\n", + "to an output file. The input temperature data is ordered (time,\n", + "latitude, longitude)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_mo.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcdat_info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mMV\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mjones\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m'/tas_mo.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mtasvar\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mjones\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tas'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mjans\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtasvar\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m12\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_mo.nc (No error)" + ] + } + ], + "source": [ + "import cdms2, cdat_info\n", + "from cdms2 import MV\n", + "jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc')\n", + "tasvar = jones['tas']\n", + "jans = tasvar[0::12]\n", + "julys = tasvar[6::12]\n", + "janavg = MV.average(jans)\n", + "janavg.id = \"tas_jan\"\n", + "janavg.long_name = \"mean January surface temperature\"\n", + "julyavg = MV.average(julys)\n", + "julyavg.id = \"tas_jul\"\n", + "julyavg.long_name = \"mean July surface temperature\"\n", + "out = cdms2.open('janjuly.nc','w')\n", + "out.write(janavg)\n", + "\n", + "out.write(julyavg)\n", + "\n", + "out.comment = \"Average January/July from Jones dataset\"\n", + "jones.close()\n", + "out.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"2,3\", \"Makes the CDMS and MV modules available.\n", + " * MV defines arithmetic functions.\"\n", + " \"4\", \"Opens a netCDF file read-only. \n", + " * The result jones is a dataset object.\"\n", + " \"5\", \"Gets the surface air temperature variable. ‘tas’ is the name of the variable in the input dataset. \n", + " * This does not actually read the data.\"\n", + " \"6\", \"Read all January monthly mean data into a variable jans.\n", + " * Variables can be sliced like arrays. \n", + " * The slice operator [0::12] means take every 12th slice from dimension 0, starting at index 0 and ending at the last index. \n", + " * If the stride 12 were omitted, it would default to 1. \n", + " **Note:** that the variable is actually 3-dimensional. Since no slice is specified for the second or third dimensions, all values of those 2,3 dimensions are retrieved. The slice operation could also have been written [0::12, : , :]. \n", + "\n", + " **Also note:** that the same script works for multi-file datasets. CDMS opens the needed data files, extracts the appropriate slices, and concatenates them into the result array.\"\n", + " \"7\", \"Reads all July data into a masked array julys.\"\n", + " \"8\", \"Calculate the average January value for each grid zone.\n", + " * Any missing data is handled automatically.\"\n", + " \"9,10\", \"Set the variable id and long\\_name attributes. \n", + " * The id is used as the name of the variable when plotted or written to a file.\"\n", + " \"14\", \"Create a new netCDF output file named ‘janjuly.nc’ to hold the results.\"\n", + " \"15\", \"Write the January average values to the output file. \n", + " * The variable will have id “tas\\_jan” in the file.\n", + " * ``write`` is a utility function which creates the variable in the file, then writes data to the variable.\n", + " * A more general method of data output is first to create a variable, then set a slice of the variable.\n", + " **Note:** that janavg and julavg have the same latitude and longitude information as tasvar. It is carried along with the computations.\"\n", + " \"17\", \"Set the global attribute ‘comment’.\"\n", + " \"18\", \"Close the output file.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cdms Module\n", + "\n", + "\n", + "The cdms module is the Python interface to CDMS. The objects and methods\n", + "in this chapter are made accessible with the command:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The functions described in this section are not associated with a class.\n", + "Rather, they are called as module functions, e.g.," + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/sample.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfile\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sample.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/sample.nc (No error)" + ] + } + ], + "source": [ + "file = cdms2.open('sample.nc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cdms Module Functions\n", + "\n", + " \"``Variable``\", \"``asVariable(s)``: \n", + " Transform ``s`` into a transient variable.\n", + " * ``s`` is a masked array, Numpy array, or Variable. \n", + " * If ``s`` is already a transient variable, ``s`` is returned. \n", + " * See also: ``isVariable``.\"\n", + " \"``Axis``\", \"``createAxis(data, bounds=None)``:\n", + " Create a one-dimensional coordinate Axis, which is not associated with a file or dataset. This is useful for creating a grid which is not contained in a file or dataset.\n", + " * ``data`` is a one-dimensional, monotonic Numpy array.\n", + " * ``bounds`` is an array of shape ``(len(data),2)``, such that for all ``i``, \n", + " * ``data[i]`` is in the range ``[bounds[i,0],bounds[i,1] ]``.\n", + " * If ``bounds`` is not specified, the default boundaries are generated at the midpoints between the consecutive data values, provided that the autobounds mode is 'on' (the default). \n", + " * See ``setAutoBounds``. \n", + " * Also see: ``CdmsFile.createAxis``\"\n", + " \"``Axis``\", \"``createEqualAreaAxis(nlat)``: \n", + " Create an equal-area latitude axis. \n", + " * The latitude values range from north to south, and for all axis values ``x[i]``, ``sin(x[i])sin(x[i+1])`` is constant. \n", + " * ``nlat`` is the axis length. \n", + " **Note:** The axis is not associated with a file or dataset.\"\n", + " \"``Axis``\", \"``createGaussianAxis(nlat)``: \n", + " Create a Gaussian latitude axis.\\\n", + " * Axis values range from north to south. \n", + " * ``nlat`` is the axis length. \n", + " **Note:** The axis is not associated with a file or dataset.\"\n", + " \"``RectGrid``\", \"``createGaussianGrid(nlats, xorigin=0.0, order='yx')``:\n", + " Create a Gaussian grid, with shape ``(nlats, 2*nlats)``. \n", + " * ``nlats`` is the number of latitudes. \n", + " * ``xorigin`` is the origin of the longitude axis. \n", + " * ``order`` is either 'yx' (lat-lon, default) or 'xy' (lon-lat)\"\n", + " \"``RectGrid``\", \"``createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None)``:\n", + " Create a generic grid, that is, a grid which is not typed as Gaussian, uniform, or equal-area. The grid is not associated with a file or dataset. \n", + " * ``latArray`` is a NumPy array of latitude values.\n", + " * ``lonArray`` is a NumPy array of longitude values. \n", + " * ``latBounds`` is a NumPy array having shape ``(len(latArray),2)``, of latitude boundaries. \n", + " * ``lonBounds`` is a NumPy array having shape ``(len(lonArray),2)``, of longitude boundaries. \n", + " * ``order`` is a ``string`` specifying the order of the axes, either 'yx' for (latitude, longitude), or 'xy' for the reverse.\n", + " * ``mask`` (optional) is an ``integer``-valued NumPy mask array, having the same shape and ordering as the grid.\" \n", + " \"``RectGrid``\", \"``createGlobalMeanGrid(grid)``:\n", + " Generate a grid for calculating the global mean via a regridding operation. The return grid is a single zone covering the range of the input grid.\n", + " * ``grid`` is a RectGrid.\"\n", + " \"``RectGrid``\", \"``createRectGrid(lat, lon, order, type='generic', mask=None)``:\n", + " Create a rectilinear grid, not associated with a file or dataset. This might be used as the target grid for a regridding operation. \n", + " * ``lat`` is a latitude axis, created by ``cdms.createAxis``. \n", + " * ``lon`` is a longitude axis, created by ``cdms.createAxis``. \n", + " * ``order`` is a string with value 'yx' (the first grid dimension is latitude) or 'xy' (the first grid dimension is longitude). \n", + " * ``type`` is one of 'gaussian','uniform','equalarea',or 'generic'. \n", + " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid.\"\n", + " \"``RectGrid``\", \"``createUniformGrid(startLat, nlat, deltaLat, start-Lon, nlon, deltaLon, order='yx', mask=None)``:\n", + " Create a uniform rectilinear grid. \n", + " * The grid is not associated with a file or dataset. \n", + " * The grid boundaries are at the midpoints of the axis values. \n", + " * ``startLat`` is the starting latitude value. \n", + " * ``nlat`` is the number of latitudes. If ``nlat`` is 1, the grid latitude boundaries will be ``startLat`` +/- ``deltaLat/2``.\n", + " * ``deltaLat`` is the increment between latitudes.\n", + " * ``startLon`` is the starting longitude value.\n", + " * ``nlon`` is the number of longitudes. If ``nlon`` is 1, the grid longitude boundaries will be ``startLon`` +/- ``deltaLon/2``.\n", + " * ``deltaLon`` is the increment between longitudes.\n", + " * ``order`` is a string with value 'yx. (the first grid dimension is latitude) or .xy. (the first grid dimension is longitude).\n", + " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid.\"\n", + " \"``Axis``\", \"``createUniformLatitudeAxis(startLat , nlat, deltaLat)``:\n", + " Create a uniform latitude axis.\n", + " * The axis boundaries are at the midpoints of the axis values.\n", + " * The axis is designated as a circular latitude axis. \n", + " * ``startLat`` is the starting latitude value.\n", + " * ``nlat`` is the number of latitudes.\n", + " * ``deltaLat`` is the increment between latitudes.\"\n", + " \"``RectGrid``\",\"``createZonalGrid(grid)``:\n", + " Create a zonal grid.\n", + " * The output grid has the same latitude as the input grid, and a single longitude. \n", + " * This may be used to calculate zonal averages via a regridding operation. \n", + " * ``grid`` is a RectGrid.\"\n", + " \"``Axis``\", \"``createUniformLongitudeAxis(startLon, nlon, delta-Lon)``: \n", + " Create a uniform longitude axis.\n", + " * The axis boundaries are at the midpoints of the axis values.\n", + " * The axis is designated as a circular longitude axis. \n", + " * ``startLon`` is the starting longitude value.\n", + " * ``nlon`` is the number of longitudes\n", + " * ``deltaLon`` is the increment between longitudes.\"\n", + " \"``Variable``\", \"``createVariable(array, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None , attributes=None, id=None)``:\"\n", + " \"``Integer``\", \"``getAutoBounds()``: \n", + " Get the current autobounds mode. Returns 0, 1, or 2.\n", + " * See ``setAutoBounds``.\"\n", + " \"``Integer``\", \"``isVariable(s)``: \n", + " * Return ``1`` if ``s`` is a variable, ``0`` otherwise.\n", + " * See also: ``asVariable``.\"\n", + " \"``Dataset``\", \"``open(url,mode='r')``:\n", + " Open or create a ``Dataset`` or ``CdmsFile``. \n", + " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. \n", + " * If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned. \n", + " * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'.\n", + " * If the protocol is 'file' or is omitted, a local file or dataset is opened.\n", + " * ``mode`` is the open mode. See `Open Modes <#id3>`__\n", + "\n", + " **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``\n", + "\n", + " **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``\"\n", + " \"``List``\", \"``order2index (axes, orderstring)``:\n", + " Find the index permutation of axes to match order. Return a list of indices.\n", + " * ``axes`` is a list of axis objects.\n", + " * ``orderstring`` is defined as in ``orderparse``.\"\n", + " \"``List``\", \"``orderparse(orderstring)``:\n", + " Parse an order string. Returns a list of axes specifiers. ``orderstring`` consists of:\n", + " * Letters t, x, y, z meaning time, longitude, latitude, level\n", + " * Numbers 0-9 representing position in axes\n", + " * Dash (-) meaning insert the next available axis here.\n", + " * The ellipsis ... meaning fill these positions with any remaining axes.\n", + " * (name) meaning an axis whose id is name\"\n", + " \"``None``\", \"``setAutoBounds(mode)``: \n", + " Set autobounds mode. In some circumstances CDMS can generate boundaries for 1-D axes and rectilinear grids, when the bounds are not explicitly defined. The autobounds mode determines how this is done:\n", + " * If ``mode`` is ``'grid'`` or ``2`` (the default), the ``getBounds`` method will automatically generate boundary information for an axis or grid if the axis is designated as a latitude or longitude axis, and the boundaries are not explicitly defined.\n", + " * If ``mode`` is ``'on'`` or ``1``, the ``getBounds`` method will automatically generate boundary information for an axis or grid, if the boundaries are not explicitly defined. \n", + " * If ``mode`` is ``'off'`` or ``0``, and no boundary data is explicitly defined, the bounds will NOT be generated; the ``getBounds`` method will return ``None`` for the boundaries.\n", + "\n", + " **Note:** In versions of CDMS prior to V4.0, the default ``mode`` was ``'on'``.\"\n", + " \"``None``\", \"``setClassifyGrids(mode)``:\n", + " Set the grid classification mode. This affects how grid type is determined, for the purpose of generating grid boundaries.\n", + " * If ``mode`` is ``'on'`` (the default), grid type is determined by a grid classification method, regardless of the value of ``grid.get-Type()``. \n", + " * If ``mode`` is ``'off'``, the value of ``grid.getType()`` determines the grid type.\" \n", + " \"``None``\", \"``writeScripGrid(path, grid, gridTitle=None)``:\n", + " Write a grid to a SCRIP grid file. \n", + " * ``path`` is a string, the path of the SCRIP file to be created. \n", + " * ``grid`` is a CDMS grid object. It may be rectangular. \n", + " * ``gridTitle`` is a string ID for the grid.\"\n", + ":" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Class Tags\n", + "\n", + " \"‘axis’\", \"Axis\"\n", + " \"‘database’\", \"Database\"\n", + " \"‘dataset’\", \"Dataset, CdmsFile \"\n", + " \"‘grid’\", \"RectGrid\"\n", + " \"‘variable’\", \"Variable\"\n", + " \"‘xlink’\", \"Xlink\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsObj\n", + "\n", + "A CdmsObj is the base class for all CDMS database objects. At the\n", + "application level, CdmsObj objects are never created and used directly.\n", + "Rather the subclasses of CdmsObj (Dataset, Variable, Axis, etc.) are the\n", + "basis of user application programming.\n", + "\n", + "All objects derived from CdmsObj have a special attribute .attributes.\n", + "This is a Python dictionary, which contains all the external\n", + "(persistent) attributes associated with the object. This is in contrast\n", + "to the internal, non-persistent attributes of an object, which are\n", + "built-in and predefined. When a CDMS object is written to a file, the\n", + "external attributes are written, but not the internal attributes.\n", + "\n", + "**Example**: get a list of all external attributes of obj." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'obj' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mextatts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattributes\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'obj' is not defined" + ] + } + ], + "source": [ + "extatts = obj.attributes.keys()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Attributes Common to All CDMS Objects\n", + "\n", + " \"Dictionary\", \"attributes\", \"External attribute dictionary for this object.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Getting and Setting Attributes\n", + "\n", + " \"various\", \"``value = obj.attname``\n", + " Get an internal or external attribute value. \n", + " * If the attribute is external, it is read from the database.\n", + " * If the attribute is not already in the database, it is created as an external attribute. \n", + " * Internal attributes cannot be created, only referenced.\"\n", + " \"various\", \"``obj.attname = value``\n", + " Set an internal or external attribute value.\n", + " * If the attribute is external, it is written to the database.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis\n", + "\n", + "A CoordinateAxis is a variable that represents coordinate information.\n", + "It may be contained in a file or dataset, or may be transient\n", + "(memoryresident). Setting a slice of a file CoordinateAxis writes to the\n", + "file, and referencing a file CoordinateAxis slice reads data from the\n", + "file. Axis objects are also used to define the domain of a Variable.\n", + "\n", + "CDMS defines several different types of CoordinateAxis objects. See `MV module <#id5>`_\n", + "documents methods that are common to all CoordinateAxis\n", + "types. See `HorizontalGrid <#id7>`_ specifies methods that are unique to 1D\n", + "Axis objects." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Types\n", + "\n", + " \"``CoordinateAxis``\", \"A variable that represents coordinate information.\n", + " * Has subtypes ``Axis2D`` and ``AuxAxis1D``.\"\n", + " \"``Axis``\", \"A one-dimensional coordinate axis whose values are strictly monotonic. \n", + " * Has subtypes ``DatasetAxis``, ``FileAxis``, and ``TransientAxis``.\n", + " * May be an index axis, mapping a range of integers to the equivalent floating point value.\n", + " * If a latitude or longitude axis, may be associated with a ``RectGrid``.\"\n", + " \"``Axis2D``\", \"A two-dimensional coordinate axis, typically a latitude or longitude axis related to a ``CurvilinearGrid``. \n", + " * Has subtypes ``DatasetAxis2D``, ``FileAxis2D``, and ``TransientAxis2D``.\"\n", + " \"``AuxAxis1D``\", \"A one-dimensional coordinate axis whose values need not be monotonic. Typically a latitude or longitude axis associated with a ``GenericGrid``.\n", + " * Has subtypes ``DatasetAuxAxis1D``, ``FileAuxAxis1D``, and ``TransientAuxAxis1D``. \n", + " * An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition.\n", + " * There can be at most one unlimited axis associated with a ``CdmsFile``.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Internal Attributes\n", + "\n", + " \"``Dictionary``\", \"``attributes``\", \"External attribute dictionary.\"\n", + " \"``String``\", \"``id``\", \"CoordinateAxis identifier.\"\n", + " \"``Dataset``\", \"``parent``\", \"The dataset which contains the variable.\"\n", + " \"``Tuple``\", \"``shape``\", \"The length of each axis.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Constructors\n", + "\n", + " \"``cdms.createAxis(data, bounds=None)``\", \"Create an axis which is not associated with a dataset or file. See `A First Example <#a-first-example>`_.\"\n", + " \"``Dataset.createAxis(name,ar)``\", \"Create an ``Axis`` in a ``Dataset``. (This function is not yet implemented.)\"\n", + " \"``CdmsFile.createAxis(name,ar,unlimited=0)``\", \"Create an Axis in a ``CdmsFile``.\n", + " * ``name`` is the string ``name`` of the ``Axis``. \n", + " * ``ar`` is a 1-D data array which defines the ``Axis`` values.\n", + " * It may have the value ``None`` if an unlimited axis is being defined. \n", + " * At most one ``Axis`` in a ``CdmsFile`` may be designated as being unlimited, meaning that it may be extended in length.\n", + " To define an axis as unlimited, either:\n", + " \n", + " * A) set ``ar`` to ``None``, and leave ``unlimited`` undefined, or\n", + " * B) set ``ar`` to the initial 1-D array, and set ``unlimited`` to ``cdms.Unlitmited``\n", + "\n", + " * ``cdms.createEqualAreaAxis(nlat)`` See `A First Example`_.\n", + " * ``cdms.createGaussianAxis(nlat)`` See `A First Example`_.\n", + " * ``cdms.createUniformLatitudeAxis(startlat, nlat, deltalat)`` See `A First Example`_.\n", + " * ``cdms.createUniformLongitudeAxis(startlon, nlon, deltalon)`` See `A First Example`_ .\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Methods\n", + "\n", + " \"``Array``\", \"``array = axis[i:j]``\", \"Read a slice of data from the external file or dataset.\n", + " * Data is returned in the physical ordering defined in the dataset.\n", + " * See `Variable Slice Operators <#id15>`_ for a description of slice operators.\"\n", + " \"``None``\", \"``axis[i:j] = array``\", \"Write a slice of data to the external file.\n", + " * Dataset axes are read-only.\"\n", + " \"``None``\", \"``assignValue(array)``\", \"Set the entire value of the axis.\n", + " * ``array`` is a Numpy array, of the same dimensionality as the axis.\"\n", + " \"``Axis``\", \"``clone(copyData=1)``\", \"Return a copy of the axis, as a transient axis.\n", + " * If ``copyData`` is 1 (the default) the data itself is copied.\"\n", + " \"``None``\", \"``designateLatitude(persistent=0)``\", \"Designate the axis to be a latitude axis.\n", + " * If persistent is true, the external file or dataset (if any) is modified. \n", + " * By default, the designation is temporary.\"\n", + " \"``None``\", \"``designateLevel(persistent=0)``\", \"Designate the axis to be a vertical level axis.\n", + " * If persistent is true, the external file or dataset (if any) is modified. \n", + " * By default, the designation is temporary.\"\n", + " \"``None``\", \"``designateLongitude(persistent=0, modulo=360.0)``\", \"Designate the axis to be a longitude axis.\n", + " * ``modulo`` is the modulus value. Any given axis value\n", + " * ``x`` is treated as equivalent to ``x + modulus``. \n", + " * If ``persistent`` is true, the external file or dataset (if any) is modified. \n", + " * By default, the designation is temporary.\"\n", + " \"``None``\", \"``designateTime(persistent=0, calendar = cdtime.MixedCalendar)``\", \"Designate the axis to be a time axis.\n", + " * If ``persistent`` is true, the external file or dataset (if any) is modified. \n", + " * By default, the designation is temporary.\n", + " * ``calendar`` is defined as in ``getCalendar()``.\"\n", + " \"``Array``\", \"``getBounds()``\", \"Get the associated boundary array. The shape of the return array depends on the type of axis:\n", + " * ``Axis``: ``(n,2)``\n", + " * ``Axis2D``: ``(i,j,4)``\n", + " * ``AuxAxis1D``: ``(ncell, nvert)`` where nvert is the maximum number of vertices of a cell.\n", + " * If the boundary array of a latitude or longitude ``Axis`` is not explicitly defined, and ``autoBounds`` mode is on, a default array is generated by calling ``genGenericBounds``. Otherwise if auto-Bounds mode is off, the return value is ``None``.\n", + " * See ``setAutoBounds``.\"\n", + " \"``Integer``\", \"``getCalendar()``\", \"Returns the calendar associated with the ``(time)``\\ axis. Possible return values, as defined in the ``cdtime`` module, are:\n", + "\n", + " * ``cdtime.GregorianCalendar``: the standard Gregorian calendar\n", + " * ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar\n", + " * ``cdtime.JulianCalendar``: years divisible by 4 are leap years\n", + " * ``cdtime.NoLeapCalendar``: a year is 365 days\n", + " * ``cdtime.Calendar360``: a year is 360 days\n", + " * ``None``: no calendar can be identified\n", + " **Note** If the axis is not a time axis, the global, file-related calendar is returned.\"\n", + " \"``Array``\", \"``getValue()``\", \"Get the entire axis vector.\"\n", + " \"``Integer``\", \"``isLatitude()``\", \"Returns true if the axis is a latitude axis.\"\n", + " \"``Integer``\", \"``isLevel()``\", \"Returns true if the axis is a level axis.\"\n", + " \"``Integer``\", \"``isLongitude()``\", \"Returns true if the axis is a longitude axis.\"\n", + " \"``Integer``\", \"``isTime()``\", \"Returns true if the axis is a time axis.\"\n", + " \"``Integer``\", \"``len(axis)``\", \"The length of the axis if one-dimensional. If multidimensional, the length of the first dimension.\"\n", + " \"``Integer``\", \"``size()``\", \"The number of elements in the axis.\"\n", + " \"``String``\", \"``typecode()``\", \"The ``Numpy`` datatype identifier.\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Methods, Additional to CoordinateAxis\n", + "\n", + "\n", + " \"``List`` of component times\", \"``asComponentTime(calendar=None)``\", \"``Array`` version of ``cdtime tocomp``. Returns a ``List`` of component times.\"\n", + " \"``List`` of relative times\", \"``asRelativeTime()``\", \"``Array`` version of ``cdtime torel``. Returns a ``List`` of relative times.\"\n", + " \"``None``\", \"``designateCircular(modulo, persistent=0)``\", \"Designate the axis to be circular. \n", + " * ``modulo`` is the modulus value.\n", + " * Any given axis value ``x`` is treated as equivalent to ``x + modulus``.\n", + " * If ``persistent`` is ``True``, the external file or dataset (if any) is modified. \n", + " * By default, the designation is temporary.\"\n", + " \"``Integer``\", \"``isCircular()``\", \"Returns ``True`` if the axis has circular topology. An axis is defined as circular if:\n", + "\n", + " * ``axis.topology == 'circular'``, or\n", + " * ``axis.topology`` is undefined, and the axis is a longitude. \n", + " * The default cycle for circular axes is 360.0\"\n", + " \"``Integer``\", \"``isLinear()``\", \"Returns ``True`` if the axis has a linear representation.\"\n", + " \"``Tuple``\", \"``mapInterval(interval)``\", \"Same as ``mapIntervalExt``, but returns only the tuple ``(i,j)``, and ``wraparound`` is restricted to one cycle.\"\n", + " \"``(i,j,k)``\", \"``mapIntervalExt(interval)``\", \"Map a coordinate interval to an index ``interval``. ``interval`` is a tuple having one of the forms:\n", + "\n", + " * ``(x,y)``\n", + " * ``(x,y,indicator)``\n", + " * ``(x,y,indicator,cycle)``\n", + " * ``None or ':'``\n", + " * where ``x`` and ``y`` are coordinates indicating the interval ``[x,y]``, and:\n", + " * ``indicator`` is a two or three-character string, where the first character is ``'c'`` if the interval is closed on the left, ``'o'`` if open, and the second character has the same meaning for the right-hand point. If present, the third character specifies how the interval should be intersected with the axi\n", + " * ``'n'`` - select node values which are contained in the interva\n", + " * ``'b'`` -select axis elements for which the corresponding cell boundary intersects the interval\n", + " * ``'e'`` - same as n, but include an extra node on either sid\n", + " * ``'s'`` - select axis elements for which the cell boundary is a subset of the interval\n", + " * The default indicator is ‘ccn’, that is, the interval is closed, and nodes in the interval are selected.\n", + " * If ``cycle`` is specified, the axis is treated as circular with the given cycle value. By default, if ``axis.isCircular()`` is true, the axis is treated as circular with a default modulus of ``360.0``.\n", + " * An interval of ``None`` or ``':'`` returns the full index interval of the axis.\n", + " * The method returns the corresponding index interval as a 3tuple ``(i,j,k)``, where ``k`` is the integer stride, and ``[i.j)`` is the half-open index interval ``i <= k < j`` ``(i >= k > j if k < 0)``, or ``none`` if the intersection is empty.\n", + " * for an axis which is circular (``axis.topology == 'circular'``), ``[i,j)`` is interpreted as follows, where ``n = len(axis)``\n", + " * if ``0 <= i < n`` and ``0 <= j <= n``, the interval does not wrap around the axis endpoint.\n", + " * otherwise the interval wraps around the axis endpoint.\n", + " * see also: ``mapinterval``, ``variable.subregion()``\"\n", + " \"``transientaxis``\", \"``subaxis(i,j,k=1)``\", \"create an axis associated with the integer range ``[i:j:k]``.\n", + " * the stride ``k`` can be positive or negative. \n", + " * wraparound is supported for longitude dimensions or those with a modulus attribute.\" \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CoordinateAxis Slice Operators\n", + "\n", + " \"``[i]``\", \"the ``ith`` element, starting with index ``0``\"\n", + " \"``[i:j]``\", \"the ``ith`` element through, but not including, element ``j``\"\n", + " \"``[i:]``\", \"the ``ith`` element through and including the end\"\n", + " \"``[:j]``\", \"the beginning element through, but not including, element ``j``\"\n", + " \"``[:]``\", \"the entire array\"\n", + " \"``[i:j:k]``\", \"every ``kth`` element, starting at ``i``, through but not including ``j``\"\n", + " \"``[-i]``\", \"the ``ith`` element from the end. ``-1`` is the last element.\n", + "\n", + " **Example:** a longitude axis has value\n", + "\n", + " * ``[0.0, 2.0, ..., 358.0]``\n", + " * of length ``180``\n", + " * map the coordinate interval: \n", + " * ``-5.0 <= x < 5.0`` to index interval(s), with wraparound. the result index interval \n", + " * ``-2 <= n < 3`` wraps around, since \n", + " * ``-2 < 0``, and has a stride of ``1`` \n", + " * this is equivalent to the two contiguous index intervals \n", + " * ``2 <= n < 0`` and ``0 <= n < 3``\"\n", + " \n", + "Example 1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'axis' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maxis\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misCircular\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0maxis\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmapIntervalExt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m5.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m5.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'co'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'axis' is not defined" + ] + } + ], + "source": [ + "axis.isCircular()\n", + "1\n", + "axis.mapIntervalExt((-5.0,5.0,'co'))\n", + "(-2,3,1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile\n", + "\n", + "A ``CdmsFile`` is a physical file, accessible via the ``cdunif``\n", + "interface. netCDF files are accessible in read-write mode. All other\n", + "formats (DRS, HDF, GrADS/GRIB, POP, QL) are accessible read-only.\n", + "\n", + "As of CDMS V3, the legacy cuDataset interface is also supported by\n", + "Cdms-Files. See “cu Module”." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Internal Attributes\n", + "\n", + " \"``Dictionary``\", \"``attributes``\", \"Global, external file attributes\"\n", + " \"``Dictionary``\", \"``axes``\", \"Axis objects contained in the file.\"\n", + " \"``Dictionary``\", \"``grids``\", \"Grids contained in the file.\"\n", + " \"``String``\", \"``id``\", \"File pathname.\"\n", + " \"``Dictionary``\", \"``variables``\", \"Variables contained in the file.\"\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Constructors\n", + "\n", + " \"``fileobj = cdms.open(path, mode)``\", \"Open the file specified by path returning a CdmsFile object. \n", + " * ``path`` is the file pathname, a string. \n", + " * ``mode`` is the open mode indicator, as listed in `Open Modes <#id3>`_.\" \n", + " \"``fileobj = cdms.createDataset(path)``\", \"Create the file specified by path, a string.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Methods Object Name Transient Variable\n", + "\n", + "\n", + " \"``Transient-Variable``\", \"``fileobj(varname, selector)``\", \"Calling a ``CdmsFile`` object as a function reads the region of data specified by the Selectors. The result is a transient variable, unless ``raw = 1`` is specified. See `Selectors <#id14>`_ .\n", + " \n", + " **Example:** The following reads data for variable 'prc', year 1980:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdms' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'test.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'prc'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1980-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1981-1'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdms' is not defined" + ] + } + ], + "source": [ + "f = cdms.open('test.nc')\n", + "x = f('prc', time=('1980-1','1981-1'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"Variable, Axis, or Grid\", \"fileobj['id']\", \"Get the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable.\n", + "\n", + "**Example:** The following gets the persistent variable" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m ``v``, equivalent to\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "``v``, equivalent to\n", + "``v = f.variables['prc']``.\n", + "f = cdms.open('sample.nc')\n", + "v = f['prc']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: The following gets the axis named time, equivalent to" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m ``t = f.axes['time']``.\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "``t = f.axes['time']``.\n", + "``t = f['time']``" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "None \tclose() \tClose the file." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Methods Copy Axis, Grid\n", + "\n", + " \"``Axis``\", \"``copyAxis(axis, newname=None)``\", \"Copy ``axis`` values and attributes to a new axis in the file. \n", + " * The returned object is persistent: it can be used to write axis data to or read axis data from the file.\n", + " * If an axis already exists in the file, having the same name and coordinate values, it is returned. It is an error if an axis of the same name exists, but with different coordinate values. \n", + " * ``axis`` is the axis object to be copied. \n", + " * ``newname``, if specified, is the string identifier of the new axis object. If not specified, the identifier of the input axis is used.\"\n", + " \"``Grid``\", \"``copyGrid(grid, newname=None)``\", \"Copy grid values and attributes to a new grid in the file. \n", + " * The returned grid is persistent. \n", + " * If a grid already exists in the file, having the same name and axes, it is returned. An error is raised if a grid of the same name exists, having different axes. \n", + " * ``grid`` is the grid object to be copied.\n", + " * ``newname``, if specified is the string identifier of the new grid object. If unspecified, the identifier of the input grid is used.\"\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Methods Create Axis, RectGrid and Variable\n", + "\n", + " \"``Axis``\", \"``createAxis(id,ar, unlimited=0)``\", \"Create a new ``Axis``. \n", + " * This is a persistent object which can be used to read or write axis data to the file.\n", + " * ``id`` is an alphanumeric string identifier, containing no blanks. \n", + " * ``ar`` is the one-dimensional axis array. \n", + " * Set ``unlimited`` to ``cdms.Unlimited`` to indicate that the axis is extensible.\"\n", + " \"``RectGrid``\", \"``createRectGrid(id,lat, lon,order,type='generic', mask=None)``\", \"Create a ``RectGrid`` in the file. \n", + " * This is not a persistent object: the order, type, and mask are not written to the file. However, the grid may be used for regridding operations. \n", + " * ``lat`` is a latitude axis in the file. \n", + " * ``lon`` is a longitude axis in the file. \n", + " * ``order`` is a string with value ``'yx'`` (the latitude) or ``'xy'`` (the first grid dimension is longitude). \n", + " * ``type`` is one of ``'gaussian'``,\\ ``'uniform'``,\\ ``'equalarea'`` , or ``'generic'``.\n", + " * If specified, ``mask`` is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid.\"\n", + " \"``Variable``\", \"``createVariable(Stringid,String datatype,Listaxes,fill_value=None)``\", \"Create a new Variable. \n", + " * This is a persistent object which can be used to read or write variable data to the file. \n", + " * ``id`` is a String name which is unique with respect to all other objects in the file.\n", + " * ``datatype`` is an ``MV2`` typecode, e.g., ``MV2.Float``, ``MV2.Int``.\n", + " * ``axes`` is a list of Axis and/or Grid objects. \n", + " * ``fill_value`` is the missing value (optional).\"\n", + " \"``Variable``\", \"``createVariableCopy(var, newname=None)``\", \"Create a new ``Variable``, with the same name, axes, and attributes as the input variable.\n", + " * An error is raised if a variable of the same name exists in the file. \n", + " * ``var`` is the ``Variable`` to be copied. \n", + " * ``newname``, if specified is the name of the new variable. If unspecified, the returned variable has the same name as ``var``.\n", + "\n", + " **Note:** Unlike copyAxis, the actual data is not copied to the new variable.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Methods Read CurveGrid, Generic-Grid\n", + "\n", + " \"``CurveGrid`` or ``Generic-Grid``\", \"``readScripGrid (self,whichGrid='destination', check-Grid=1)``\", \"Read a curvilinear or generic grid from a SCRIP netCDF file. \n", + " * The file can be a SCRIP grid file or remapping file. \n", + " * If a mapping file, ``whichGrid`` chooses the grid to read, either ``'source'`` or ``'destination'``.\n", + " * If ``checkGrid`` is ``1`` (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. \n", + " * The repair consists of shifting the cell vertices to the same side modulo 360 degrees.\"\n", + " \"``None``\", \"``sync()``\", \"Writes any pending changes to the file.\"\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CdmsFile Methods Write Variable\n", + "\n", + "\n", + " \"``Variable``\", \"``write(var,attributes=None,axes=None, extbounds=None,id=None,extend=None, fill_value=None, index=None, typecode=None)``\",\"Write a variable or array to the file.\n", + " * The return value is the associated file variable.\n", + " * If the variable does not exist in the file, it is first defined and all attributes written, then the data is written. By default, the time dimension of the variable is defined as the unlimited dimension of the file.\n", + " * If the data is already defined, then data is extended or overwritten depending on the value of keywords ``extend`` and ``index``, and the unlimited dimension values associated with ``var``.\n", + "\n", + " * ``var`` is a Variable, masked array, or Numpy array.\n", + " * ``attributes`` is the attribute dictionary for the variable. The default is ``var.attributes``.\n", + " * ``axes`` is the list of file axes comprising the domain of the variable. The default is to copy ``var.getAxisList()``.\n", + " * ``extbounds`` is the unlimited dimension bounds. Defaults to ``var.getAxis(0).getBounds()``.\n", + " * ``id`` is the variable name in the file. Default is ``var.id``.\n", + " * ``extend = 1`` causes the first dimension to be unlimited: iteratively writeable. \n", + " * The default is ``None``, in which case the first dimension is extensible if it is ``time.Set`` to ``0`` to turn off this behaviour.\n", + " * ``fill_value`` is the missing value flag.\n", + " * ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension.\n", + " **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CDMS Datatypes\n", + "\n", + " \"``CdChar``\", \"character\"\n", + " \"``CdDouble``\", \"double-precision floating-point\"\n", + " \"``CdFloat``\", \"floating-point\"\n", + " \"``CdInt``\", \"integer\"\n", + " \"``CdLong``\", \"long integer\"\n", + " \"``CdShort``\", \"short integer\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Database\n", + "\n", + "A Database is a collection of datasets and other CDMS objects. It\n", + "consists of a hierarchical collection of objects, with the database\n", + "being at the root, or top of the hierarchy. A database is used to:\n", + "\n", + "- search for metadata\n", + "- access data\n", + "- provide authentication and access control for data and metadata\n", + "\n", + "The figure below illustrates several important points:\n", + "\n", + "- Each object in the database has a relative name of the form tag=id.\n", + " The id of an object is unique with respect to all objects contained\n", + " in the parent.\n", + "\n", + "- The name of the object consists of its relative name followed by the\n", + " relative name(s) of its antecedent objects, up to and including the\n", + " database name. In the figure below, one of the variables has name\n", + " ``\"variable=ua,dataset=ncep_reanalysis_mo,database=CDMS\"``.\n", + "\n", + "- Subordinate objects are thought of as being contained in the parent.\n", + " In this example, the database ‘CDMS’ contains two datasets, each of\n", + " which contain several variables." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Overview\n", + "\n", + "To access a database:\n", + "\n", + "#. Open a connection. The connect method opens a database connection. Connect takes a database URI and returns a database object:\n", + " ``db=cdms.connect(\"ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US\")``\n", + "\n", + "#. Search the database, locating one or more datasets, variables, and/or\n", + " other objects.\n", + "\n", + " The database searchFilter method searches the database. A single\n", + " database connection may be used for an arbitrary number of searches.\n", + "\n", + " **Example**: Find all observed datasets\n", + "\n", + " ``result = db.searchFilter(category=\"observed\",tag=\"dataset\")``\n", + "\n", + " Searches can be restricted to a subhierarchy of the database.\n", + "\n", + " **Example:** Search just the dataset ``'ncep_reanalysis_mo'``:\n", + "\n", + " ``result = db.searchFilter(relbase=\"dataset=ncep_reanalysis\")``\n", + "\n", + "#. Refine the search results if necessary. The result of a search can be\n", + " narrowed with the searchPredicate method.\n", + "#. Process the results. A search result consists of a sequence of\n", + " entries. Each entry has a name, the name of the CDMS object, and an\n", + " attribute dictionary, consisting of the attributes located by the\n", + " search:\n", + "\n", + " `` for entry in result: print entry.name, entry.attributes``\n", + "\n", + "#. Access the data. The CDMS object associated with an entry is obtained\n", + " from the getObject method:\n", + "\n", + " ``obj = entry.getObject()``\n", + "\n", + " If the id of a dataset is known, the dataset can be opened directly\n", + " with the open method:\n", + "\n", + " ``dset = db.open(\"ncep_reanalysis_mo\")``\n", + "\n", + "#. Close the database connection:\n", + "\n", + " ``db.close()``\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Database Internal Attributes\n", + "\n", + "\n", + " \"``Dictionary``\", \"``attributes``\", \"Database attribute dictionary\"\n", + " \"``LDAP``\", \"``db``\", \"(LDAP only) LDAP database object\"\n", + " \"``String``\", \"``netloc``\", \"Hostname, for server-based databases\"\n", + " \"``String``\", \"``path``\", \"path name\"\n", + " \"``String``\", \"``uri``\", \"Uniform Resource Identifier\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Database Constructors\n", + "\n", + " \"``db = cdms.connect(uri=None, user='', password='')``\", \"Connect to the database. ``uri`` is the Universal Resource Indentifier of the database. The form of the URI depends on the implementation of the database.\n", + " * For a Lightweight Directory Access Protocol (LDAP) database, the form is: ``ldap://host[:port]/dbname``.\n", + " * For example, if the database is located on host dbhost.llnl.gov, and is named ``'database=CDMS,ou=PCMDI,o=LLNL,c=US'``, the URI is: ``ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US``. \n", + " * If unspecified, the URI defaults to the value of environment variable CDMSROOT. ``user`` is the user ID. \n", + " * If unspecified, an anonymous connection is made. ``password`` is the user password. A password is not required for an anonymous connection\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Database Methods\n", + "\n", + " \"None\", \"``close()``\", \"Close a database\"\n", + " \"List\", \"``listDatasets()``\", \"Return a list of the dataset IDs in this database. A dataset ID can be passed to the ``open`` command.\"\n", + " \"Dataset\", \"``open(dsetid, mode='r')``\", \"Open a dataset.\n", + "\n", + " * ``dsetid``, is the string dataset identifier\n", + "\n", + " * ``mode``, is the open mode, 'r' - read-only, 'r+' - read-write, 'w' - create.\n", + "\n", + " * ``openDataset``, is a synonym for ``open``.\"\n", + " \"SearchResult\",\"``searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None)``\",\"Search a CDMS database.\n", + " * ``filter`` is the string search filter. Simple filters have the form 'tag = value'. Simple filters can be combined using logical operators '&', '\\|', '!' in prefix notation. \n", + " **Example:**\n", + "\n", + " * The filter ``'(&(objec)(id=cli))'`` finds all variables named 'cli'.\n", + " * A formal definition of search filters is provided in the following section.\n", + " * ``tag`` restricts the search to objects with that tag ('dataset' | 'variable' | 'database' | 'axis' | 'grid').\n", + " * ``relbase`` is the relative name of the base object of the search. The search is restricted to the base object and all objects below it in the hierarchy.\n", + "\n", + " **Example:**\n", + "\n", + " * To search only dataset 'ncep_reanalysis_mo', specify:\n", + " * ``relbase='dataset=ncep_reanalysis_mo'``\n", + " * To search only variable 'ua' in 'ncep_reanalysis_mo', use:\n", + " * ``relbase='variable=ua, dataset=ncep_reanalysis_mo'``\n", + " If no base is specified, the entire database is searched. See the ``scope`` argument also.\n", + "\n", + " * ``scope`` is the search scope (**Subtree** | **Onelevel** | **Base**).\n", + " * **Subtree** searches the base object and its descendants.\n", + " * **Onelevel** searches the base object and its immediate descendants.\n", + " * **Base**\\ searches the base object alone.\n", + " * The default is **Subtree**.\n", + " * ``attnames``: list of attribute names. Restricts the attributes returned. If ``None``, all attributes are returned. Attributes 'id' and 'objectclass' are always included in the list.\n", + " * ``timeout``: integer number of seconds before timeout. The default is no timeout.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Searching a Database\n", + "\n", + "The ``searchFilter`` method is used to search a database. The result is\n", + "called a search result, and consists of a sequence of result entries.\n", + "\n", + "In its simplest form, ``searchFilter`` takes an argument consisting of a\n", + "string filter. The search returns a sequence of entries, corresponding\n", + "to those objects having an attribute which matches the filter. Simple\n", + "filters have the form (tag = value), where value can contain wildcards.\n", + "For example:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m (id = ncep*)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "(id = ncep*)\n", + "(project = AMIP2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note** Simple filters can be combined with the logical operators '&', '|', '!'. For example, \n", + "\n", + " mode, is the open mode, ‘r’ - read-only, ‘r+’ - read-write, ‘w’ - create.\n", + "\n", + "(&(id = bmrc*)(project = AMIP2))\n", + "\n", + " To search only dataset ‘ncep_reanalysis_mo’, specify:\n", + " relbase='dataset=ncep_reanalysis_mo'\n", + " To search only variable ‘ua’ in ‘ncep_reanalysis_mo’, use:\n", + " relbase='variable=ua, dataset=ncep_reanalysis_mo'\n", + "\n", + " If no base is specified, the entire database is searched. See the scope argument also.\n", + "\n", + " scope is the search scope (Subtree | Onelevel | Base).\n", + " Subtree searches the base object and its descendants.\n", + " Onelevel searches the base object and its immediate descendants.\n", + " Basesearches the base object alone.\n", + " The default is Subtree.\n", + " attnames: list of attribute names. Restricts the attributes returned. If None, all attributes are returned. Attributes ‘id’ and ‘objectclass’ are always included in the list.\n", + " timeout: integer number of seconds before timeout. The default is no timeout.”\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m (&(id = bmrc*)(project = AMIP2))\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "(&(id = bmrc*)(project = AMIP2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "matches all objects with id starting with bmrc, and a project attribute\n", + "with value ‘AMIP2’.\n", + "\n", + "Formally, search filters are strings defined as follows:\n", + "Attribute names are defined in the chapter on “Climate Data Markup Language (CDML)”. In addition, some special attributes are defined for convenience:\n", + "\n", + " category is either “experimental” or “observed”\n", + " parentid is the ID of the parent dataset\n", + " project is a project identifier, e.g., “AMIP2”\n", + " objectclass is the list of tags associated with the object.\n", + "\n", + "The set of objects searched is called the search scope. The top object in the hierarchy is the base object. By default, all objects in the database are searched, that is, the database is the base object. If the database is very large, this may result in an unnecessarily slow or inefficient search. To remedy this the search scope can be limited in several ways:\n", + "\n", + " The base object can be changed.\n", + " The scope can be limited to the base object and one level below, or to just the base object.\n", + " The search can be restricted to objects of a given class (dataset, variable, etc.)\n", + " The search can be restricted to return only a subset of the object attributes\n", + " The search can be restricted to the result of a previous search.\n", + " A search result is accessed sequentially within a for loop:\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'(&(category=obs*)(id=ncep*))'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mentry\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mentry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "result = db.searchFilter('(&(category=obs*)(id=ncep*))')\n", + "for entry in result:\n", + " print entry.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Search results can be narrowed using searchPredicate. In the following example, the result of one search is itself searched for all variables defined on a 94x192 grid:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 9)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m9\u001b[0m\n\u001b[0;31m for entry in result2: print entry.name\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "result = db.searchFilter('parentid=ncep*',tag=\"variable\")\n", + "len(result)\n", + "\n", + "result2 = result.searchPredicate(lambda x:\n", + "\n", + "\n", + "len(result2)\n", + "\n", + "for entry in result2: print entry.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "2.7.6. Table SearchResult Methods\n", + "Type \tMethod \tDefinition\n", + "ResultEntry \t[i] \tReturn the i-th search result. Results can also be returned in a for loop: for entry in db.searchResult(tag='dataset'):\n", + "Integer \tlen() \tNumber of entries in the result.\n", + "SearchResult \tsearchPredicate(predicate, tag=None) \t\n", + "\n", + "Refine a search result, with a predicate search.\n", + "\n", + " predicate is a function which takes a single CDMS object and returns true (1) if the object satisfies the predicate, 0 if not.\n", + " tag restricts the search to objects of the class denoted by the tag.\n", + "\n", + " Note:: In the current implementation, searchPredicate is much less efficient than searchFilter. For best performance, use searchFilter to narrow the scope of the search, then use searchPredicate for more general searches.\n", + "\n", + "A search result is a sequence of result entries. Each entry has a string name, the name of the object in the database hierarchy, and an attribute dictionary. An entry corresponds to an object found by the search, but differs from the object, in that only the attributes requested are associated with the entry. In general, there will be much more information defined for the associated CDMS object, which is retrieved with the getObject method.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.7.7. Table ResultEntry Attributes\n", + "Type \tMethod \tDefinition\n", + "String \tname \tThe name of this entry in the database.\n", + "Dictionary \tattributes \tThe attributes returned from the search. attributes[key] is a list of all string values associated with the key" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.7.8. Table ResultEntry Methods\n", + "Type \tMethod \tDefinition\n", + "CdmsObj \tgetObject() \t\n", + "\n", + "Return the CDMS object associated with this entry.\n", + " Note: For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable.\n", + "\n", + "CdmsObj \tgetObject() \t\n", + "\n", + "Return the CDMS object associated with this entry.\n", + " Note: For many search applications it is unnecessary to access the associated CDMS object. For best performance this function should be used only when necessary, for example, to retrieve data associated with a variable. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.7.9. Accessing data\n", + "\n", + "To access data via CDMS:\n", + "\n", + " Locate the dataset ID. This may involve searching the metadata.\n", + " Open the dataset, using the open method.\n", + " Reference the portion of the variable to be read.\n", + "\n", + "In the next example, a portion of variable ‘ua’ is read from dataset ‘ncep_reanalysis_mo’:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdset\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ncep_reanalysis_mo'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mua\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdset\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'ua'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mua\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "dset = db.open('ncep_reanalysis_mo')\n", + "ua = dset.variables['ua']\n", + "data = ua[0,0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.7.10. Examples of Database Searches\n", + "\n", + "In the following examples, db is the database opened with:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdms' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'cdms' is not defined" + ] + } + ], + "source": [ + "db = cdms.connect()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This defaults to the database defined in environment variable CDMSROOT.\n", + "\n", + "Example: List all variables in dataset ‘ncep_reanalysis_mo’:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mentry\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilter\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"parentid=ncep_reanalysis_mo\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtag\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"variable\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mentry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "for entry in db.searchFilter(filter = \"parentid=ncep_reanalysis_mo\", tag = \"variable\"):\n", + " print entry.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: Find all axes with bounds defined:\n", + "\n", + "Example: Locate all GDT datasets:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mentry\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilter\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"Conventions=GDT*\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"dataset\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mentry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "for entry in db.searchFilter(filter=\"Conventions=GDT*\",tag=\"dataset\"):\n", + " print entry.name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: Find all variables with missing time values, in observed datasets:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mentry\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilter\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"(&(project=CMIP2)(id=hfss))\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtag\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"variable\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mentry\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetObject\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparent\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "for entry in db.searchFilter(filter = \"(&(project=CMIP2)(id=hfss))\", tag = \"variable\"):\n", + " print entry.getObject().parent.id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: Find all observed variables on 73x144 grids:\n", + "\n", + "Example: Find all CMIP2 datasets having a variable with id “hfss”:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'db' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"database\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"database\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"dataset\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"datasets\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"variable\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"variables\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msearchFilter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtag\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"axis\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"axes\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'db' is not defined" + ] + } + ], + "source": [ + "print len(db.searchFilter(tag=\"database\")),\"database\"\n", + "print len(db.searchFilter(tag=\"dataset\")),\"datasets\"\n", + "print len(db.searchFilter(tag=\"variable\")),\"variables\"\n", + "print len(db.searchFilter(tag=\"axis\")),\"axes\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Example: Find all observed variables on 73x144 grids:\n", + "\"Dictionary\", \"``attributes``\", \"Dataset external attributes.\"\n", + "\"Dictionary\", \"``axes``\", \"Axes contained in the dataset.\"\n", + "\"String\", \"``datapath``\", \"Path of data files, relative to the parent database. If no parent, the datapath is absolute.\"\n", + "\"Dictionary\", \"``grids``\", \"Grids contained in the dataset.\"\n", + "\"String\", \"``mode``\", \"Open mode.\"\n", + "\"Database\", \"``parent``\", \"Database which contains this dataset. If the dataset is not part of a database, the value is ``None``.\"\n", + "\"String\", \"``uri``\", \"Uniform Resource Identifier of this dataset.\"\n", + "\"Dictionary\", \"``variables``\", \"Variables contained in the dataset.\"\n", + "\"Dictionary\", \"``xlinks``\", \"External links contained in the dataset.\"\n", + "\n", + "Example: Find all observed variables with more than 1000 timepoints:\n", + "\n", + "\n", + "1 \"‘r’\", \"read-only\"\n", + "2 \"‘r+’\", \"read-write\"\n", + "3 \"‘a’\", \"read-write. Open the file if it exists, otherwise create a new file\"\n", + "4 \"‘w’\", \"Create a new file, read-write\"\n", + "Example: Find the total number of each type of object in the database:\n", + "\n", + " f = cdms.open(‘test. xml’)\n", + " x = f(‘prc’, time=(‘1980-1’,‘1981-1’))”\n", + "\n", + " “Variable, Axis, or Grid”, “datasetobj['id']”, “The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns None if not found.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "2.8. Dataset\n", + "\n", + "A Dataset is a virtual file. It consists of a metafile, in CDML/XML representation, and one or more data files.\n", + "\n", + "As of CDMS V3, the legacy cuDataset interface is supported by Datasets. See “cu Module”.\n", + "2.8.1. Table Dataset Internal Attributes\n", + "Type \tName \tDescription\n", + "Dictionary \tattributes \tDataset external attributes.\n", + "Dictionary \taxes \tAxes contained in the dataset.\n", + "String \tdatapath \tPath of data files, relative to the parent database. If no parent, the datapath is absolute.\n", + "Dictionary \tgrids \tGrids contained in the dataset.\n", + "String \tmode \tOpen mode.\n", + "Database \tparent \tDatabase which contains this dataset. If the dataset is not part of a database, the value is None.\n", + "String \turi \tUniform Resource Identifier of this dataset.\n", + "Dictionary \tvariables \tVariables contained in the dataset.\n", + "Dictionary \txlinks \tExternal links contained in the dataset.\n", + "2.8.2. Table Dataset Constructors\n", + "Constructor \tDescription\n", + "datasetobj = cdms.open(String uri, String mode='r') \tOpen the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in Open Modes . openDataset is a synonym for open\n", + "2.8.3. Table Open Modes\n", + "Mode \tDefinition\n", + "‘r’ \tread-only\n", + "‘r+’ \tread-write\n", + "‘a’ \tread-write. Open the file if it exists, otherwise create a new file\n", + "‘w’ \tCreate a new file, read-write\n", + "2.8.4. Table Dataset Methods\n", + "Type \tDefinition \tDescription\n", + "Transient-Variable \tdatasetobj(varname, selector) \t\n", + "\n", + "Calling a Dataset object as a function reads the region of data defined by the selector. The result is a transient variable, unless raw = 1 is specified. See ‘Selectors’.\n", + "\n", + " Example: The following reads data for variable ‘prc’, year 1980:\n", + "\n", + " f = cdms.open(‘test. xml’)\n", + " x = f(‘prc’, time=(‘1980-1’,‘1981-1’))\n", + "\n", + "Variable, Axis, or Grid \tdatasetobj['id'] \t\n", + "\n", + "The square bracket operator applied to a dataset gets the persistent variable, axis or grid object having the string identifier. This does not read the data for a variable. Returns None if not found.\n", + "\n", + " Example:\n", + "\n", + " f = cdms.open(‘sampl e.xml’)\n", + " v = f[‘prc’]\n", + " gets the persistent variable v, equivalent to v =f.variab les['prc'].\n", + "\n", + " Example:\n", + " t = f['time'] gets the axis named ‘time’, equivalent to t = f.axes['time']\n", + "\n", + "None \tclose() \tClose the dataset.\n", + "RectGrid \tcreateRectGrid(id, lat, lon,order, type='generic', mask=None) \t\n", + "\n", + "Create a RectGrid in the dataset. This is not a persistent object: the order, type, and mask are not written to the dataset. However, the grid may be used for regridding operations.\n", + "\n", + " lat is a latitude axis in the dataset.\n", + " lon is a longitude axis in the dataset.\n", + " order is a string with value ‘yx’ (the first grid dimension is latitude) or ‘xy’ (the first grid dimension is longitude).\n", + " type is one of ‘gaussian’,’uniform’,’eq ualarea’,or ‘generic’\n", + " If specified, mask is a two-dimensional, logical Numpy array (all values are zero or one) with the same shape as the grid.\n", + "\n", + "Axis \tgetAxis(id) \t\n", + "\n", + "Get an axis object from the file or dataset.\n", + "\n", + " id is the string axis identifier.\n", + "\n", + "Grid \tgetGrid(id) \t\n", + "\n", + "Get a grid object from a file or dataset.\n", + "\n", + " id is the string grid identifier.\n", + "\n", + "List \tgetPaths() \tGet a sorted list of pathnames of datafiles which comprise the dataset. This does not include the XML metafile path, which is stored in the .uri attribute.\n", + "Variable \tgetVariable(id) \t\n", + "\n", + "Get a variable object from a file or dataset.\n", + "\n", + " id is the string variable identifier.\n", + "\n", + "CurveGrid or GenericGrid \treadScripGrid(self, whichGrid='destination', check-orGeneric-Grid=1) \t\n", + "\n", + "Read a curvilinear orgeneric grid from a SCRIP dataset. The dataset can be a SCRIP grid file or remappingfile.\n", + "\n", + " If a mapping file, whichGrid chooses the grid to read, either 'source' or 'destination'.\n", + " If checkGrid is 1 (default), the grid cells are checked for convexity, and ‘repaired’ if necessary. Grid cells may appear to be nonconvex if they cross a 0 / 2pi boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.\n", + "\n", + "None \tsync() \tWrite any pending changes to the dataset.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.9. MV Module\n", + "\n", + "The fundamental CDMS data object is the variable. A variable is comprised of:\n", + "\n", + " a masked data array, as defined in the NumPy MV2 module.\n", + " a domain: an ordered list of axes and/or grids.\n", + " an attribute dictionary.\n", + "\n", + "The MV module is a work-alike replacement for the MV2 module, that carries along the domain and attribute information where appropriate. MV provides the same set of functions as MV2. However, MV functions generate transient variables as results. Often this simplifies scripts that perform computation. MV2 is part of the Python Numpy package, documented at http://www.numpy.org.\n", + "\n", + "MV can be imported with the command:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named MV", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mMV\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mImportError\u001b[0m: No module named MV" + ] + } + ], + "source": [ + "import MV" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The command" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named MV", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mMV\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mImportError\u001b[0m: No module named MV" + ] + } + ], + "source": [ + "from MV import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "allows use of MV commands without any prefix.\n", + "\n", + "Table Variable Constructors in module MV, lists the constructors in MV. All functions return a transient variable. In most cases the keywords axes, attributes, and id are available. axes is a list of axis objects which specifies the domain of the variable. attributes is a dictionary. id is a special attribute string that serves as the identifier of the variable, and should not contain blanks or non-printing characters. It is used when the variable is plotted or written to a file. Since the id is just an attribute, it can also be set like any attribute:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'var' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mvar\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'temperature'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'var' is not defined" + ] + } + ], + "source": [ + "var.id = 'temperature'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For completeness MV provides access to all the MV2 functions. The functions not listed in the following tables are identical to the corresponding MV2 function: allclose, allequal, common_fill_value, compress, create_mask, dot, e, fill_value, filled, get_print_limit, getmask, getmaskarray, identity, indices, innerproduct, isMV2, isMaskedArray, is_mask, isarray, make_mask, make_mask_none, mask_or, masked, pi, put, putmask, rank, ravel, set_fill_value, set_print_limit, shape, size. See the documentation at http://numpy.sourceforge.net for a description of these functions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "2.9.1. Table Variable Constructors in Module MV\n", + "Constructor \tDescription\n", + "arrayrange(start, stop=None, step=1, typecode=None, axis=None, attributes=None, id=None) \tJust like MV2.arange() except it returns a variable whose type can be specfied by the keyword argument typecode. The axis, attribute dictionary, and string identifier of the result variable may be specified. Synonym: arange\n", + "masked_array(a, mask=None, fill_value=None, axes=None, attributes=None, id=None) \tSame as MV2.masked_array but creates a variable instead. If no axes are specified, the result has default axes, otherwise axes is a list of axis objects matching a.shape.\n", + "masked_object(data,value, copy=1,savespace=0,axes=None, attributes=None, id=None) \tCreate variable masked where exactly data equal to value. Create the variable with the given list of axis objects, attribute dictionary, and string id.\n", + "masked_values(data,value, rtol=1e-05, atol=1e-08, copy=1, savespace=0, axes=None, attributes=None, id=None) \tConstructs a variable with the given list of axes and attribute dictionary, whose mask is set at those places where abs(data - value) > atol + rtol * abs(data). This is a careful way of saying that those elements of the data that have value = value (to within a tolerance) are to be treated as invalid. If data is not of a floating point type, calls masked_object instead.\n", + "ones(shape, typecode='l',savespace=0,axes=none, attributes=none, id=none) \treturn an array of all ones of the given length or shape.\n", + "reshape(a,newshape, axes=none, attributes=none, id=none) \tcopy of a with a new shape.\n", + "resize(a,newshape, axes=none, attributes=none, id=none) \treturn a new array with the specified shape. the original arrays total size can be any size.\n", + "zeros(shape,typecode='l',savespace=0, axes=none, attributes=none, id=none) \tan array of all zeros of the given length or shape\n", + "\n", + "The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.9.2. Table MV Functions\n", + "Function \tDescription\n", + "argsort(x, axis=-1, fill_value=None) \tReturn a Numpy array of indices for sorting along a given axis.\n", + "asarray(data, typecode=None) \t\n", + "\n", + "Same as cdms.createVariable(data, typecode, copy=0).\n", + "\n", + " This is a short way of ensuring that something is an instance of a variable of a given type before proceeding, as in data = asarray(data).\n", + " Also see the variable astype() function.\n", + "\n", + "average(a, axis=0, weights=None) \t\n", + "\n", + "Computes the average value of the non-masked elements of x along the selected axis.\n", + "\n", + " If weights is given, it must match the size and shape of x, and the value returned is: sum(a*weights)/sum(weights)\n", + " In computing these sums, elements that correspond to those that are masked in x or weights are ignored.\n", + "\n", + "choose(condition, t) \t\n", + "\n", + "Has a result shaped like array condition.\n", + "\n", + " t must be a tuple of two arrays t1 and t2.\n", + " Each element of the result is the corresponding element of t1where condition is true, and the corresponding element of t2 where condition is false.\n", + " The result is masked where condition is masked or where the selected element is masked.\n", + "\n", + "concatenate(arrays, axis=0, axisid=None, axisattributes=None) \tConcatenate the arrays along the given axis. Give the extended axis the id and attributes provided - by default, those of the first array.\n", + "count(a, axis=None) \tCount of the non-masked elements in a, or along a certain axis.\n", + "isMaskedVariable(x) \tReturn true if x is an instance of a variable.\n", + "masked_equal(x, value) \tx masked where x equals the scalar value. For floating point values consider masked_values(x, value) instead.\n", + "masked_greater(x, value) \tx masked where x > value\n", + "masked_greater_equal(x, value) \tx masked where x >= value\n", + "masked_less(x, value) \tx masked where x < value\n", + "masked_less_equal(x, value) \tx masked where x ≤ value\n", + "masked_not_equal(x, value) \tx masked where x != value\n", + "masked_outside(x, v1, v2) \tx with mask of all values of x that are outside [v1,v2]\n", + "masked_where(condition, x, copy=1) \t\n", + "\n", + "Return x as a variable masked where condition is true.\n", + "\n", + " Also masked where x or condition masked.\n", + " condition is a masked array having the same shape as x.\n", + "\n", + "maximum(a, b=None) \tCompute the maximum valid values of x if y is None; with two arguments, return the element-wise larger of valid values, and mask the result where either x or y is masked.\n", + "minimum(a, b=None) \tCompute the minimum valid values of x if y is None; with two arguments, return the element-wise smaller of valid values, and mask the result where either x or y is masked.\n", + "outerproduct(a, b) \tReturn a variable such that result[i, j] = a[i] * b[j]. The result will be masked where a[i] or b[j] is masked.\n", + "power(a, b) \ta**b\n", + "product(a, axis=0, fill_value=1) \tProduct of elements along axis using fill_value for missing elements.\n", + "repeat(ar, repeats, axis=0) \tReturn ar repeated repeats times along axis. repeats is a sequence of length ar.shape[axis] telling how many times to repeat each element.\n", + "set_default_fill_value(value_type, value) \t\n", + "\n", + "Set the default fill value for value_type to value.\n", + "\n", + " value_type is a string: ‘real’,’complex’,’character’,’integer’,or ‘object’.\n", + " value should be a scalar or single-element array.\n", + "\n", + "sort(ar, axis=-1) \tSort array ar elementwise along the specified axis. The corresponding axis in the result has dummy values.\n", + "sum(a, axis=0, fill_value=0) \tSum of elements along a certain axis using fill_value for missing.\n", + "take(a, indices, axis=0) \tReturn a selection of items from a. See the documentation in the Numpy manual.\n", + "transpose(ar, axes=None) \tPerform a reordering of the axes of array ar depending on the tuple of indices axes; the default is to reverse the order of the axes.\n", + "where(condition, x, y) \tx where condition is true, y otherwise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.10. HorizontalGrid\n", + "\n", + "A HorizontalGrid represents a latitude-longitude coordinate system. In addition, it optionally describes how lat-lon space is partitioned into cells. Specifically, a HorizontalGrid:\n", + "\n", + " consists of a latitude and longitude coordinate axis.\n", + " may have associated boundary arrays describing the grid cell boundaries,\n", + " may optionally have an associated logical mask.\n", + "\n", + "CDMS supports several types of HorizontalGrids:\n", + "\n", + "2.10.1. Table Grids\n", + "Grid Type \tDefinition\n", + "RectGrid \tAssociated latitude an longitude are 1-D axes, with strictly monotonic values.\n", + "GenericGrid \tLatitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)\n", + "2.10.2. Table HorizontalGrid Internal Attribute\n", + "Type \tName \tDefinition\n", + "Dictionary \tattributes \tExternal attribute dictionary.\n", + "String \tid \tThe grid identifier.\n", + "Dataset or CdmsFile \tparent \tThe dataset or file which contains the grid.\n", + "Tuple \tshape \tThe shape of the grid, a 2-tuple\n", + "2.10.3. Table RectGrid Constructors\n", + "Constructor \tDescription\n", + "cdms.createRectGrid(lat, lon, order, type='generic', mask=None) \tCreate a grid not associated with a file or dataset. See A First Example\n", + "CdmsFile.createRectGrid(id, lat, lon, order, type='generic', mask=None) \tCreate a grid associated with a file. See CdmsFile Constructors\n", + "Dataset.createRectGrid(id, lat, lon, order, type='generic', mask=None) \tCreate a grid associated with a dataset. See Dataset Constructors\n", + "cdms.createGaussianGrid(nlats, xorigin=0.0, order='yx') \tSee A First Example\n", + "cdms.createGenericGrid(latArray, lonArray, latBounds=None, lonBounds=None, order='yx', mask=None) \tSee A First Example\n", + "cdms.createGlobalMeanGrid(grid) \tSee A First Example\n", + "cdms.createRectGrid(lat, lon, order, type='generic', mask=None) \tSee A First Example\n", + "cdms.createUniformGrid(startLat, nlat, deltaLat, startLon, nlon, deltaLon, order='yx', mask=None) \tSee A First Example\n", + "cdms.createZonalGrid(grid) \tSee A First Example\n", + "2.10.4. Table HorizontalGrid Methods\n", + "Type \tMethod \tDescription\n", + "Horizontal-Grid \tclone() \tReturn a transient copy of the grid.\n", + "Axis \tgetAxis(Integer n) \tGet the n-th axis.n is either 0 or 1.\n", + "Tuple \tgetBounds() \t\n", + "\n", + "Get the grid boundary arrays.\n", + "\n", + " Returns a tuple (latitudeArray, longitudeArray), where latitudeArray is a Numpy array of latitude bounds, and similarly for longitudeArray.The shape of latitudeArray and longitudeArray depend on the type of grid:\n", + "\n", + " for rectangular grids with shape (nlat, nlon), the boundary arrays have shape (nlat,2) and (nlon,2).\n", + " for curvilinear grids with shape (nx, ny), the boundary arrays each have shape (nx, ny, 4).\n", + " for generic grids with shape (ncell,), the boundary arrays each have shape (ncell, nvert) where nvert is the maximum number of vertices per cell.\n", + " for rectilinear grids: If no boundary arrays are explicitly defined (in the file or dataset), the result depends on the auto- Bounds mode (see cdms.setAutoBounds) and the grid classification mode (see cdms.setClassifyGrids).\n", + "\n", + " By default, autoBounds mode is enabled, in which case the boundary arrays are generated based on the type of grid.\n", + "\n", + " If disabled, the return value is (None,None).For rectilinear grids:\n", + " The grid classification mode specifies how the grid type is to be determined.\n", + " By default, the grid type (Gaussian, uniform, etc.) is determined by calling grid.classifyInFamily.\n", + " If the mode is ‘off’ grid.getType is used instead.\n", + "\n", + "Axis \tgetLatitude() \tGet the latitude axis of this grid.\n", + "Axis \tgetLongitude() \tGet the latitude axis of this grid.\n", + "Axis \tgetMask() \t\n", + "\n", + "Get the mask array of this grid, if any.\n", + "\n", + " Returns a 2-D Numpy array, having the same shape as the grid.\n", + " If the mask is not explicitly defined, the return value is None.\n", + "\n", + "Axis \tgetMesh(self, transpose=None) \t\n", + "\n", + "Generate a mesh array for the meshfill graphics method.\n", + "\n", + " If transpose is defined to a tuple, say (1,0), first transpose latbounds and lonbounds according to the tuple, in this case (1,0,2).\n", + "\n", + "None \tsetBounds(latBounds, lonBounds, persistent=0) \t\n", + "\n", + "Set the grid boundaries.\n", + "\n", + " latBounds is a NumPy array of shape (n,2), such that the boundaries of the kth axis value are [latBounds[k,0],latBou nds[k,1] ].\n", + " lonBounds is defined similarly for the longitude array.\n", + "\n", + " Note: By default, the boundaries are not written to the file or dataset containing the grid (if any). This allows bounds to be set on read-only files, for regridding. If the optional argument persistent is set to the boundary array is written to the file.\n", + "\n", + "None \tsetMask(mask, persistent=0) \t\n", + "\n", + "Set the grid mask.\n", + "\n", + " If persistent == 1, the mask values are written to the associated file, if any.\n", + " Otherwise, the mask is associated with the grid, but no I/O is generated.\n", + " mask is a two-dimensional, Boolean-valued Numpy array, having the same shape as the grid.\n", + "\n", + "Horizontal-Grid \tsubGridRegion(latInterval, lonInterval) \t\n", + "\n", + "Create a new grid corresponding to the coordinate region defined by latInterval, lonInterv al.\n", + "\n", + " latInterval and lonInterval are the coordinate intervals for latitude and longitude, respectively.\n", + " Each interval is a tuple having one of the forms:\n", + " (x,y)\n", + " (x,y,indicator)\n", + " (x,y,indicator,cycle)\n", + " None\n", + "\n", + " Where x and y are coordinates indicating the interval [x,y), and:\n", + "\n", + " indicator is a two-character string, where the first character is ‘c’ if the interval is closed on the left, ‘o’ if open, and the second character has the same meaning for the right-hand point. (Default: ‘co’).\n", + " If cycle is specified, the axis is treated as circular with the given cycle value.\n", + " By default, if grid.isCircular() is true, the axis is treated as circular with a default value of 360.0.\n", + " An interval of None returns the full index interval of the axis.\n", + " If a mask is defined, the subgrid also has a mask corresponding to the index ranges.\n", + "\n", + " Note: The result grid is not associated with any file or dataset.\n", + "\n", + "Transient-CurveGrid \ttoCurveGrid(gridid=None) \t\n", + "\n", + "Convert to a curvilinear grid.\n", + "\n", + " If the grid is already curvilinear, a copy of the grid object is returned.\n", + " gridid is the string identifier of the resulting curvilinear grid object.\n", + " If unspecified, the grid ID is copied.\n", + "\n", + " Note: This method does not apply to generic grids.\n", + "\n", + " Transient-GenericGrid toGenericGrid(gridid=None) Convert to a generic grid.\n", + " If the grid is already generic, a copy of the grid is returned.\n", + " gridid is the string identifier of the resulting curvilinear grid object.\n", + " If unspecified, the grid ID is copied.\n", + "\n", + "2.10.5. Table RectGrid Methods, Additional to HorizontalGrid Methods\n", + "Type \tMethod \tDescription\n", + "String \tgetOrder() \t\n", + "\n", + "Get the grid ordering, either ‘yx’ if latitude is the first axis, or ‘xy’ if longitude is the first axis.\n", + "\n", + " String getType()\n", + "\n", + " Get the grid type, either ‘gaussian’, ‘uniform’, ‘equalarea’, or ‘generic’.\n", + " (Array,Array) getWeights()\n", + " Get the normalized area weight arrays, as a tuple (latWeights, lonWeights).\n", + " It is assumed that the latitude and longitude axes are defined in degrees.\n", + "\n", + " The latitude weights are defined as:\n", + "\n", + " latWeights[i] = 0.5 * abs(sin(latBounds[i+1]) - sin(latBounds[i]))\n", + "\n", + " The longitude weights are defined as:\n", + "\n", + " lonWeights[i] = abs(lonBounds[i+1] - lonBounds [i])/360.0\n", + "\n", + " For a global grid, the weight arrays are normalized such that the sum of the weights is 1.0\n", + "\n", + " Example:\n", + "\n", + " Generate the 2-D weights array, such that weights[i.j] is the fractional area of grid zone [i,j].\n", + " from cdms import MV\n", + " latwts, lonwts = gri d.getWeights()\n", + " weights = MV.outerproduct(latwts, lonwts)\n", + " Also see the function area_weights in module pcmdi.weighting.\n", + "\n", + "None \tsetType(gridtype) \t\n", + "\n", + "Set the grid type.\n", + "\n", + " gridtype is one of ‘gaussian’, ‘uniform’, ‘equalarea’, or ‘generic’.\n", + "\n", + "RectGrid \tsubGrid((latStart,latStop),(lonStart,lonStop)) \t\n", + "\n", + "Create a new grid, with latitude index range `` [latStart : latStop] and longitude index range [lonStart : lonStop]. Either index range can also be specified as None, indicating that the entire range of the latitude or longitude is used.\n", + "\n", + " Example:\n", + "\n", + " This creates newgrid corresponding to all latitudes and index range [lonStart:lonStop] of oldgrid.\n", + " newgrid = oldgrid.subGrid(None, (lonStart, lon Stop))\n", + " If a mask is defined, the subgrid also has a mask corresponding to the index ranges.\n", + "\n", + " Note: The result grid is not associated with any file or dataset.\n", + "\n", + "RectGrid \ttranspose() \t\n", + "\n", + "Create a new grid, with axis order reversed. The grid mask is also transposed.\n", + " Note: The result grid is not associated with any file or dataset. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.11. Variable\n", + "\n", + "A Variable is a multidimensional data object, consisting of:\n", + "\n", + " a multidimensional data array, possibly masked,\n", + " a collection of attributes\n", + " a domain, an ordered tuple of CoordinateAxis objects.\n", + "\n", + "A Variable which is contained in a Dataset or CdmsFile is called a persistent variable. Setting a slice of a persistent Variable writes data to the Dataset or file, and referencing a Variable slice reads data from the Dataset. Variables may also be transient, not associated with a Dataset or CdmsFile.\n", + "\n", + "Variables support arithmetic operations, including the basic Python operators (+,,*,/,**, abs, and sqrt), as well as the operations defined in the MV module. The result of an arithmetic operation is a transient variable, that is, the axis information is transferred to the result.\n", + "\n", + "The methods subRegion and subSlice return transient variables. In addition, a transient variable may be created with the cdms.createVariable method. The vcs and regrid module methods take advantage of the attribute, domain, and mask information in a transient variable.\n", + "2.11.1. Table Variable Internal Attributes\n", + "Type \tName \tDefinition\n", + "Dictionary \tattributes \tExternal attribute dictionary.\n", + "String \tid \tVariable identifier.\n", + "String \tname_in_file \tThe name of the variable in the file or files which represent the dataset. If different from id, the variable is aliased.\n", + "Dataset or CdmsFile \tparent \tThe dataset or file which contains the variable.\n", + "Tuple \tshape \tThe length of each axis of the variable\n", + "2.11.2. Table Variable Constructors\n", + "Constructor \tDescription\n", + "Dataset.createVariable(String id, String datatype, List axes) \tCreate a Variable in a Dataset. This function is not yet implemented.\n", + "CdmsFile.createVariable(String id, String datatype, List axes or Grids) \t\n", + "\n", + "Create a Variable in a CdmsFile.\n", + "\n", + " id is the name of the variable.\n", + " datatype is the MV2 or Numpy | typecode, for example, MV2.Float.\n", + " axesOrGrids is a list of Axis and/or Grid objects, on which the variable is defined. Specifying a rectilinear grid is equivalent to listing the grid latitude and longitude axes, in the order defined for the grid.\n", + "\n", + " Note: this argument can either be a list or a tuple. If the tuple form is used, and there is only one element, it must have a following comma, e.g.: (axisobj,).\n", + "\n", + "cdms.createVariable(array, typecode=None, copy=0, savespace=0,mask=None, fill_value=None, grid=None, axes=None,attributes=None, id=None) \t\n", + "\n", + "Create a transient variable, not associated with a file or dataset.\n", + "\n", + " array is the data values: a Variable, masked array, or Numpy array.\n", + " typecode is the MV2 typecode of the array. Defaults to the typecode of array.\n", + " copy is an integer flag: if 1, the variable is created with a copy of the array, if 0 the variable data is shared with array.\n", + " savespace is an integer flag: if set to 1, internal Numpy operations will attempt to avoid silent upcasting.\n", + " mask is an array of integers with value 0 or 1, having the same shape as array. array elements with a corresponding mask value of 1 are considered invalid, and are not used for subsequent Numpy operations. The default mask is obtained from array if present, otherwise is None.\n", + " fill_value is the missing value flag. The default is obtained from array if possible, otherwise is set to 1.0e20 for floating point variables, 0 for integer-valued variables.\n", + " grid is a rectilinear grid object.\n", + " axes is a tuple of axis objects. By default the axes are obtained from array if present. Otherwise for a dimension of length n, the default axis has values [0., 1., …, double(n)].\n", + " attributes is a dictionary of attribute values. The dictionary keys must be strings. By default the dictionary is obtained from array if present, otherwise is empty.\n", + " id is the string identifier of the variable. By default the id is obtained from array if possible, otherwise is set to ‘variable_n’ for some integer.\n", + "\n", + "2.11.3. Table Variable Methods\n", + "Type \tMethod \tDefinition\n", + "Variable \ttvar = var[ i:j, m:n] \t\n", + "\n", + "Read a slice of data from the file or dataset, resulting in a transient variable.\n", + "\n", + " Singleton dimensions are ‘squeezed’ out.\n", + " Data is returned in the physical ordering defined in the dataset.\n", + " The forms of the slice operator are listed in Variable Slice Operators\n", + "\n", + "None \tvar[ i:j, m:n] = array \t\n", + "\n", + "Write a slice of data to the external dataset.\n", + "\n", + " The forms of the slice operator are listed in Result Entry Methods . (Variables in CdmsFiles only)\n", + "\n", + "Variable \ttvar = var(selector) \t\n", + "\n", + "Calling a variable as a function reads the region of data defined by the selector.\n", + "\n", + " The result is a transient variable, unless raw=1 keyword is specified.\n", + " See Selectors’ .\n", + "\n", + "None \tassignValue(Array ar) \tWrite the entire data array. Equivalent to var[:] = ar. (Variables in CdmsFiles only).\n", + "Variable \tastype(typecode) \t\n", + "\n", + "Cast the variable to a new datatype.\n", + "\n", + " Typecodes are as for MV, MV2, and Numpy modules.\n", + "\n", + "Variable \tclone(copyData=1) \t\n", + "\n", + "Return a copy of a transient variable.\n", + "\n", + " If copyData is 1 (the default) the variable data is copied as well.\n", + " If copyData is 0, the result transient variable shares the original transient variables data array.\n", + "\n", + "Transient Variable \tcrossSectionRegrid(newLevel, newLatitude, method='log', missing=None, order=None) \t\n", + "\n", + "Return a lat/level vertical cross-section regridded to a new set of latitudes newLatitude and levels newLevel.\n", + "\n", + " The variable should be a function of latitude, level, and (optionally) time.\n", + " newLevel is an axis of the result pressure levels.\n", + " newLatitude is an axis of the result latitudes.\n", + " method is optional, either ‘log’ to interpolate in the log of pressure (default), or ‘linear’ for linear interpolation.\n", + " missing is a missing data value. The default is var.getMissing()\n", + " order is an order string such as ‘tzy’ or ‘zy’. The default is var.getOrder().\n", + " See also: regrid, pressureRegrid.\n", + "\n", + "Axis \tgetAxis(n) \t\n", + "\n", + "Get the n-th axis.\n", + "\n", + " n is an integer.\n", + "\n", + "List \tgetAxisIds() \tGet a list of axis identifiers.\n", + "Integer \tgetAxisIndex(axis_spec) \t\n", + "\n", + "Return the index of the axis specificed by axis_spec. Return -1 if no match.\n", + "\n", + " axis_spec is a specification as defined for getAxisList\n", + "\n", + "List \tgetAxisList(axes=None, omit=None, order=None) \t\n", + "\n", + "Get an ordered list of axis objects in the domain of the variable.\n", + "\n", + " If axes is not None, include only certain axes. Otherwise axes is a list of specifications as described below. Axes are returned in the order specified unless the order keyword is given.\n", + " If omit is not None, omit those specified by an integer dimension number. Otherwise omit is a list of specifications as described below.\n", + " order is an optional string determining the output order.\n", + "\n", + " Specifications for the axes or omit keywords are a list, each element having one of the following forms:\n", + "\n", + " an integer dimension index, starting at 0.\n", + " a string representing an axis id or one of the strings ‘time’, ‘latitude’, ‘lat’, ‘longitude’, ‘lon’, ‘lev’ or ‘level’.\n", + " a function that takes an axis as an argument and returns a value. If the value returned is true, the axis matches.\n", + " an axis object; will match if it is the same object as axis.\n", + " order can be a string containing the characters t,x,y,z, or * .\n", + " If a dash (‘-‘) is given, any elements of the result not chosen otherwise are filled in from left to right with remaining candidates.\n", + "\n", + "List \tgetAxisListIndex(axes=None, omit=None, order=None) \tReturn a list of indices of axis objects. Arguments are as for getAxisList.\n", + "List \tgetDomain() \t\n", + "\n", + "Get the domain.\n", + "\n", + " Each element of the list is itself a tuple of the form (axis,start,length,tru e_length)\n", + "\n", + " where axis is an axis object,\n", + " start is the start index of the domain relative to the axis object,\n", + " length is the length of the axis, and true_length is the actual number of (defined) points in the domain.\n", + "\n", + " See also: getAxisList.\n", + "\n", + "Horizontal-Grid \tgetGrid() \tReturn the associated grid, or None if the variable is not gridded.\n", + "Axis \tgetLatitude() \tGet the latitude axis, or None if not found.\n", + "Axis \tgetLevel() \tGet the vertical level axis, or None if not found.\n", + "Axis \tgetLongitude() \tGet the longitude axis, or None if not found.\n", + "Various \tgetMissing() \t\n", + "\n", + "Get the missing data value, or None if not found.\n", + "\n", + " String getOrder() Get the order string of a spatio-temporal variable.\n", + "\n", + " The order string specifies the physical ordering of the data.\n", + " It is a string of characters with length equal to the rank of the variable, indicating the order of the variable’s time, level, latitude, and/or longitude axes.\n", + "\n", + " Each character is one of:\n", + "\n", + " ‘t’: time\n", + " ‘z’: vertical level\n", + " ‘y’: latitude\n", + " ‘x’: longitude\n", + " ‘-‘: the axis is not spatio-temporal.\n", + "\n", + " Example: * A variable with ordering ‘tzyx’ is 4-dimensional, where the ordering of axes is (time, level, latitude, longitude).\n", + "\n", + " Note: The order string is of the form required for the order argument of a regridder function.\n", + "\n", + " intervals is a list of scalars, 2-tuples representing [i,j), slices, and/or Ellipses.\n", + " If no argument(s) are present, all file paths associated with the variable are returned.\n", + " Returns a list of tuples of the form (path,slicetuple), where path is the path of a file, and slicetuple is itself a tuple of slices, of the same length as the rank of the variable, representing the portion of the variable in the file corresponding to intervals.\n", + "\n", + " Note: This function is not defined for transient variables.\n", + "\n", + "Axis \tgetTime() \tGet the time axis, or None if not found.\n", + "List \tgetPaths(*intervals) \tGet the file paths associated with the index region specified by intervals.\n", + "Integer \tlen(var) \t\n", + "\n", + "The length of the first dimension of the variable. If the variable is zero-dimensional (scalar), a length of 0 is returned.\n", + " Note: size() returns the total number of elements.\n", + "\n", + "Transient Variable \tpressureRegrid (newLevel, method='log', missin=None, order=None) \t\n", + "\n", + "Return the variable regridded to a new set of pressure levels newLevel.\n", + "\n", + " The variable must be a function of latitude, longitude, pressure level, and (optionally) time.\n", + "\n", + " newLevel is an axis of the result pressure levels.\n", + " method is optional, either ‘log’ to interpolate in the log of pressure (default), or ‘linear’ for linear interpolation.\n", + " missing is a missing data value. The default is var.getMissing()\n", + " order is an order string such as ‘tzyx’ or ‘zyx’. The default is var.getOrder()\n", + " See also: regrid, crossSectionRegrid.\n", + "\n", + "Integer \trank() \tThe number of dimensions of the variable.\n", + "Transient \tregrid (togrid, missing=None, order=None, Variable mask=None) \t\n", + "\n", + "Return the variable regridded to the horizontal grid togrid.\n", + "\n", + " missing is a Float specifying the missing data value. The default is 1.0e20.\n", + " order is a string indicating the order of dimensions of the array. It has the form returned from variable.getOrder().\n", + " For example, the string ‘tzyx’ indicates that the dimension order of array is (time, level, latitude, longitude).\n", + " If unspecified, the function assumes that the last two dimensions of array match the input grid.\n", + " mask is a Numpy array, of datatype Integer or Float, consisting of ones and zeros. A value of 0 or 0.0 indicates that the corresponding data value is to be ignored for purposes of regridding.\n", + " If mask is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid.\n", + " If the mask has more than two dimensions, it must have the same shape as array. In this case, the missing data value is also ignored.\n", + " Such an n-dimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time.\n", + "\n", + " Note: If neither missing or mask is set, the default mask is obtained from the mask of the array if any.\n", + "\n", + " See also: crossSectionRegrid, pressureRegrid.\n", + "\n", + "None \tsetAxis(n, axis) \tSet the n-th axis (0-origin index) of to a copy of axis.\n", + "None \tsetAxisList(axislist) \tSet all axes of the variable. axislist is a list of axis objects.\n", + "None \tsetMissing(value) \tSet the missing value. Integer size() Number of elements of the variable.\n", + "Variable \tsubRegion(* region, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0) \t\n", + "\n", + "Read a coordinate region of data, returning a transient variable.\n", + "\n", + " A region is a hyperrectangle in coordinate space.\n", + "\n", + " region is an argument list, each item of which specifies an interval of a coordinate axis. The intervals are listed in the order of the variable axes.\n", + " If trailing dimensions are omitted, all values of those dimensions are retrieved.\n", + " If an axis is circular (axis.isCircular() is true) or cycle is specified (see below), then data will be read with wraparound in that dimension.\n", + " Only one axis may be read with wraparound.\n", + " A coordinate interval has one of the forms listed in Index and Coordinate Intervals .\n", + " Also see axis.mapIntervalExt.\n", + " The optional keyword arguments time, level, latitude, and longitude may also be used to specify the dimension for which the interval applies. This is particularly useful if the order of dimensions is not known in advance.\n", + " An exception is raised if a keyword argument conflicts with a positional region argument.\n", + " The optional keyword argument squeeze determines whether or not the shape of the returned array contains dimensions whose length is 1; by default this argument is 0, and such dimensions are not ‘squeezed out’.\n", + " The optional keyword argument raw specifies whether the return object is a variable or a masked array.\n", + " By default, a transient variable is returned, having the axes and attributes corresponding to2,3 the region read. If raw=1, an MV2 masked array is returned, equivalent to the transient variable without the axis and attribute information.\n", + "\n", + "Variable \tsubSlice(* specs, time=None, level=None, latitude=None, longitude=None, squeeze=0, raw=0) \t\n", + "\n", + "Read a slice of data, returning a transient variable.\n", + "\n", + " This is a functional form of the slice operator [] with the squeeze option turned off.\n", + "\n", + " specs is an argument list, each element of which specifies a slice of the corresponding dimension.\n", + "\n", + " There can be zero or more positional arguments, each of the form:\n", + "\n", + " a single integer n, meaning slice(n, n+1)\n", + " an instance of the slice class\n", + " a tuple, which will be used as arguments to create a slice\n", + " ‘:’, which means a slice covering that entire dimension\n", + " Ellipsis (…), which means to fill the slice list with ‘:’ leaving only enough room at the end for the remaining positional arguments\n", + " a Python slice object, of the form slice(i,j,k)\n", + " If there are fewer slices than corresponding dimensions, all values of the trailing dimensions are read.\n", + " The keyword arguments are defined as in subRegion.\n", + " There must be no conflict between the positional arguments and the keywords.\n", + " In (a)-(c) and (f), negative numbers are treated as offsets from the end of that dimension, as in normal Python indexing.\n", + " String typecode() The Numpy datatype identifier.\n", + "\n", + "2.11.4. Example Get a Region of Data.\n", + "\n", + "Variable ta is a function of (time, latitude, longitude). Read data corresponding to all times, latitudes -45.0 up to but not including+45.0, longitudes 0.0 through and including longitude 180.0:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'ta' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubRegion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m':'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m45.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m45.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'co'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m180.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'ta' is not defined" + ] + } + ], + "source": [ + "data = ta.subRegion(':', (-45.0,45.0,'co'), (0.0, 180.0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or equivalently:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "unexpected EOF while parsing (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0,\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m unexpected EOF while parsing\n" + ] + } + ], + "source": [ + "data = ta.subRegion(latitude=(-45.0,45.0,'co'), longitude=(0.0,\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Read all data for March, 1980:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'ta' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubRegion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1980-3'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1980-4'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'co'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'ta' is not defined" + ] + } + ], + "source": [ + "data = ta.subRegion(time=('1980-3','1980-4','co'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.11.6. Table Index and Coordinate Intervals\n", + "Interval Definition \tExample Interval Definition \tExample\n", + "x \tsingle point, such that axis[i]==x In general x is a scalar. If the axis is a time axis, x may also be a cdtime relative time type, component time type, or string of the form ‘yyyy-mm-dd hh:mi:ss’ (where trailing fields of the string may be omitted. \t\n", + "\n", + "180.0\n", + " cdtime.reltime(48,'hour s since 1980-1') '1980-1-3'\n", + "\n", + "(x,y) \tindices i such that x ≤ axis[i] ≤ y \t(-180,180)\n", + "(x,y,'co') \tx ≤ axis[i] < y. The third item is defined as in mapInterval. \t(-90,90,'cc')\n", + "(x,y,'co',cycle) \tx ≤ axis[i]< y, with wraparound \t\n", + "\n", + "( 180, 180, 'co', 360.0)\n", + " Note: It is not necesary to specify the cycle of a circular longitude axis, that is, for which axis.isCircular() is true.\n", + "\n", + "slice(i,j,k) \t\n", + "\n", + " slice object, equivalent to i:j:k in a slice operator. Refers to the indices i, i+k, i+2k, … up to but not including index j. If i is not specified or is None it defaults to 0. If j is not specified or is None it defaults to the length of the axis. The stride k defaults to 1. k may be negative.\n", + "\n", + "\t\n", + "\n", + "slice(1,10)\n", + " slice(,,-1) reverses the direction of the axis.\n", + "\n", + "':' \tall axis values of one dimension \t \n", + "Ellipsis \tall values of all intermediate axes \t " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.12. Selectors\n", + "\n", + "A selector is a specification of a region of data to be selected from a variable. For example, the statement:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'v' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'1979-1-1'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1000.0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m100.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'v' is not defined" + ] + } + ], + "source": [ + "x = v(time='1979-1-1', level=(1000.0,100.0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "means ‘select the values of variable v for time ‘1979-1-1’ and levels 1000.0 to 100.0 inclusive, setting x to the result.’ Selectors are generally used to represent regions of space and time.\n", + "\n", + "The form for using a selector is:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'v' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'v' is not defined" + ] + } + ], + "source": [ + "result = v(s)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "where v is a variable and s is the selector. An equivalent form is:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'f' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'varid'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'f' is not defined" + ] + } + ], + "source": [ + "result = f('varid', s)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "where f is a file or dataset, and ‘varid’ is the string ID of a variable.\n", + "\n", + "A selector consists of a list of selector components. For example, the selector:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "can't assign to literal (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m time='1979-1-1', level=(1000.0,100.0)\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to literal\n" + ] + } + ], + "source": [ + "time='1979-1-1', level=(1000.0,100.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "has two components: time=’1979-1-1’, and level=(1000.0,100.0). This illustrates that selector components can be defined with keywords, using the form:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'value' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mkeyword\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'value' is not defined" + ] + } + ], + "source": [ + "keyword=value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that for the keywords time, level, latitude, and longitude, the selector can be used with any variable. If the corresponding axis is not found, the selector component is ignored. This is very useful for writing general purpose scripts. The required keyword overrides this behavior. These keywords take values that are coordinate ranges or index ranges as defined in See Index and Coordinate Intervals.\n", + "\n", + "The following keywords are available: Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.12.1. Table Selector Keywords\n", + "Keyword \tDescription \tValue\n", + "axisid \tRestrict the axis with ID axisid to a value or range of values. \tSee Index and Coordinate Intervals\n", + "grid \tRegrid the result to the grid. \tGrid object\n", + "latitude \tRestrict latitude values to a value or range. Short form: lat \tSee Index and Coordinate Intervals\n", + "level \tRestrict vertical levels to a value or range. Short form: lev \tSee Index and Coordinate Intervals\n", + "longitude \tRestrict longitude values to a value or range. Short form: lon \tSee Index and Coordinate Intervals\n", + "order \tReorder the result. \tOrder string, e.g., ‘tzyx’\n", + "raw \tReturn a masked array (MV2.array) rather than a transient variable. \t0: return a transient variable (default); =1: return a masked array.\n", + "required \tRequire that the axis IDs be present. \tList of axis identifiers.\n", + "squeeze \tRemove singleton dimensions from the result. \t0: leave singleton dimensions (default); 1: remove singleton dimensions.\n", + "time \tRestrict time values to a value or range. \tSee Index and Coordinate Intervals\n", + "\n", + "Another form of selector components is the positional form, where the component order corresponds to the axis order of a variable. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'hus' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx9\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhus\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1979-1-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1979-2-1'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1000.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'hus' is not defined" + ] + } + ], + "source": [ + "x9 = hus(('1979-1-1','1979-2-1'),1000.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "reads data for the range (‘1979-1-1’,’1979-2-1’) of the first axis, and coordinate value 1000.0 of the second axis. Non-keyword arguments of the form(s) listed in Index and Coordinate Intervals are treated as positional. Such selectors are more concise, but not as general or flexible as the other types described in this section.\n", + "\n", + "Selectors are objects in their own right. This means that a selector can be defined and reused, independent of a particular variable. Selectors are constructed using the cdms.selectors.Selector class. The constructor takes an argument list of selector components. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named cdms.selectors", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselectors\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSelector\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0msel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mSelector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1979-1-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1979-2-1'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1000.\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mx1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mx2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named cdms.selectors" + ] + } + ], + "source": [ + "from cdms.selectors import Selector\n", + "sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.)\n", + "x1 = v1(sel)\n", + "x2 = v2(sel)\n", + "\n", + "from cdms.selectors import Selector\n", + "sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.)\n", + "x1 = v1(sel)\n", + "x2 = v2(sel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For convenience CDMS provides several predefined selectors, which can be used directly or can be combined into more complex selectors. The selectors time, level, latitude, longitude, and required are equivalent to their keyword counterparts. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named cdms", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhus\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1979-1-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1979-2-1'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1000.\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named cdms" + ] + } + ], + "source": [ + "from cdms import time, level\n", + "x = hus(time('1979-1-1','1979-2-1'), level(1000.))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and\n", + "\n", + "are equivalent. Additionally, the predefined selectors latitudeslice, longitudeslice, levelslice, and timeslice take arguments (startindex, stopindex[, stride]):" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named cdms", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtimeslice\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevelslice\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevelslice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m16\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m17\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named cdms" + ] + } + ], + "source": [ + "from cdms import timeslice, levelslice\n", + "x = v(timeslice(0,2), levelslice(16,17))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, a collection of selectors is defined in module cdutil.region:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m SH=SouthernHemisphere=domain(latitude=(-90.,0.))\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "from cdutil.region import *\n", + "NH=NorthernHemisphere=domain(latitude=(0.,90.)\n", + "SH=SouthernHemisphere=domain(latitude=(-90.,0.))\n", + "Tropics=domain(latitude=(-23.4,23.4))\n", + "NPZ=AZ=ArcticZone=domain(latitude=(66.6,90.))\n", + "SPZ=AAZ=AntarcticZone=domain(latitude=(-90.,-66.6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Selectors can be combined using the & operator, or by refining them in the call:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named cdms.selectors", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselectors\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSelector\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msel2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mSelector\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1979-1-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1979-2-1'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0msel3\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msel2\u001b[0m \u001b[0;34m&\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1000.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mx1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mhus\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msel3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named cdms.selectors" + ] + } + ], + "source": [ + "from cdms.selectors import Selector\n", + "from cdms import level\n", + "sel2 = Selector(time=('1979-1-1','1979-2-1'))\n", + "sel3 = sel2 & level(1000.0)\n", + "x1 = hus(sel3)\n", + "x2 = hus(sel2, level=1000.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.12.2. Selector Examples\n", + "\n", + "CDMS provides a variety of ways to select or slice data. In the following examples, variable hus is contained in file sample.nc, and is a function of (time, level, latitude, longitude). Time values are monthly starting at 1979-1-1. There are 17 levels, the last level being 1000.0. The name of the vertical level axis is ‘plev’. All the examples select the first two times and the last level. The last two examples remove the singleton level dimension from the result array." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named cdms", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sample.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mhus\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'hus'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# Keyword selection\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named cdms" + ] + } + ], + "source": [ + "import cdms\n", + "f = cdms.open('sample.nc')\n", + "hus = f.variables['hus']\n", + "\n", + "# Keyword selection\n", + "x = hus(time=('1979-1-1','1979-2-1'), level=1000.)\n", + "\n", + "# Interval indicator (see mapIntervalExt)\n", + "x = hus(time=('1979-1-1','1979-3-1','co'), level=1000.)\n", + "\n", + "# Axis ID (plev) as a keyword\n", + "x = hus(time=('1979-1-1','1979-2-1'), plev=1000.)\n", + "\n", + "# Positional\n", + "x9 = hus(('1979-1-1','1979-2-1'),1000.0)\n", + "\n", + "# Predefined selectors\n", + "from cdms import time, level\n", + "x = hus(time('1979-1-1','1979-2-1'), level(1000.))\n", + "\n", + "from cdms import timeslice, levelslice\n", + "x = hus(timeslice(0,2), levelslice(16,17))\n", + "\n", + "# Call file as a function\n", + "x = f('hus', time=('1979-1-1','1979-2-1'), level=1000.)\n", + "\n", + "# Python slices\n", + "x = hus(time=slice(0,2), level=slice(16,17))\n", + "\n", + "# Selector objects\n", + "from cdms.selectors import Selector\n", + "sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.)\n", + "x = hus(sel)\n", + "\n", + "sel2 = Selector(time=('1979-1-1','1979-2-1'))\n", + "sel3 = sel2 & level(1000.0)\n", + "x = hus(sel3)\n", + "x = hus(sel2, level=1000.0)\n", + "\n", + "# Squeeze singleton dimension (level)\n", + "x = hus[0:2,16]\n", + "x = hus(time=('1979-1-1','1979-2-1'), level=1000., squeeze=1)\n", + "\n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.13. Examples\n", + "2.13.1. Example 1\n", + "\n", + "In this example, two datasets are opened, containing surface air temperature (‘tas’) and upper-air temperature (‘ta’) respectively. Surface air temperature is a function of (time, latitude, longitude). Upper-air temperature is a function of (time, level, latitude, longitude). Time is assumed to have a relative representation in the datasets (e.g., with units ‘months since basetime’).\n", + "\n", + "Data is extracted from both datasets for January of the first input year through December of the second input year. For each time and level, three quantities are calculated: slope, variance, and correlation. The results are written to a netCDF file. For brevity, the functions corrCoefSlope and removeSeasonalCycle are omitted." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1. import cdms\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "1. import cdms\n", + " import MV\n", + "\n", + " # Calculate variance, slope, and correlation of\n", + " # surface air temperature with upper air temperature\n", + " # by level, and save to a netCDF file. 'pathTa' is the location of\n", + " # the file containing 'ta', 'pathTas' is the file with contains 'tas'.\n", + " # Data is extracted from January of year1 through December of year2.\n", + " def ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,month1,month2):\n", + "\n", + " # Open the files for ta and tas\n", + " fta = cdms.open(pathTa)\n", + " ftas = cdms.open(pathTas)\n", + "\n", + "2. #Get upper air temperature\n", + " taObj = fta['ta']\n", + " levs = taObj.getLevel()\n", + "\n", + " #Get the surface temperature for the closed interval [time1,time2]\n", + " tas = ftas('tas', time=(month1,month2,'cc'))\n", + "\n", + " # Allocate result arrays\n", + " newaxes = taObj.getAxisList(omit='time')\n", + " newshape = tuple([len(a) for a in newaxes])\n", + " cc = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='correlation')\n", + " b = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='slope')\n", + " v = MV.zeros(newshape, typecode=MV.Float, axes=newaxes, id='variance')\n", + "\n", + " # Remove seasonal cycle from surface air temperature\n", + " tas = removeSeasonalCycle(tas)\n", + "\n", + " # For each level of air temperature, remove seasonal cycle\n", + " # from upper air temperature, and calculate statistics\n", + "5. for ilev in range(len(levs)):\n", + "\n", + " ta = taObj(time=(month1,month2,'cc'), \\\n", + " level=slice(ilev, ilev+1), squeeze=1)\n", + " ta = removeSeasonalCycle(ta)\n", + " cc[ilev], b[ilev] = corrCoefSlope(tas ,ta)\n", + " v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0])\n", + "\n", + " # Write slope, correlation, and variance variables\n", + "6. f = cdms.open('CC_B_V_ALL.nc','w')\n", + " f.title = filtered\n", + " f.write(b)\n", + " f.write(cc)\n", + " f.write(v)\n", + " f.close()\n", + "\n", + "7. if __name__=='__main__':\n", + " pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml'\n", + " pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml'\n", + " # Process Jan80 through Dec81\n", + " ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Two modules are imported, \"cdms\", and \"MV\". \"MV\" implements\n", + " arithmetic functions.\n", + "15. \"taObj\" is a file (persistent) variable. At this point, no data has\n", + " actually been read. This happens when the file variable is sliced, or\n", + " when the subRegion function is called. levs is an axis.\n", + "20. Calling the file like a function reads data for the given variable\n", + " and time range. Note that month1 and month2 are time strings.\n", + "25. In contrast to \"taObj\", the variables \"cc:\" b\" and \"v\" are\n", + " transient variables, not associated with a file. The assigned names\n", + " are used when the variables are written.\n", + "34. Another way to read data is to call the variable as a function. The\n", + " squeeze option removes singleton axes, in this case the level axis.\n", + "43. Write the data. Axis information is written automatically.\n", + "50. This is the main routine of the script. \"pathTa\" and \"pathTas\"\n", + " pathnames. Data is processed from January 1980 through December 1981.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2.13.2. Example 2\n", + "\n", + "In the next example, the pointwise variance of a variable over time is calculated, for all times in a dataset. The name of the dataset and variable are entered, then the variance is calculated and plotted via the vcs module." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 13)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m13\u001b[0m\n\u001b[0;31m print Hit return to continue: ,\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "#!/usr/bin/env python\n", + "#\n", + "# Calculates gridpoint total variance\n", + "# from an array of interest\n", + "#\n", + "\n", + "import cdms\n", + "from MV import *\n", + "\n", + "# Wait for return in an interactive window\n", + "\n", + "def pause():\n", + " print Hit return to continue: ,\n", + " line = sys.stdin.readline()\n", + "\n", + "1. # Calculate pointwise variance of variable over time\n", + "# Returns the variance and the number of points\n", + "# for which the data is defined, for each grid point\n", + "def calcVar(x):\n", + " # Check that the first axis is a time axis\n", + " firstaxis = x.getAxis(0)\n", + " if not firstaxis.isTime():\n", + " raise 'First axis is not time, variable:', x.id\n", + "\n", + " n = count(x,0)\n", + " sumxx = sum(x*x)\n", + " sumx = sum(x)\n", + " variance = (n*sumxx -(sumx * sumx))/(n * (n-1.))\n", + "\n", + " return variance, n\n", + "\n", + " if __name__=='__main__':\n", + " import vcs, sys\n", + "\n", + " print 'Enter dataset path [/pcmdi/cdms/obs/erbs_mo.xml]: ',\n", + " path = string.strip(sys.stdin.readline())\n", + " if path=='': path='/pcmdi/cdms/obs/erbs_mo.xml'\n", + "\n", + "2. # Open the dataset\n", + " dataset = cdms.open(path)\n", + "\n", + " # Select a variable from the dataset\n", + " print 'Variables in file:',path\n", + " varnames = dataset.variables.keys()\n", + " varnames.sort()\n", + " for varname in varnames:\n", + "\n", + " var = dataset.variables[varname]\n", + " if hasattr(var,'long_name'):\n", + " long_name = var.long_name\n", + " elif hasattr(var,'title'):\n", + " long_name = var.title\n", + " else:\n", + " long_name = '?'\n", + "\n", + " print '%-10s: %s'%(varname,long_name)\n", + " print 'Select a variable: ',\n", + "3. varname = string.strip(sys.stdin.readline())\n", + " var = dataset(varname)\n", + " dataset.close()\n", + "\n", + " # Calculate variance, count, and set attributes\n", + " variance,n = calcVar(var)\n", + " variance.id = 'variance_%s'%var.id\n", + " n.id = 'count_%s'%var.id\n", + " if hasattr(var,'units'):\n", + " variance.units = '(%s)^2'%var.units\n", + "\n", + " # Plot variance\n", + " w=vcs.init()\n", + "4. w.plot(variance)\n", + " pause()\n", + " w.clear()\n", + " w.plot(n)\n", + " pause()\n", + " w.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The result of running this script is as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 2)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]:\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "% calcVar.py\n", + "Enter dataset path [/pcmdi/cdms/sample/obs/erbs_mo.xml]:\n", + "\n", + "Variables in file: /pcmdi/cdms/sample/obs/erbs_mo.xml\n", + "albt : Albedo TOA [%]\n", + "albtcs : Albedo TOA clear sky [%]\n", + "rlcrft : LW Cloud Radiation Forcing TOA [W/m^2]\n", + "rlut : LW radiation TOA (OLR) [W/m^2]\n", + "rlutcs : LW radiation upward TOA clear sky [W/m^2]\n", + "rscrft : SW Cloud Radiation Forcing TOA [W/m^2]\n", + "rsdt : SW radiation downward TOA [W/m^2]\n", + "rsut : SW radiation upward TOA [W/m^2]\n", + "rsutcs : SW radiation upward TOA clear sky [W/m^2]\n", + "Select a variable: albt\n", + "\n", + "\n", + "\n", + "Hit return to continue:\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notes:\n", + "\n", + " n = count(x, 0) returns the pointwise number of valid values, summing across axis 0, the first axis. count is an MV function.\n", + " dataset is a Dataset or CdmsFile object, depending on whether a .xml or .nc pathname is entered. dataset.variables is a dictionary mapping variable name to file variable.\n", + " var is a transient variable.\n", + " Plot the variance and count variables. Spatial longitude and latitude information are carried with the computations, so the continents are plotted correctly.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/chapter3.ipynb b/chapter3.ipynb new file mode 100644 index 00000000..f0cf33ac --- /dev/null +++ b/chapter3.ipynb @@ -0,0 +1,392 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Module: CdTime" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time Types\n", + "\n", + "The ``cdtime`` module implements the CDMS time types, methods, and\n", + "calendars. These are made available with the command:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import cdtime" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Two time types are available: relative time and component time. Relative\n", + "time is time relative to a fixed base time. It consists of:\n", + "\n", + "- a units string, of the form ‘units since basetime’, and\n", + "- a floating-point value\n", + "\n", + "For example, the time “28.0 days since 1996-1-1” has value=28.0, and\n", + "units=’days since 1996-1-1’\n", + "\n", + "Component time consists of the integer fields year, month, day, hour,\n", + "minute, and the floating-point field second. A sample component time is\n", + "``1996-2-28 12:10:30.0``\n", + "\n", + "The ``cdtime`` module contains functions for converting between these\n", + "forms, based on the common calendars used in climate simulation. Basic\n", + "arithmetic and comparison operators are also available.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calendars\n", + "\n", + "A calendar specifies the number of days in each month, for a given year.\n", + "cdtime supports these calendars:\n", + "\n", + "- ``cdtime.GregorianCalendar``: years evenly divisible by four are leap\n", + " years, except century years not evenly divisible by 400. This is\n", + " sometimes called the proleptic Gregorian calendar, meaning that the\n", + " algorithm for leap years applies for all years.\n", + "- ``cdtime.MixedCalendar``: mixed Julian/Gregorian calendar. Dates\n", + " before 158210-15 are encoded with the Julian calendar, otherwise are\n", + " encoded with the Gregorian calendar. The day immediately following\n", + " 1582-10-4 is 1582-10-15. This is the default calendar.\n", + "- ``cdtime.JulianCalendar``: years evenly divisible by four are leap\n", + " years,\n", + "- ``cdtime.NoLeapCalendar``: all years have 365 days,\n", + "- ``cdtime.Calendar360``: all months have 30 days.\n", + "\n", + "Several ``cdtime`` functions have an optional calendar argument. The\n", + "default calendar is the ``MixedCalendar``. The default calendar may be\n", + "changed with the command:\n", + "\n", + "\n", + "``cdtime.DefaultCalendar = newCalendar``\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time Constructors\n", + "\n", + "The following table describes the methods for creating time types." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time Constructors Types\n", + "\n", + " \"Reltime\", \"``cdtime.reltime(value, relunits)``\", \"Create a relative time type.\n", + " * ``value`` is an integer or floating point value.\n", + " * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``\n", + " * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. \n", + " * The default basetime is 1979-1-1, if no ``since`` clause is specified. \n", + " **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``\"\n", + " \"Comptime\", \"``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``\", \"Create a component time type.\n", + " * ``year`` is an integer.\n", + " * ``month`` is an integer in the range 1 .. 12\n", + " * ``day`` is an integer in the range 1 .. 31\n", + " * ``hour`` is an integer in the range 0 .. 23\n", + " * ``minute`` is an integer in the range 0 .. 59\n", + " * ``second`` is a floating point number in the range 0.0 ,, 60.0.\n", + "\n", + " **Example:** ``c = cdtime.comptime(1996, 2, 28)``\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Relative Time Member Types\n", + "\n", + "\"Float\", \"value\", \"Number of units\" \n", + "\"String\", \"units\", \"Relative units, of the form “unit(s) since basetime\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Component Time\n", + "\n", + "A component time type has six members, all of which are settable." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Component Time Types\n", + " \n", + " * \"Integer\", \"year\", \"Year value\"\n", + " * \"Integer\", \"month\", \"Month, in the range 1..12\"\n", + " * \"Integer\", \"day\", \"Day of month, in the range 1 .. 31\"\n", + " * \"Integer\", \"hour\", \"Hour, in the range 0 .. 23\"\n", + " * \"Integer\", \"minute\", \"Minute, in the range 0 .. 59\"\n", + " * \"Float\", \"second\", \"Seconds, in the range 0.0 .. 60.0\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time Methods\n", + "\n", + "The following methods apply both to relative and component times." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time Methods Types\n", + "\n", + " \"Comptime or Reltime\", \"``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``\", \"Add an interval of time to a time type t. Returns the same type of time.\n", + " * ``value`` is the Float number of interval units.\n", + " * ``intervalUnits`` is ``cdtime.[Second (s) | Minute(s) Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s) ]``\n", + " * ``calendar`` is the calendar type.\"\n", + " \"Integer\", \"``t.cmp(t2, calendar=cdtime.DefaultCalendar)``\", \"Compare time values t and t2. Returns -1, 0, 1 as t is less than, equal to, or greater than t2 respectively.\n", + " * ``t2`` is the time to compare.\n", + " * ``calendar`` is the calendar type.\"\n", + " \"Comptime or Reltime\", \"``t.sub(value,intervalUnits, calendar=cdtime.DefaultCalendar)``\", \"Subtract an interval of time from a time type t. Returns the same type of time.\n", + " * ``value`` is the Float number of interval units.\n", + " * ``intervalUnits`` is cdtime.[Second (s) | Minute(s) | Hour(s) | Day(s) | Week(s) | Month(s) | Season(s) | Year(s)]\n", + " * ``calendar`` is the calendar type. \"\n", + " \"Comptime\", \"``t.tocomp(calendar = cdtime.DefaultCalendar)``\", \"Convert to component time. Returns the equivalent component time.\n", + " * ``calendar`` is the calendar type.\"\n", + " \"Reltime\", \"``t.torel(units, calendar=cdtime.DefaultCalendar)``\", \"Convert to relative time. Returns the equivalent relative time.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Examples" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 5)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m 29.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "from cdtime import *\n", + "c = comptime(1996,2,28)\n", + "r = reltime(28,\"days since 1996-1-1\") \n", + "print r.add(1,Day)\n", + "29.000000 days since 1996-1-1\n", + "print c.add(36,Hours)\n", + "1996-2-29 12:0:0.0 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m 1979-9-1 0:0:0.0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "c = comptime(1979,8,31) \n", + "c.add(1,Month) \n", + "1979-9-1 0:0:0.0 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compare time values." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 7)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m7\u001b[0m\n\u001b[0;31m .. >>> print r.cmp(c)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "from cdtime import * \n", + "r = cdtime.reltime(28,\"days since 1996-1-1\") \n", + "c = comptime(1996,2,28) \n", + "print c.cmp(r) \n", + "1\n", + "\n", + ".. >>> print r.cmp(c) \n", + ".. -1\n", + ".. >>> print r.cmp(r) \n", + ".. 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Subtract an interval of time." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 5)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m 18.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "from cdtime import * \n", + "r = cdtime.reltime(28,\"days since 1996-1-1\") \n", + "c = comptime(1996,2,28) \n", + "print r.sub(10,Days) \n", + "18.000000 days since 1996-1-1 \n", + "print c.sub(30,Days) \n", + "1996-1-29 0:0:0.0 " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For intervals of years or months, see the **note** under add() in the example above.\n", + "\n", + "Convert to component time." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m 1996-1-29 0:0:0.0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "r = cdtime.reltime(28,\"days since 1996-1-1\") \n", + "r.tocomp()\n", + "1996-1-29 0:0:0.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Convert to relative time." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 3)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m 58.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "c = comptime(1996,2,28) \n", + "print c.torel(\"days since 1996-1-1\") \n", + "58.000000 days since 1996-1-1 \n", + "r = reltime(28,\"days since 1996-1-1\") \n", + "print r.torel(\"days since 1995\") \n", + "393.000000 days since 1995 \n", + "print r.torel(\"days since 1995\").value \n", + "393.0 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/chapter4.ipynb b/chapter4.ipynb new file mode 100644 index 00000000..cc09a03d --- /dev/null +++ b/chapter4.ipynb @@ -0,0 +1,1029 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Regridding Data\n", + "\n" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "Overview\n", + "\n", + "CDMS provides several methods for interpolating gridded data:\n", + "\n", + "- from one rectangular, lat-lon grid to another (CDMS regridder)\n", + "- between any two lat-lon grids (SCRIP regridder)\n", + "- from one set of pressure levels to another\n", + "- from one vertical (lat/level) cross-section to another vertical\n", + " cross-section.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CDMS Horizontal Regridder\n", + "\n", + "The simplest method to regrid a variable from one rectangular, lat/lon\n", + "grid to another is to use the regrid function defined for variables.\n", + "This function takes the target grid as an argument, and returns the\n", + "variable regridded to the target grid:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/bin/sh: wgethttps://cdat.llnl.gov/cdat/sample_data/clt.nc: No such file or directory\r\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1370: Warning: \n", + "avariable.regrid: We chose regridTool = esmf for you among the following choices:\n", + " Tools -> 'regrid2' (old behavior)\n", + " 'esmf' (conserve, patch, linear) or\n", + " 'libcf' (linear)\n", + " warnings.warn(message, Warning)\n", + "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1377: Warning: \n", + "avariable.regrid: We chose regridMethod = linear for you among the following choices:\n", + " 'conserve' or 'linear' or 'patch'\n", + " warnings.warn(message, Warning)\n" + ] + }, + { + "data": { + "text/plain": [ + "(181, 360)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "!wget\"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "# wget \"https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", + "import cdms2\n", + "import cdat_info\n", + "f1=cdms2.open(\"clt.nc\")\n", + "f2=cdms2.open(\"geos5-sample.nc\")\n", + "clt=f1('clt') # Read the data\n", + "clt.shape\n", + "(120, 46, 72)\n", + "ozone=f2['ozone'] # Get the file variable (no data read)\n", + "outgrid = ozone.getGrid() # Get the target grid\n", + "cltnew = clt.regrid(outgrid)\n", + "cltnew.shape\n", + "(120, 181, 360)\n", + "outgrid.shape\n", + "(181, 360)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A somewhat more efficient method is to create a regridder function. This\n", + "has the advantage that the mapping is created only once and can be used\n", + "for multiple arrays. Also, this method can be used with data in the form\n", + "of an MV2.MaskedArray. The steps in this process are:\n", + "\n", + "#. Given an input grid and output grid, generate a regridder function.\n", + "#. Call the regridder function on a Numpy array, resulting in an array\n", + " defined on the output grid. The regridder function can be called with\n", + " any array or variable defined on the input grid.\n", + "\n", + "The following example illustrates this process. The regridder function\n", + "is generated at line 9, and the regridding is performed at line 10:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/regrid2/horizontal.py:374: Warning: While this will work for now, please note that the Regridder class has been renamed Horizontal, the name 'Regridder' will be deprecated in future version. Please edit your code accordingly\n", + " Warning)\n" + ] + } + ], + "source": [ + "!#wget\"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "!#wget\"https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", + "import cdms2\n", + "from regrid2 import Regridder\n", + "f = cdms2.open(\"clt.nc\")\n", + "cltf = f['clt']\n", + "ingrid = cltf.getGrid()\n", + "g = cdms2.open('geos5-sample.nc')\n", + "outgrid = g['ozone'].getGrid()\n", + "regridfunc = Regridder(ingrid, outgrid)\n", + "cltnew = regridfunc(cltf)\n", + "f.close()\n", + "g.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notes\n", + "\n", + "**Line #3** Makes the CDMS module available.\n", + "\n", + "**Line #4** Makes the Regridder class available from the regrid module.\n", + "\n", + "**Line #5** Opens the input dataset.\n", + "\n", + "**Line #6** Gets the variable object named ‘clt’. No data is read.\n", + "\n", + "**Line #7** Gets the input grid.\n", + "\n", + "**Line #8** Opens a dataset to retrieve the output grid.\n", + "\n", + "**Line #9** The output grid is the grid associated with the variable named ‘ozone’ in dataset g. Just the grid is retrieved, not the data.\n", + "\n", + "**Line #10** Generates a regridder function regridfunc.\n", + "\n", + "**Line #11** Reads all data for variable cltf, and calls the regridder\n", + "function on that data, resulting in a transient variable cltnew.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Horizontal Regridder\n", + "\n", + "To interpolate between grids where one or both grids is non-rectangular,\n", + "CDMS provides an interface to the SCRIP regridder package developed at\n", + "Los Alamos National Laboratory (https://oceans11.lanl.gov/trac/SCRIP). \n", + "\n", + "Figure 3 illustrates the process:\n", + "\n", + "#. Obtain or generate the source and target grids in SCRIP netCDF\n", + " format. A CDMS grid can be written to a netCDF file, in SCRIP format,\n", + " using the write-ScripGrid method.\n", + "#. Edit the input namelist file scrip\\_in to reference the grids and\n", + " select the method of interpolation, either conservative, bilinear,\n", + " bicubic, or distance-weighted. See the SCRIP documentation for\n", + " detailed instructions.\n", + "#. Run the scrip executable to generate a remapping file containing the\n", + " transformation coefficients.\n", + "#. CDMS, open the remapping file and create a regridder function with\n", + " the readRegridder method.\n", + "#. Call the regridder function on the input variable, defined on the\n", + " source grid. The return value is the variable interpolated to the new\n", + " grid. Note that the variable may have more than two dimensions. Also\n", + " note that the input arguments to the regridder function depend on the\n", + " type of regridder. For example, the bicubic interpolation has\n", + " additional arguments for the gradients of the variable." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regridding Data with SCRIP\n", + "\n", + "**Example:**\n", + "\n", + "Regrid data from a T42 to POP4/3 grid, using the first-order,\n", + "conservative interpolator.\n", + "\n", + "In this example:\n", + "\n", + "- The input grid is defined in remap_grid_T42.nc.\n", + "- The output grid is defined in remap_grid_POP43.nc.\n", + "- The input data is variable src_array in file sampleT42Grid.nc.\n", + "- The file scrip_in has contents:\n", + "\n", + " &remap_inputs\n", + " num_maps = 1\n", + "\n", + " grid1_file = 'remap_grid_T42.nc'\n", + " grid2_file = 'remap_grid_POP43.nc'\n", + " interp_file1 = 'rmp_T42_to_POP43_conserv.nc'\n", + " interp_file2 = 'rmp_POP43_to_T42_conserv.nc'\n", + " map1_name = 'T42 to POP43 Conservative Mapping' \n", + " map2_name = 'POP43 to T42 Conservative Mapping'\n", + " map_method = 'conservative'\n", + " normalize_opt = 'frac'\n", + " output_opt = 'scrip'\n", + " restrict_type = 'latitude'\n", + " num_srch_bins = 90\n", + " luse_grid1_area = .false.\n", + " luse_grid2_area = .false.\n", + "\n", + "\n", + "``num_maps`` specifies the number of mappings generated, either 1 or 2.\n", + "For a single mapping, ``grid1_file`` and ``grid2_file`` are the source\n", + "and target grid definitions, respectively. The ``map_method`` specifies\n", + "the type of interpolation, either ‘conservative’, ‘bilinear’, ‘bicubic’,\n", + "or ‘distwgt’ (distanceweighted). The remaining parameters are described\n", + "in the SCRIP documentation.\n", + "\n", + "Once the grids and input file are defined, run the scrip executable to\n", + "generate the remapping file ‘rmp\\_T42\\_to\\_POP43\\_conserv.nc’\n", + "\n", + "\n", + "::\n", + "\n", + " % scrip\n", + " Using latitude bins to restrict search.\n", + " Computing remappings between:\n", + " T42 Gaussian Grid\n", + " and\n", + " POP 4/3 Displaced-Pole T grid\n", + " grid1 sweep\n", + " grid2 sweep\n", + " Total number of links = 63112\n", + "\n", + "\n", + "Next, run CDAT and create the regridder:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 2064964 (2.0M) [application/x-netcdf]\n", + "Saving to: “remap_grid_POP43.nc”\n", + "\n", + "100%[======================================>] 2,064,964 --.-K/s in 0.02s \n", + "\n", + "2018-08-15 09:10:03 (85.3 MB/s) - “remap_grid_POP43.nc” saved [2064964/2064964]\n", + "\n", + "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 688696 (673K) [application/x-netcdf]\n", + "Saving to: “remap_grid_T42.nc”\n", + "\n", + "100%[======================================>] 688,696 --.-K/s in 0.009s \n", + "\n", + "2018-08-15 09:10:03 (73.7 MB/s) - “remap_grid_T42.nc” saved [688696/688696]\n", + "\n", + "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 4637612 (4.4M) [application/x-netcdf]\n", + "Saving to: “rmp_POP43_to_T42_conserv.nc”\n", + "\n", + "100%[======================================>] 4,637,612 --.-K/s in 0.1s \n", + "\n", + "2018-08-15 09:10:04 (40.3 MB/s) - “rmp_POP43_to_T42_conserv.nc” saved [4637612/4637612]\n", + "\n", + "--2018-08-15 09:10:04-- https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 4637612 (4.4M) [application/x-netcdf]\n", + "Saving to: “rmp_T42_to_POP43_conserv.nc”\n", + "\n", + "100%[======================================>] 4,637,612 --.-K/s in 0.05s \n", + "\n", + "2018-08-15 09:10:04 (96.7 MB/s) - “rmp_T42_to_POP43_conserv.nc” saved [4637612/4637612]\n", + "\n", + "--2018-08-15 09:10:04-- https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 7081508 (6.8M) [application/x-netcdf]\n", + "Saving to: “xieArkin-T42.nc”\n", + "\n", + "100%[======================================>] 7,081,508 --.-K/s in 0.07s \n", + "\n", + "2018-08-15 09:10:04 (95.4 MB/s) - “xieArkin-T42.nc” saved [7081508/7081508]\n", + "\n" + ] + } + ], + "source": [ + "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc\"\n", + "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", + "!wget \"https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc\"\n", + "!wget \"https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc\"\n", + "!wget \"https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", + "# Import regrid package for regridder functions\n", + "import regrid2, cdms2\n", + "# Read the regridder from the remapper file\n", + "remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc')\n", + "regridf = regrid2.readRegridder(remapf)\n", + "\n", + "remapf.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then read the input data and regrid:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Get the source variable\n", + "f = cdms2.open('xieArkin-T42.nc')\n", + "t42prc = f('prc')\n", + "f.close()\n", + "# Regrid the source variable\n", + "popdat = regridf(t42prc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that ``t42dat`` can have rank greater than 2. The trailing\n", + "dimensions must match the input grid shape. For example, if ``t42dat``\n", + "has shape (12, 64, 128), then the input grid must have shape (64,128).\n", + "Similarly if the variable had a generic grid with shape (8092,), the\n", + "last dimension of the variable would have length 8092." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pressure-Level Regridder\n", + "\n", + "To regrid a variable which is a function of latitude, longitude,\n", + "pressure level, and (optionally) time to a new set of pressure levels,\n", + "use the ``pressureRegrid`` function defined for variables. This function\n", + "takes an axis representing the target set of pressure levels, and\n", + "returns a new variable ``d`` regridded to that dimension." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2018-08-15 09:11:24-- https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 7868676 (7.5M) [application/x-netcdf]\n", + "Saving to: “ta_ncep_87-6-88-4.nc”\n", + "\n", + "100%[======================================>] 7,868,676 --.-K/s in 0.07s \n", + "\n", + "2018-08-15 09:11:24 (106 MB/s) - “ta_ncep_87-6-88-4.nc” saved [7868676/7868676]\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "(11, 1, 73, 144)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "!wget \"https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\"\n", + "f=cdms2.open(\"ta_ncep_87-6-88-4.nc\")\n", + "ta=f('ta')\n", + "ta.shape\n", + "(11, 17, 73, 144)\n", + "ta.getAxisIds()\n", + "['time', 'level', 'latitude', 'longitude']\n", + "result = ta.pressureRegrid(cdms2.createAxis([1000.0]))\n", + "result.shape\n", + "(11, 1, 73, 144)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cross-Section Regridder\n", + "\n", + "To regrid a variable which is a function of latitude, height, and\n", + "(optionally) time to a new latitude/height cross-section, use the\n", + "``crossSectionRegridder`` defined for variables. This function takes as\n", + "arguments the new latitudes and heights, and returns the variable\n", + "regridded to those axes." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2018-08-15 09:12:55-- https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 7868676 (7.5M) [application/x-netcdf]\n", + "Saving to: “ta_ncep_87-6-88-4.nc.1”\n", + "\n", + "100%[======================================>] 7,868,676 --.-K/s in 0.08s \n", + "\n", + "2018-08-15 09:12:55 (95.3 MB/s) - “ta_ncep_87-6-88-4.nc.1” saved [7868676/7868676]\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "(2, 10, 144)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "!wget \"https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\"\n", + "f=cdms2.open(\"ta_ncep_87-6-88-4.nc\")\n", + "ta=f('ta')\n", + "ta.shape\n", + "(11, 17, 73, 144)\n", + "levOut=cdms2.createAxis([1000.0,950.])\n", + "levOut.designateLevel()\n", + "latOut=cdms2.createAxis(ta.getLatitude()[10:20])\n", + "latOut.designateLatitude()\n", + "ta0 = ta[0,:]\n", + "ta0.getAxisIds()\n", + "['level', 'latitude', 'longitude']\n", + "taout = ta0.crossSectionRegrid(levOut, latOut)\n", + "taout.shape\n", + "(2, 10, 144)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regrid Module\n", + "\n", + "The ``regrid`` module implements the CDMS regridding functionality as\n", + "well as the SCRIP interface. Although this module is not strictly a part\n", + "of CDMS, it is designed to work with CDMS objects." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CDMS Regridder Constructor\n", + "\n", + " \"``regridFunction = Regridder(inputGrid, outputGrid)``\", \"Create a regridder function which interpolates a data array from input to output grid.\n", + " * `CDMS regridder functions`_ describes the calling sequence of this function.\n", + " * ``inputGrid`` and ``outputGrid`` are CDMS grid objects.\n", + " **Note:** To set the mask associated with inputGrid or outputGrid, use the grid setMask function.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder\n", + "\n", + "SCRIP regridder functions are created with the ``regrid.readRegridder``\n", + "function:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder Constructor\n", + "\n", + " \"``regridFunction = regrid.readRegridder(fileobj, mapMethod=None, checkGrid=1)``\", \"Read a regridder from an open CDMS file object.\n", + " * ``fileobj`` is a CDMS file object, as returned from ``cdms.open``.\n", + " * ``mapMethod`` is one of:\n", + " * ``'conservative'``: conservative remapper, suitable where area-integrated fields such as water or heat fluxes must be conserved.\n", + " * ``'bilinear'``: bilinear interpolation\n", + " * ``'bicubic'``: bicubic interpolation\n", + " * ``'distwgt'``: distance-weighted interpolation.\n", + " * It is only necessary to specify the map method if it is not defined in the file.\n", + " * If ``checkGrid`` is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Grid cells may appear to be nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of shifting the cell vertices to the same side modulo 360 degrees.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regridder Functions\n", + "\n", + "It is only necessary to specify the map method if it is not defined in\n", + "the file.\n", + "\n", + "If ``checkGrid`` is 1 (default), the grid cells are checked for\n", + "convexity, and ‘repaired’ if necessary. Grid cells may appear to be\n", + "nonconvex if they cross a ``0 / 2pi`` boundary. The repair consists of\n", + "shifting the cell vertices to the same side modulo 360 degrees." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_`CDMS Regridder Functions`\n", + "\n", + "A CDMS regridder function is an instance of the CDMS ``Regridder``\n", + "class. The function is associated with rectangular input and output\n", + "grids. Typically its use is straightforward: the function is passed an\n", + "input array and returns the regridded array. However, when the array has\n", + "missing data, or the input and/or output grids are masked, the logic\n", + "becomes more complicated.\n", + "\n", + "Step 1\n", + "~~~~~~\n", + "\n", + "The regridder function first forms an input mask. This mask is either\n", + "two-dimensional or n-dimensional, depending on the rank of the\n", + "user-supplied mask. If no mask or missing value is specified, the mask\n", + "is obtained from the data array mask if present.\n", + "\n", + "**Two-dimensional case:**\n", + "\n", + "- Let mask\\_1 be the two-dimensional user mask supplied via the mask\n", + " argument, or the mask of the input grid if no user mask is specified.\n", + "- If a missing-data value is specified via the missing argument, let\n", + " the implicit\\_mask be the two-dimensional mask defined as 0 where the\n", + " first horizontal slice of the input array is missing, 1 elsewhere.\n", + "- The input mask is the logical AND(mask\\_1, implicit\\_mask)\n", + "\n", + "**N-dimensional case:**\n", + "\n", + "- If the user mask is 3 or 4-dimensional with the same shape as the\n", + " input array, it is used as the input mask.\n", + "\n", + "Step 2\n", + "~~~~~~\n", + "\n", + "The data is then regridded. In the two-dimensional case, the input mask\n", + "is ‘broadcast’ across the other dimensions of the array. In other words,\n", + "it assumes that all horizontal slices of the array have the same mask.\n", + "The result is a new array, defined on the output grid. Optionally, the\n", + "regridder function can also return an array having the same shape as the\n", + "output array, defining the fractional area of the output array which\n", + "overlaps a non-missing input grid cell. This is useful for calculating\n", + "area-weighted means of masked data.\n", + "\n", + "Step 3\n", + "~~~~~~\n", + "\n", + "Finally, if the output grid has a mask, it is applied to the result\n", + "array. Where the output mask is 0, data values are set to the missing\n", + "data value, or 1.0e20 if undefined. The result array or transient\n", + "variable will have a mask value of 1 (invalid value) for those output\n", + "grid cells which completely overlap input grid cells with missing values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CDMS Regridder Function Types\n", + "\n", + "\"Array or Transient-Variable\", \"``regridFunction(array, missing=None, order=None, mask=None)``\", \"Interpolate a gridded data array to a new grid. The interpolation preserves the area-weighted mean on each horizontal slice.\n", + " * If array is a Variable, a TransientVariable of the same rank as the input array is returned, otherwise a masked array is returned.\n", + " * ``array`` is a Variable, masked array, or Numpy array of rank 2, 3, or 4. * For example, the string 'tzyx' indicates that the dimension order of ``array`` is (time, level, latitude, longitude). If unspecified, the function assumes that the last two dimensions of ``array`` match the input grid.\n", + " * ``missing`` is a Float specifying the missing data value. The default is 1.0e20.\n", + " * ``order`` is a string indicating the order of dimensions of the array. It has the form returned from ``variable.getOrder().``\n", + " * ``mask`` is a Numpy array, of datatype Integer or Float, consisting of a fractional number between 0 and 1.\n", + " * A value of 1 or 1.0 indicates that the corresponding data value is to be ignored for purposes of regridding.\n", + " * A value of 0 or 0.0 indicates that the corresponding data value is valid. This is consistent with the convention for masks used by the MV2 module.\n", + " * A fractional value between 0.0 and 1.0 indicates the fraction of the data value (e.g., the corresponding cell) to be ignored when regridding. This is useful if a variable is regridded first to grid A and then to another grid B; the mask when regridding from A to B would be (1.0 - f) where f is the maskArray returned from the initial grid operation using the ``returnTuple`` argument.\n", + " * If ``mask`` is two-dimensional of the same shape as the input grid, it overrides the mask of the input grid.\n", + " * If the mask has more than two dimensions, it must have the same shape as ``array``. In this case, the ``missing`` data value is also ignored. Such an ndimensional mask is useful if the pattern of missing data varies with level (e.g., ocean data) or time.\n", + " **Note:** If neither ``missing`` or ``mask`` is set, the default mask is obtained from the mask of the array if any.\"\n", + " \"Array, Array\", \"``regridFunction(ar, missing=None, order=None, mask=None, returnTuple=1)``\", \"If called with the optional ``returnTuple`` argument equal to 1, the function returns a tuple ``dataArray``, ``maskArray``).\n", + " * ``dataArray`` is the result data array.\n", + " * ``maskArray`` is a Float32 array of the same shape as ``dataArray``, such that ``maskArray[i,j]`` is fraction of the output grid cell [i,j] overlapping a non-missing cell of the grid.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder Functions\n", + "\n", + "A SCRIP regridder function is an instance of the ScripRegridder class.\n", + "Such a function is created by calling the regrid.readRegridder method.\n", + "Typical usage is straightforward:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2\n", + "import regrid2\n", + "remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc')\n", + "regridf = regrid2.readRegridder(remapf)\n", + "f = cdms2.open('xieArkin-T42.nc')\n", + "t42prc = f('prc')\n", + "f.close()\n", + "# Regrid the source variable\n", + "popdat = regridf(t42prc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The bicubic regridder takes four arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# outdat = regridf(t42prc, gradlat, gradlon, gradlatlon)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A regridder function also has associated methods to retrieve the\n", + "following fields:\n", + "\n", + "- Input grid\n", + "- Output grid\n", + "- Source fraction: the fraction of each source (input) grid cell\n", + " participating in the interpolation.\n", + "- Destination fraction: the fraction of each destination (output) grid\n", + " cell participating in the interpolation.\n", + "\n", + "In addition, a conservative regridder has the associated grid cell areas\n", + "for source and target grids." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder Function Types\n", + "\n", + "\"Array or Transient-Variable\", \"[conservative, bilinear, and distance-weighted regridders] ``regridFunction(array)``\", \"Interpolate a gridded data array to a new grid. The return value is the regridded data variable.\n", + " * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape. \n", + " * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Similarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.\"\n", + " \"Array or Transient-Variable\", \"[bicubic regridders] ``regridFunction(array, gradientLat, gradientLon, gradientLatLon)``\", \"Interpolate a gridded data array to a new grid, using a bicubic regridder. The return value is the regridded data variable.\n", + " * ``array`` is a Variable, MaskedArray, or Numpy array. The rank of the array may be greater than the rank of the input grid, in which case the input grid shape must match a trailing portion of the array shape.\n", + " * For example, if the input grid is curvilinear with shape (64,128), the last two dimensions of the array must match. Simiarly, if the input grid is generic with shape (2560,), the last dimension of the array must have that length.\n", + " * ``gradientLat``: df/di (see the SCRIP documentation). Same shape as ``array``.\n", + " * ``gradientLon``: df/dj. Same shape as ``array``.\n", + " * ``gradientLatLon``: d(df)/(di)(dj). Same shape as array.\"\n", + " \"Numpy array\", \"``getDestinationArea()`` [conservative regridders only]\", \"Return the area of the destination (output) grid cell. \n", + " * The array is 1-D, with length equal to the number of cells in the output grid.\"\n", + " \"Numpy array\", \"``getDestinationFraction()``\", \"Return the area fraction of the destination (output) grid cell that participates in the regridding.\n", + " * The array is 1-D, with length equal to the number of cells in the output grid.\"\n", + " \"CurveGrid or Generic-Grid\", \"``getInputGrid()``\", \"Return the input grid, or None if no input grid is associated with the regridder.\"\n", + " \"CurveGrid or Generic-Grid\", \"``getOutputGrid()``\", \"Return the output grid.\"\n", + " \"Numpy array\", \"``getSourceFraction()``\", \"Return the area fraction of the source (input) grid cell that participates in the regridding.\n", + " * The array is 1-D, with length equal to the number of cells in the input grid\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Examples\n", + "\n", + "\n", + "CDMS Regridder\n", + "\n", + "\n", + "**Example:**\n", + "\n", + "Regrid data to a uniform output grid." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2\n", + "from regrid2 import Regridder\n", + "f = cdms2.open('clt.nc')\n", + "cltf = f.variables['clt']\n", + "ingrid = cltf.getGrid()\n", + "outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0)\n", + "regridFunc = Regridder(ingrid, outgrid)\n", + "newrls = regridFunc(cltf)\n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regridder Constructures\n", + "\n", + " \"3\", \"Open a netCDF file for input.\"\n", + " \"6\", \"Create a 4 x 5 degree output grid. Note that this grid is not associated with a file or dataset.\"\n", + " \"7\", \"Create the regridder function.\"\n", + " \"8\", \"Read all data and regrid. The missing data value is obtained from variable rlsf\"\n", + "\n", + "Return the area fraction of the source (input) grid cell that\n", + "participates in the regridding. The array is 1-D, with length equal to\n", + "the number of cells in the input grid.\n", + "\n", + "**Example:**\n", + "\n", + "Get a mask from a separate file, and set as the input grid mask." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--2018-08-15 09:17:18-- https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 1718908 (1.6M) [application/x-netcdf]\n", + "Saving to: “clt.nc.8”\n", + "\n", + "100%[======================================>] 1,718,908 --.-K/s in 0.02s \n", + "\n", + "2018-08-15 09:17:18 (80.0 MB/s) - “clt.nc.8” saved [1718908/1718908]\n", + "\n", + "--2018-08-15 09:17:18-- https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\n", + "Resolving cdat.llnl.gov... 198.128.245.146\n", + "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 34487602 (33M) [application/x-netcdf]\n", + "Saving to: “geos5-sample.nc.2”\n", + "\n", + "100%[======================================>] 34,487,602 98.5M/s in 0.3s \n", + "\n", + "2018-08-15 09:17:18 (98.5 MB/s) - “geos5-sample.nc.2” saved [34487602/34487602]\n", + "\n" + ] + } + ], + "source": [ + "!wget https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", + "!wget https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\n", + "import cdms2\n", + "from regrid2 import Regridder\n", + "#\n", + "f = cdms2.open('clt.nc')\n", + "cltf = f.variables['clt']\n", + "outgrid = cltf.getGrid()\n", + "g = cdms2.open('geos5-sample.nc')\n", + "ozoneg = g.variables['ozone']\n", + "ingrid = ozoneg.getGrid()\n", + "regridFunc = Regridder(ingrid,outgrid)\n", + "uwmaskvar = g.variables['uwnd']\n", + "uwmask = uwmaskvar[:]<0\n", + "outArray = regridFunc(ozoneg.subSlice(time=0),mask=uwmask)\n", + "f.close()\n", + "g.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"7\", \"Get the input grid.\"\n", + " \"10\", \"Get the output grid.\"\n", + " \"11\", \"Create the regridder function.\"\n", + " \"14\", \"Get the mask.\"\n", + " \"15\", \"Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0.\"\n", + "\n", + "\n", + "**Note:** Although it cannot be determined from the code, both mask and\n", + "the input array sof are four-dimensional. This is the n-dimensional\n", + "case.\n", + "\n", + "\n", + "**Example:**\n", + "\n", + "Generate an array of zonal mean values." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m f = cdms.open(‘rls_ccc_per.nc’)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "f = cdms.open(‘rls_ccc_per.nc’)\n", + "rlsf = f.variables[‘rls’]\n", + "ingrid = rlsf.getGrid()\n", + "outgrid = cdms.createZonalGrid(ingrid)\n", + "regridFunc = Regridder(ingrid,outgrid)\n", + "mean = regridFunc(rlsf)\n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"3\", \"Get the input grid. Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid.\"\n", + " \"4\", \"Create a zonal grid. outgrid has the same latitudes as ingrid, and a singleton longitude dimension. createGlobalMeanGrid could be used here to generate a global mean array.\"\n", + " \"5\", \"Generate the regridder function.\"\n", + " \"6\", \"Generate the zonal mean array.\"\n", + "\n", + "\n", + "**Example:**\n", + "\n", + "Regrid an array with missing data, and calculate the area-weighted mean\n", + "of the result." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2\n", + "from cdms2.MV2 import *\n", + "from regrid2 import Regridder\n", + "f = cdms2.open(\"ta_ncep_87-6-88-4.nc\")\n", + "var = f('ta')\n", + "outgrid = cdms2.createUniformGrid(90.0, 46, -4.0, 0.0, 72, 5.0)\n", + "outlatw, outlonw = outgrid.getWeights()\n", + "outweights = outerproduct(outlatw, outlonw)\n", + "grid = var.getGrid()\n", + "sample = var[0,0]\n", + "latw, lonw = grid.getWeights()\n", + "weights = outerproduct(latw, lonw)\n", + "inmask = where(greater(absolute(sample),1.e15),0,1)\n", + "mean = add.reduce(ravel(inmask*weights*sample))/add.reduce(ravel(inmask*weights))\n", + "regridFunc = Regridder(grid, outgrid)\n", + "outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1)\n", + "outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"2\", \"Create a uniform target grid.\"\n", + " \"3\", \"Get the latitude and longitude weights.\"\n", + " \"4\", \"Generate a 2-D weights array.\"\n", + " \"5\", \"Get the input grid. ``var`` is a 4-D variable.\"\n", + " \"6\", \"Get the first horizontal slice from ``var``.\"\n", + " \"7-8\", \"Get the input weights, and generate a 2-D weights array.\"\n", + " \"9\", \"Set the 2-D input mask.\"\n", + " \"10\", \"Calculate the input array area-weighted mean.\"\n", + " \"11\", \"Create the regridder function.\"\n", + " \"12\", \"Regrid. Because returnTuple is set to 1, the result is a tuple (dataArray, maskArray).\"\n", + " \"13\", \"Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SCRIP Regridder\n", + "\n", + "**Example:**\n", + "\n", + "Regrid from a curvilinear to a generic grid, using a conservative\n", + "remapping. Compute the area-weighted means on input and output for\n", + "comparison." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 24)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m24\u001b[0m\n\u001b[0;31m Input mean: 2.60376502339\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", + "!wget https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc\n", + "!wget \"https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", + "import cdms2, regrid2, MV2\n", + "# Open the SCRIP remapping file and data file\n", + "fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc')\n", + "fdat = cdms2.open('xieArkin-T42.nc')\n", + "# Input data array\n", + "dat = fdat('prc')[0,:]\n", + "# Read the SCRIP regridder\n", + "regridf = regrid2.readRegridder(fremap)\n", + "# Regrid the variable\n", + "outdat = regridf(dat)\n", + "# Get the cell area and fraction arrays. Areas are computed only\n", + "# for conservative regridding.\n", + "srcfrac = regridf.getSourceFraction()\n", + "srcarea = regridf.getSourceArea()\n", + "dstfrac = regridf.getDestinationFraction()\n", + "dstarea = regridf.getDestinationArea()\n", + "# calculate area-weighted means\n", + "inmean = MV2.sum(srcfrac*srcarea*MV2.ravel(dat)) / MV2.sum(srcfrac*srcarea)\n", + "outmean = MV2.sum(dstfrac*dstarea*MV2.ravel(outdat)) / MV2.sum(dstfrac*dstarea)\n", + "print 'Input mean:', inmean\n", + "Input mean: 2.60376502339\n", + "print 'Output mean:', outmean\n", + "Output mean: 2.60376502339\n", + "fremap.close()\n", + "fdat.close()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/chapter5.ipynb b/chapter5.ipynb new file mode 100644 index 00000000..c75cd842 --- /dev/null +++ b/chapter5.ipynb @@ -0,0 +1,320 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Plotting CDMS data in Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Overview\n", + "~~~~~~~~\n", + "\n", + "Data read via the CDMS Python interface can be plotted using the ``vcs``\n", + "module. This module, part of the Climate Data\n", + "Analysis Tool (CDAT) is documented in the CDAT reference manual.\n", + "The ``vcs`` module provides access to the functionality of the VCS\n", + "visualization program.\n", + "\n", + "Examples of plotting data accessed from CDMS are given below, as well as\n", + "documentation for the plot routine keywords.\n", + "\n", + "Examples\n", + "~~~~~~~~\n", + "\n", + "In the following examples, it is assumed that variable ``psl`` is\n", + "dimensioned (time, latitude, longitude). ``psl`` is contained in the\n", + "dataset named ``'sample.xml'``." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting a Gridded Variable\n", + "\n", + "Example: plotting a gridded variable" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3169: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " dout = self.data[indx]\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vtk/util/numpy_support.py:135: FutureWarning: Conversion of the second argument of issubdtype from `complex` to `np.complexfloating` is deprecated. In future, it will be treated as `np.complex128 == np.dtype(complex).type`.\n", + " assert not numpy.issubdtype(z.dtype, complex), \\\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3201: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " mout = _mask[indx]\n" + ] + } + ], + "source": [ + "import cdms2, vcs \n", + "f = cdms2.open(\"clt.nc\") \n", + "clt = f.variables['clt'] \n", + "sample = clt[0,:] \n", + "w=vcs.init() \n", + "w.plot(sample) \n", + "f.close() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Notes:**\n", + "\n", + " \"3\",\"Get a horizontal slice, for the first time point.\"\n", + " \"4\",\"Create a VCS Canvas ``w``.\" \n", + " \"5\", \"Plot the data. Because sample is a transient variable, it encapsulates all the time, latitude, longitude, and attribute information.\"\n", + " \"7\", \"Close the file. This must be done after the reference to the persistent variable ``ps l``.\"\n", + "\n", + "Thats it! The axis coordinates, variable name, description, units, etc.\n", + "are obtained from variable sample.\n", + "\n", + "What if the units are not explicitly defined for ``clt``, or a different\n", + "description is desired? ``plot`` has a number of other keywords which\n", + "fill in the extra plot information.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using A Plot Keywords" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3792: VCSDeprecationWarning: Deprecation Warning: Keyword 'file_comment' will be removed in the next versionof UV-CDAT.\n", + " \"of UV-CDAT.\" % keyarg, vcs.VCSDeprecationWarning)\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3796: UserWarning: Unrecognized vcs plot keyword: hms, assuming backend (vtk) keyword\n", + " (keyarg, self.backend.type))\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3792: VCSDeprecationWarning: Deprecation Warning: Keyword 'long_name' will be removed in the next versionof UV-CDAT.\n", + " \"of UV-CDAT.\" % keyarg, vcs.VCSDeprecationWarning)\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3796: UserWarning: Unrecognized vcs plot keyword: ymd, assuming backend (vtk) keyword\n", + " (keyarg, self.backend.type))\n" + ] + } + ], + "source": [ + "import cdms2, vcs \n", + "f = cdms2.open(\"clt.nc\") \n", + "clt = f.variables['clt'] \n", + "sample = clt[0,:] \n", + "w=vcs.init() \n", + "w.plot(sample, units='percent', file_comment='', long_name=\"Total Cloud\", comment1=\"Example plot\", hms=\"00:00:00\", ymd=\"1979/01/01\") \n", + "f.close() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** Keyword arguments can be listed in any order." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting a Time-Latitude Slice\n", + "\n", + "Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``,\n", + "this example selects and plots a time-latitude slice:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import cdms2, vcs \n", + "f = cdms2.open(\"clt.nc\") \n", + "clt = f.variables['clt'] \n", + "samp = clt[:,:,0] \n", + "w = vcs.init() \n", + "w.plot(samp, name='Total Cloudiness') \n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \"4\", \"``samp`` is a slice of ``clt``, at index ``0`` of the last dimension. Since ``samp`` was obtained from the slice operator, it is a transient variable, which includes the latitude and time information.\"\n", + " \"6\", \"The ``name`` keyword defines the identifier, default is the name found in the file.\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plotting Subsetted Data\n", + "\n", + "Calling the variable ``clt`` as a function reads a subset of the\n", + "variable. The result variable ``samp`` can be plotted directly:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import cdms2, vcs \n", + "f = cdms2.open(\"clt.nc\")\n", + "clt = f.variables['clt']\n", + "samp = clt(time = (0.0,100.0), longitude = 180.0, squeeze=1)\n", + "w = vcs.init()\n", + "w.plot(samp)\n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot Method\n", + "\n", + "The ``plot`` method is documented in the CDAT Reference Manual. This\n", + "section augments the documentation with a description of the optional\n", + "keyword arguments. The general form of the plot command is:\n", + "\n", + "``canvas.plot(array [, args] [,key=value [, key=value [, ...] ] ])``\n", + "\n", + "where:\n", + "\n", + "- canvas is a VCS Canvas object, created with the vcs.init method.\n", + "\n", + "- array is a variable, masked array, or Numpy array having between\n", + " two and five dimensions. The last dimensions of the array is termed\n", + " the 'x' dimension, the next-to-last the 'y' dimension, then 'z', 't',\n", + " and 'w'.\n", + " \n", + " - For example, if array is three-dimensional, the axes are\n", + " (z,y,x), and if array is four-dimensional, the axes are (t,z,y,x).\n", + " \n", + " **Note:** that the t dimension need have no connection with time; any \n", + " spatial axis can be mapped to any plot dimension.)\n", + "\n", + " - For a graphics method which is two-dimensional, such as boxfill,\n", + " the y-axis is plotted on the horizontal, and the x-axis on the vertical.\n", + "\n", + " - If array is a gridded variable on a rectangular grid, the plot\n", + " function uses a box-fill graphics method.\n", + "\n", + " - If it is non-rectangular, the meshfill graphics method is used.\n", + "\n", + " **Note:** that some plot keywords apply only to rectangular grids only.\n", + "\n", + "- args are optional positional arguments:\n", + "\n", + " ``args`` := template\\_name, graphics\\_method, graphics\\_name\n", + "\n", + " ``template_name``: the name of the VCS template (e.g., 'AMIP')\n", + "\n", + " ``graphics_method``: the VCS graphics method (boxfill)\n", + "\n", + " ``graphics_name``: the name of the specific graphics method\n", + " ('default')\n", + "\n", + " See the CDAT Reference Manual and VCS Reference Manual for a\n", + " detailed description of these arguments.\n", + "\n", + "- ``key=value``, ... are optional keyword/value pairs, listed in any\n", + " order. These are defined in the table below.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot Keywords\n", + "\n", + " \"``comment1``\", \"string\", \"Comment plotted above ``file_comment``\"\n", + " \"``comment2``\", \"string\", \"Comment plotted above ``comment1``\"\n", + " \"``comment3``\", \"string\", \"Comment plotted above ``comment2``\"\n", + " \"``continents``\", \"0 or 1\", \"if ``1``, plot continental outlines (default:plot if\n", + " * ``xaxis`` is longitude, \n", + " * ``yaxis`` is latitude -or- ``xname`` is 'longitude' and ``yname`` is 'latitude'\"\n", + " \"``file_comment``\", \"string\", \"Comment, defaults to ``variable.parent.comment``\"\n", + " \"``grid``\", \"CDMS grid object\", \"Grid associated with the data. Defaults to ``variable.getGrid()``\"\n", + " \"``hms``\", \"string\", \"Hour, minute, second\"\n", + " \"``long_name``\", \"string\", \"Descriptive variable name, defaults to ``variable.long_name``.\"\n", + " \"``missing_value``\", \"same type as array\", \"Missing data value, defaults to ``variable.getMissing()``\"\n", + " \"``name``\", \"string\", \"Variable name, defaults to ``variable.id``\"\n", + " \"``time``\", \"cdtime relative or absolute\", \"Time associated with the data.\n", + " **Example:**\n", + " ``cdtime.reltime(30.0, 'days since 1978-1-1').``\"\n", + " \"``units``\", \"string\", \"Data units. Defaults to ``variable.units``\"\n", + " \"``variable``\", \"CDMS variable object\", \"Variable associated with the data. The variable grid must have the same shape as the data array.\"\n", + " \"``xarray`` (``[y|z|t|w]array``)\", \"1-D Numpy array\", \"*Rectangular grids only*.\n", + " * Array of coordinate values, having the same length as the corresponding dimension.\n", + " * Defaults to ``xaxis[:\\] (y|z|t|waxis[:])``\"\n", + " \"``xaxis`` (``[y|z|t|w]axis``)\", \"CDMS axis object\", \"*Rectangular grids only*.\n", + " * Axis object. \n", + " * ``xaxis`` defaults to ``grid.getAxis(0)`` \n", + " * ``yaxis`` defaults to ``grid.getAxis(1)``\"\n", + " \"``xbounds`` (``ybounds``)\", \"2-D Numpy array\", \"*Rectangular grids only*.\n", + " * Boundary array of shape ``(n,2)`` where ``n`` is the axis length.\n", + " * Defaults to ``xaxis.getBounds()``, or ``xaxis.genGenericBounds()``\n", + " * if ``None``, similarly for ``ybounds``.\"\n", + " \"``xname`` (``[y|z|t|w]name``)\", \"string\", \"*Rectangular grids only*. \n", + " * Axis name.\n", + " * Defaults to ``xaxis.id`` (``[y|z|t|w]axis.id``)\"\n", + " \"``xrev`` (``yrev``)\", \"0 or 1\", \"If ``xrev`` (``yrev``) is 1, reverse the direction of the ``x-axis (y-axis)``. \n", + " * Defaults to 0, with the following exceptions:\n", + " * If the ``y-axis`` is latitude, and has decreasing values, ``yrev`` defaults to 1\n", + " * If the ``y-axis`` is a vertical level, and has increasing pressure levels, ``yrev`` defaults to 1.\"\n", + " \"``xunits`` (``[y|z|t|w]units``)\", \"string\", \"*Rectangular grids only*.\n", + " * Axis units.\n", + " * Defaults to ``xaxis.units`` (``[y|z|t|w]axis.units``).\"\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 0f807ff0..928e161f 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -95,7 +95,7 @@ from file sample.nc into variable u: .. - +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f = cdms2.open('clt.nc') >>> u = f('u') From 0fbeabaae58514bc9f186f55f7e5f40f8a61cfef Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 24 Oct 2018 13:22:02 -0700 Subject: [PATCH 235/239] Changes to all --- chapter3.ipynb | 212 ++++++++++-------- chapter4.ipynb | 410 ++++++++++++++++------------------ docs/source/manual/cdms_4.rst | 19 +- 3 files changed, 326 insertions(+), 315 deletions(-) diff --git a/chapter3.ipynb b/chapter3.ipynb index f0cf33ac..c4fa7778 100644 --- a/chapter3.ipynb +++ b/chapter3.ipynb @@ -19,7 +19,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -91,33 +91,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Time Constructors Types\n", - "\n", - " \"Reltime\", \"``cdtime.reltime(value, relunits)``\", \"Create a relative time type.\n", - " * ``value`` is an integer or floating point value.\n", - " * relunits`` is a string of the form 'unit(s) [since basetime]' where ``unit = [second | minute | hour | day | week | month | season | year ]``\n", - " * ``basetime`` has the form ``yyyy-mm-dd hh:mi:ss``. \n", - " * The default basetime is 1979-1-1, if no ``since`` clause is specified. \n", - " **Example:** ``r = cdtime.reltime(28, 'days since 1996-1-1')``\"\n", - " \"Comptime\", \"``cdtime.comptime(year, month=1, day=1, hour=0, minute=0, second=0.0)``\", \"Create a component time type.\n", - " * ``year`` is an integer.\n", - " * ``month`` is an integer in the range 1 .. 12\n", - " * ``day`` is an integer in the range 1 .. 31\n", - " * ``hour`` is an integer in the range 0 .. 23\n", - " * ``minute`` is an integer in the range 0 .. 59\n", - " * ``second`` is a floating point number in the range 0.0 ,, 60.0.\n", + "Table Time Constructors\n", "\n", - " **Example:** ``c = cdtime.comptime(1996, 2, 28)``\"\n" + "A relative time type has two members, value and units. Both can be set." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Relative Time Member Types\n", + "Relative Time\n", "\n", - "\"Float\", \"value\", \"Number of units\" \n", - "\"String\", \"units\", \"Relative units, of the form “unit(s) since basetime\"" + "3.4.1. Table Relative Time Members" ] }, { @@ -126,21 +111,15 @@ "source": [ "Component Time\n", "\n", - "A component time type has six members, all of which are settable." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Component Time Types\n", - " \n", - " * \"Integer\", \"year\", \"Year value\"\n", - " * \"Integer\", \"month\", \"Month, in the range 1..12\"\n", - " * \"Integer\", \"day\", \"Day of month, in the range 1 .. 31\"\n", - " * \"Integer\", \"hour\", \"Hour, in the range 0 .. 23\"\n", - " * \"Integer\", \"minute\", \"Minute, in the range 0 .. 59\"\n", - " * \"Float\", \"second\", \"Seconds, in the range 0.0 .. 60.0\"" + "A component time type has six members, all of which are settable.\n", + "3.5.1. Table Component Time\n", + "Type \tName \tSummary\n", + "Integer \tyear \tYear value\n", + "Integer \tmonth \tMonth, in the range 1..12\n", + "Integer \tday \tDay of month, in the range 1 .. 31\n", + "Integer \thour \tHour, in the range 0 .. 23\n", + "Integer \tminute \tMinute, in the range 0 .. 59\n", + "Float \tsecond \tSeconds, in the range 0.0 .. 60.0" ] }, { @@ -156,7 +135,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Time Methods Types\n", + "Time Methods \n", "\n", " \"Comptime or Reltime\", \"``t.add(value,intervalUnits, calendar=cdtime.Default-Calendar)``\", \"Add an interval of time to a time type t. Returns the same type of time.\n", " * ``value`` is the Float number of interval units.\n", @@ -183,26 +162,25 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 5)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m 29.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "name": "stdout", + "output_type": "stream", + "text": [ + "29.000000 days since 1996-1-1\n", + "1996-2-29 12:0:0.0\n" ] } ], "source": [ "from cdtime import *\n", "c = comptime(1996,2,28)\n", - "r = reltime(28,\"days since 1996-1-1\") \n", + "r = reltime(28,\"days since 1996-1-1\")\n", "print r.add(1,Day)\n", - "29.000000 days since 1996-1-1\n", - "print c.add(36,Hours)\n", - "1996-2-29 12:0:0.0 " + "\n", + "print c.add(36,Hours)" ] }, { @@ -212,24 +190,55 @@ "**Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising." ] }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1979-9-1 0:0:0.0" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "c = comptime(1979,8,31)\n", + "c.add(1,Month) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months:" + ] + }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 3)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m 1979-9-1 0:0:0.0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] + "data": { + "text/plain": [ + "1981-8-1 0:0:0.0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "c = comptime(1979,8,31) \n", - "c.add(1,Month) \n", - "1979-9-1 0:0:0.0 " + "c = comptime(1979,8,31)\n", + "c.add(2,Years)" ] }, { @@ -245,25 +254,59 @@ "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 7)", + "ename": "NameError", + "evalue": "name 'cdtime' is not defined", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m7\u001b[0m\n\u001b[0;31m .. >>> print r.cmp(c)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcdtime\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreltime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m28\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"days since 1996-1-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1996\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m28\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcmp\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdtime' is not defined" ] } ], "source": [ - "from cdtime import * \n", - "r = cdtime.reltime(28,\"days since 1996-1-1\") \n", - "c = comptime(1996,2,28) \n", - "print c.cmp(r) \n", - "1\n", + "from cdtime import *\n", + "r = cdtime.reltime(28,\"days since 1996-1-1\")\n", + "c = comptime(1996,2,28)\n", + "print c.cmp(r)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Subtract an interval of time." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'cdtime' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcdtime\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreltime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m28\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"days since 1996-1-1\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1996\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m28\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msub\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mDays\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdtime' is not defined" + ] + } + ], + "source": [ + "from cdtime import *\n", + "r = cdtime.reltime(28,\"days since 1996-1-1\")\n", + "c = comptime(1996,2,28)\n", + "print r.sub(10,Days)\n", "\n", - ".. >>> print r.cmp(c) \n", - ".. -1\n", - ".. >>> print r.cmp(r) \n", - ".. 1" + "print c.sub(30,Days)" ] }, { @@ -337,35 +380,28 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 3)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m 58.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "name": "stdout", + "output_type": "stream", + "text": [ + "58.000000 days since 1996-1-1\n", + "393.000000 days since 1995\n", + "393.0\n" ] } ], "source": [ - "c = comptime(1996,2,28) \n", - "print c.torel(\"days since 1996-1-1\") \n", - "58.000000 days since 1996-1-1 \n", - "r = reltime(28,\"days since 1996-1-1\") \n", - "print r.torel(\"days since 1995\") \n", - "393.000000 days since 1995 \n", - "print r.torel(\"days since 1995\").value \n", - "393.0 " + "c = comptime(1996,2,28)\n", + "print c.torel(\"days since 1996-1-1\")\n", + "\n", + "r = reltime(28,\"days since 1996-1-1\")\n", + "print r.torel(\"days since 1995\")\n", + "\n", + "print r.torel(\"days since 1995\").value" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/chapter4.ipynb b/chapter4.ipynb index cc09a03d..17592cc0 100644 --- a/chapter4.ipynb +++ b/chapter4.ipynb @@ -37,27 +37,20 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/bin/sh: wgethttps://cdat.llnl.gov/cdat/sample_data/clt.nc: No such file or directory\r\n" - ] - }, { "name": "stderr", "output_type": "stream", "text": [ - "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1370: Warning: \n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1341: Warning: \n", "avariable.regrid: We chose regridTool = esmf for you among the following choices:\n", " Tools -> 'regrid2' (old behavior)\n", " 'esmf' (conserve, patch, linear) or\n", " 'libcf' (linear)\n", " warnings.warn(message, Warning)\n", - "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1377: Warning: \n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1348: Warning: \n", "avariable.regrid: We chose regridMethod = linear for you among the following choices:\n", " 'conserve' or 'linear' or 'patch'\n", " warnings.warn(message, Warning)\n" @@ -69,28 +62,27 @@ "(181, 360)" ] }, - "execution_count": 2, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "!wget\"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", - "# wget \"https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", "import cdms2\n", "import cdat_info\n", "f1=cdms2.open(\"clt.nc\")\n", "f2=cdms2.open(\"geos5-sample.nc\")\n", "clt=f1('clt') # Read the data\n", "clt.shape\n", - "(120, 46, 72)\n", + "\n", "ozone=f2['ozone'] # Get the file variable (no data read)\n", "outgrid = ozone.getGrid() # Get the target grid\n", "cltnew = clt.regrid(outgrid)\n", "cltnew.shape\n", - "(120, 181, 360)\n", - "outgrid.shape\n", - "(181, 360)" + "\n", + "outgrid.shape" ] }, { @@ -113,21 +105,21 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/regrid2/horizontal.py:374: Warning: While this will work for now, please note that the Regridder class has been renamed Horizontal, the name 'Regridder' will be deprecated in future version. Please edit your code accordingly\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/regrid2/horizontal.py:374: Warning: While this will work for now, please note that the Regridder class has been renamed Horizontal, the name 'Regridder' will be deprecated in future version. Please edit your code accordingly\n", " Warning)\n" ] } ], "source": [ - "!#wget\"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", - "!#wget\"https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\"\n", "import cdms2\n", "from regrid2 import Regridder\n", "f = cdms2.open(\"clt.nc\")\n", @@ -204,61 +196,91 @@ "source": [ "Regridding Data with SCRIP\n", "\n", - "**Example:**\n", + "Example:\n", "\n", - "Regrid data from a T42 to POP4/3 grid, using the first-order,\n", - "conservative interpolator.\n", + "Regrid data from a T42 to POP4/3 grid, using the first-order, conservative interpolator.\n", "\n", "In this example:\n", "\n", - "- The input grid is defined in remap_grid_T42.nc.\n", - "- The output grid is defined in remap_grid_POP43.nc.\n", - "- The input data is variable src_array in file sampleT42Grid.nc.\n", - "- The file scrip_in has contents:\n", - "\n", - " &remap_inputs\n", - " num_maps = 1\n", - "\n", - " grid1_file = 'remap_grid_T42.nc'\n", - " grid2_file = 'remap_grid_POP43.nc'\n", - " interp_file1 = 'rmp_T42_to_POP43_conserv.nc'\n", - " interp_file2 = 'rmp_POP43_to_T42_conserv.nc'\n", - " map1_name = 'T42 to POP43 Conservative Mapping' \n", - " map2_name = 'POP43 to T42 Conservative Mapping'\n", - " map_method = 'conservative'\n", - " normalize_opt = 'frac'\n", - " output_opt = 'scrip'\n", - " restrict_type = 'latitude'\n", - " num_srch_bins = 90\n", - " luse_grid1_area = .false.\n", - " luse_grid2_area = .false.\n", - "\n", - "\n", - "``num_maps`` specifies the number of mappings generated, either 1 or 2.\n", - "For a single mapping, ``grid1_file`` and ``grid2_file`` are the source\n", - "and target grid definitions, respectively. The ``map_method`` specifies\n", - "the type of interpolation, either ‘conservative’, ‘bilinear’, ‘bicubic’,\n", - "or ‘distwgt’ (distanceweighted). The remaining parameters are described\n", - "in the SCRIP documentation.\n", - "\n", - "Once the grids and input file are defined, run the scrip executable to\n", - "generate the remapping file ‘rmp\\_T42\\_to\\_POP43\\_conserv.nc’\n", - "\n", - "\n", - "::\n", - "\n", - " % scrip\n", - " Using latitude bins to restrict search.\n", - " Computing remappings between:\n", - " T42 Gaussian Grid\n", - " and\n", - " POP 4/3 Displaced-Pole T grid\n", - " grid1 sweep\n", - " grid2 sweep\n", - " Total number of links = 63112\n", - "\n", - "\n", - "Next, run CDAT and create the regridder:\n" + " The input grid is defined in remap_grid_T42.nc.\n", + " The output grid is defined in remap_grid_POP43.nc.\n", + " The input data is variable src_array in file sampleT42Grid.nc.\n", + " The file scrip_in has contents:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m &remap_inputs\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "&remap_inputs\n", + "num_maps = 1\n", + "\n", + "grid1_file = 'remap_grid_T42.nc'\n", + "grid2_file = 'remap_grid_POP43.nc'\n", + "interp_file1 = 'rmp_T42_to_POP43_conserv.nc'\n", + "interp_file2 = 'rmp_POP43_to_T42_conserv.nc'\n", + "map1_name = 'T42 to POP43 Conservative Mapping'\n", + "map2_name = 'POP43 to T42 Conservative Mapping'\n", + "map_method = 'conservative'\n", + "normalize_opt = 'frac'\n", + "output_opt = 'scrip'\n", + "restrict_type = 'latitude'\n", + "num_srch_bins = 90\n", + "luse_grid1_area = .false.\n", + "luse_grid2_area = .false." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "num_maps specifies the number of mappings generated, either 1 or 2. For a single mapping, grid1_file and grid2_file are the source and target grid definitions, respectively. The map_method specifies the type of interpolation, either ‘conservative’, ‘bilinear’, ‘bicubic’, or ‘distwgt’ (distanceweighted). The remaining parameters are described in the SCRIP documentation.\n", + "\n", + "Once the grids and input file are defined, run the scrip executable to generate the remapping file ‘rmp_T42_to_POP43_conserv.nc’" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 2)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m Using latitude bins to restrict search.\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "% scrip\n", + "Using latitude bins to restrict search.\n", + " Computing remappings between:\n", + "T42 Gaussian Grid\n", + " and\n", + "POP 4/3 Displaced-Pole T grid\n", + "grid1 sweep\n", + "grid2 sweep\n", + "Total number of links = 63112" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, run CDAT and create the regridder:" ] }, { @@ -267,79 +289,30 @@ "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 2064964 (2.0M) [application/x-netcdf]\n", - "Saving to: “remap_grid_POP43.nc”\n", - "\n", - "100%[======================================>] 2,064,964 --.-K/s in 0.02s \n", - "\n", - "2018-08-15 09:10:03 (85.3 MB/s) - “remap_grid_POP43.nc” saved [2064964/2064964]\n", - "\n", - "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 688696 (673K) [application/x-netcdf]\n", - "Saving to: “remap_grid_T42.nc”\n", - "\n", - "100%[======================================>] 688,696 --.-K/s in 0.009s \n", - "\n", - "2018-08-15 09:10:03 (73.7 MB/s) - “remap_grid_T42.nc” saved [688696/688696]\n", - "\n", - "--2018-08-15 09:10:03-- https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 4637612 (4.4M) [application/x-netcdf]\n", - "Saving to: “rmp_POP43_to_T42_conserv.nc”\n", - "\n", - "100%[======================================>] 4,637,612 --.-K/s in 0.1s \n", - "\n", - "2018-08-15 09:10:04 (40.3 MB/s) - “rmp_POP43_to_T42_conserv.nc” saved [4637612/4637612]\n", - "\n", - "--2018-08-15 09:10:04-- https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 4637612 (4.4M) [application/x-netcdf]\n", - "Saving to: “rmp_T42_to_POP43_conserv.nc”\n", - "\n", - "100%[======================================>] 4,637,612 --.-K/s in 0.05s \n", - "\n", - "2018-08-15 09:10:04 (96.7 MB/s) - “rmp_T42_to_POP43_conserv.nc” saved [4637612/4637612]\n", - "\n", - "--2018-08-15 09:10:04-- https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 7081508 (6.8M) [application/x-netcdf]\n", - "Saving to: “xieArkin-T42.nc”\n", - "\n", - "100%[======================================>] 7,081,508 --.-K/s in 0.07s \n", - "\n", - "2018-08-15 09:10:04 (95.4 MB/s) - “xieArkin-T42.nc” saved [7081508/7081508]\n", - "\n" + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/rmp_T42_to_POP43_conserv.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mregrid2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;31m# Read the regridder from the remapper file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mremapf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'rmp_T42_to_POP43_conserv.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0mregridf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mregrid2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreadRegridder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mremapf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mremapf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/rmp_T42_to_POP43_conserv.nc (No error)" ] } ], "source": [ - "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc\"\n", - "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", - "!wget \"https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc\"\n", - "!wget \"https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc\"\n", - "!wget \"https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", "# Import regrid package for regridder functions\n", "import regrid2, cdms2\n", "# Read the regridder from the remapper file\n", "remapf = cdms2.open('rmp_T42_to_POP43_conserv.nc')\n", "regridf = regrid2.readRegridder(remapf)\n", - "\n", "remapf.close()" ] }, @@ -352,9 +325,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/xieArkin-T42.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Get the source variable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'xieArkin-T42.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mt42prc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'prc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# Regrid the source variable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/xieArkin-T42.nc (No error)" + ] + } + ], "source": [ "# Get the source variable\n", "f = cdms2.open('xieArkin-T42.nc')\n", @@ -449,53 +436,38 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "--2018-08-15 09:12:55-- https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 7868676 (7.5M) [application/x-netcdf]\n", - "Saving to: “ta_ncep_87-6-88-4.nc.1”\n", - "\n", - "100%[======================================>] 7,868,676 --.-K/s in 0.08s \n", - "\n", - "2018-08-15 09:12:55 (95.3 MB/s) - “ta_ncep_87-6-88-4.nc.1” saved [7868676/7868676]\n", - "\n" + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/ta_ncep_87-6-88-4.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# wget \"http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ta_ncep_87-6-88-4.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mta\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ta'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/ta_ncep_87-6-88-4.nc (No error)" ] - }, - { - "data": { - "text/plain": [ - "(2, 10, 144)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "!wget \"https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc\"\n", "f=cdms2.open(\"ta_ncep_87-6-88-4.nc\")\n", "ta=f('ta')\n", "ta.shape\n", - "(11, 17, 73, 144)\n", + "\n", "levOut=cdms2.createAxis([1000.0,950.])\n", "levOut.designateLevel()\n", "latOut=cdms2.createAxis(ta.getLatitude()[10:20])\n", "latOut.designateLatitude()\n", "ta0 = ta[0,:]\n", "ta0.getAxisIds()\n", - "['level', 'latitude', 'longitude']\n", + "\n", "taout = ta0.crossSectionRegrid(levOut, latOut)\n", - "taout.shape\n", - "(2, 10, 144)" + "taout.shape" ] }, { @@ -656,9 +628,23 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/rmp_T42_to_POP43_conserv.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mregrid2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mremapf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'rmp_T42_to_POP43_conserv.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mregridf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mregrid2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreadRegridder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mremapf\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'xieArkin-T42.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/rmp_T42_to_POP43_conserv.nc (No error)" + ] + } + ], "source": [ "import cdms2\n", "import regrid2\n", @@ -680,7 +666,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -747,7 +733,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -784,41 +770,12 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "--2018-08-15 09:17:18-- https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 1718908 (1.6M) [application/x-netcdf]\n", - "Saving to: “clt.nc.8”\n", - "\n", - "100%[======================================>] 1,718,908 --.-K/s in 0.02s \n", - "\n", - "2018-08-15 09:17:18 (80.0 MB/s) - “clt.nc.8” saved [1718908/1718908]\n", - "\n", - "--2018-08-15 09:17:18-- https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 34487602 (33M) [application/x-netcdf]\n", - "Saving to: “geos5-sample.nc.2”\n", - "\n", - "100%[======================================>] 34,487,602 98.5M/s in 0.3s \n", - "\n", - "2018-08-15 09:17:18 (98.5 MB/s) - “geos5-sample.nc.2” saved [34487602/34487602]\n", - "\n" - ] - } - ], + "outputs": [], "source": [ - "!wget https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", - "!wget https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\n", + "# wget http://cdat.llnl.gov/cdat/sample_data/clt.nc\n", + "# wget http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc\n", "import cdms2\n", "from regrid2 import Regridder\n", "#\n", @@ -899,9 +856,23 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/ta_ncep_87-6-88-4.nc (No error)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMV2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mregrid2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mRegridder\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ta_ncep_87-6-88-4.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mvar\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ta'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0moutgrid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreateUniformGrid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m90.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m46\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m4.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m72\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/ta_ncep_87-6-88-4.nc (No error)" + ] + } + ], "source": [ "import cdms2\n", "from cdms2.MV2 import *\n", @@ -954,22 +925,27 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 14, "metadata": {}, "outputs": [ { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 24)", + "ename": "CDMSError", + "evalue": "Cannot open file /export/reshel3/cdms/rmp_T42_to_C02562_conserv.nc (No error)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m24\u001b[0m\n\u001b[0;31m Input mean: 2.60376502339\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mregrid2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mMV2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# Open the SCRIP remapping file and data file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mfremap\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'rmp_T42_to_C02562_conserv.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 7\u001b[0m \u001b[0mfdat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'xieArkin-T42.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;31m# Input data array\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/rmp_T42_to_C02562_conserv.nc (No error)" ] } ], "source": [ - "!wget \"https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", - "!wget https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc\n", - "!wget \"https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc\"\n", + "# wget http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc\n", + "# wget \"http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc\"\n", "import cdms2, regrid2, MV2\n", "# Open the SCRIP remapping file and data file\n", "fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc')\n", @@ -990,11 +966,11 @@ "inmean = MV2.sum(srcfrac*srcarea*MV2.ravel(dat)) / MV2.sum(srcfrac*srcarea)\n", "outmean = MV2.sum(dstfrac*dstarea*MV2.ravel(outdat)) / MV2.sum(dstfrac*dstarea)\n", "print 'Input mean:', inmean\n", - "Input mean: 2.60376502339\n", + "\n", "print 'Output mean:', outmean\n", - "Output mean: 2.60376502339\n", + "\n", "fremap.close()\n", - "fdat.close()\n" + "fdat.close()" ] }, { diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 7b8c0883..7afb1324 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -263,7 +263,7 @@ To regrid a variable which is a function of latitude, height, and arguments the new latitudes and heights, and returns the variable regridded to those axes. -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") @@ -292,7 +292,7 @@ of CDMS, it is designed to work with CDMS objects. CDMS Horizontal Regridder ^^^^^^^^^^^^^^^^^^^^^^^^^ -.. doctest:: +:: from regrid2 import Regridder @@ -435,7 +435,7 @@ A SCRIP regridder function is an instance of the ScripRegridder class. Such a function is created by calling the regrid.readRegridder method. Typical usage is straightforward: -.. doctest:: +:: >>> import cdms2 >>> import regrid2 @@ -451,7 +451,7 @@ Typical usage is straightforward: The bicubic regridder takes four arguments: -.. doctest:: +:: >>> # outdat = regridf(t42prc, gradlat, gradlon, gradlatlon) @@ -511,7 +511,7 @@ CDMS Regridder Regrid data to a uniform output grid. -.. doctest:: +:: >>> import cdms2 @@ -544,7 +544,7 @@ the number of cells in the input grid. Get a mask from a separate file, and set as the input grid mask. -.. doctest:: +:: >>> # wget http://cdat.llnl.gov/cdat/sample_data/clt.nc >>> # wget http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc @@ -585,8 +585,7 @@ case. Generate an array of zonal mean values. -.. doctest:: - +:: >>> f = cdms.open(‘rls_ccc_per.nc’) >>> rlsf = f.variables[‘rls’] >>> ingrid = rlsf.getGrid() @@ -614,7 +613,7 @@ Generate an array of zonal mean values. Regrid an array with missing data, and calculate the area-weighted mean of the result. -.. doctest:: +:: >>> import cdms2 >>> from cdms2.MV2 import * @@ -670,7 +669,7 @@ Regrid from a curvilinear to a generic grid, using a conservative remapping. Compute the area-weighted means on input and output for comparison. -.. doctest:: +:: >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" >>> # wget http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc From dd65dfda5482a0073a433fbcf9db72f0498da447 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 6 Nov 2018 15:45:11 -0800 Subject: [PATCH 236/239] Changes to Jupyter Notebooks --- chapter1.ipynb | 170 +++------------------------------- chapter2.ipynb | 39 +++----- chapter3.ipynb | 37 ++------ chapter5.ipynb | 59 ++++++++---- docs/source/manual/cdms_1.rst | 17 ++-- docs/source/manual/cdms_5.rst | 8 +- 6 files changed, 83 insertions(+), 247 deletions(-) diff --git a/chapter1.ipynb b/chapter1.ipynb index c4c4ee9b..31e31559 100644 --- a/chapter1.ipynb +++ b/chapter1.ipynb @@ -1766,191 +1766,45 @@ "Databases add the ability to search for data and metadata in a\n", "distributed computing environment. At present CDMS supports one\n", "particular type of database, based on the Lightweight Directory Access\n", - "Protocol (LDAP).\n", - "\n", - ".. Here is an example of accessing data via a database:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m .. >>> db = cdms.connect() # Connect to the default database.\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - ".. >>> db = cdms.connect() # Connect to the default database.\n", - ".. >>> f = db.open('ncep_reanalysis_mo') # Open a dataset.\n", - ".. >>> f.variables.keys() # List the variables in the dataset.\n", - ".. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va']\n" + "Protocol (LDAP).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Databases are discussed further in `Section 2.7 `__." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Open file and retrieve u and v variable" + "Here is an example of accessing data via a database:" ] }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 52, "metadata": {}, "outputs": [ { - "ename": "CDMSError", - "evalue": "Cannot open file /export/reshel3/cdms/clt.nc (No error)", + "ename": "NameError", + "evalue": "name 'cdms' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf1\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"clt.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mu\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'v'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 513\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 515\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 516\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 517\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/home/reshel3/anaconda2/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1299\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1300\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1301\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1302\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/clt.nc (No error)" + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Connect to the default database.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ncep_reanalysis_mo'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Open a dataset.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# List the variables in the dataset.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'cdms' is not defined" ] } ], "source": [ - "f1=cdms2.open(\"clt.nc\")\n", - "u = f1('u')\n", - "v = f1('v')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Compute wind velocity" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "vel = MV.sqrt(u[0]**2 + v[0]**2)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(2, 80, 97)" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "vel.shape" + "db = cdms.connect() # Connect to the default database.\n", + "f = db.open('ncep_reanalysis_mo') # Open a dataset.\n", + "f.variables.keys() # List the variables in the dataset." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Display wind velocity" + "Databases are discussed further in Section 2.7 __.\n" ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "import vcs" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "plot=vcs.init()" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAJeCAIAAADdhMaJAAAFsUlEQVR4Xu3BMQEAAADCoPVPbQdvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAxmFQAAQLiEWwAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot.isofill(vel[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "u1 = f1('u',time=1.)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAJeCAIAAADdhMaJAAAFsUlEQVR4Xu3BMQEAAADCoPVPbQdvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAxmFQAAQLiEWwAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot.isofill(u1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/chapter2.ipynb b/chapter2.ipynb index 29c11114..db767067 100644 --- a/chapter2.ipynb +++ b/chapter2.ipynb @@ -1033,16 +1033,12 @@ "metadata": {}, "source": [ "Searching a Database\n", - "\n", - "The ``searchFilter`` method is used to search a database. The result is\n", - "called a search result, and consists of a sequence of result entries.\n", - "\n", - "In its simplest form, ``searchFilter`` takes an argument consisting of a\n", - "string filter. The search returns a sequence of entries, corresponding\n", - "to those objects having an attribute which matches the filter. Simple\n", - "filters have the form (tag = value), where value can contain wildcards.\n", - "For example:\n", - "\n" + "Type \tName \tSummary\n", + "Dictionary \tattributes \tDatabase attribute dictionary\n", + "LDAP \tdb \t(LDAP only) LDAP database object\n", + "String \tnetloc \tHostname, for server-based databases\n", + "String \tpath \tpath name\n", + "String \turi \tUniform Resource Identifier" ] }, { @@ -1113,7 +1109,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "matches all objects with id starting with bmrc, and a project attribute\n", + "Matches all objects with id starting with bmrc, and a project attribute\n", "with value ‘AMIP2’.\n", "\n", "Formally, search filters are strings defined as follows:\n", @@ -2799,6 +2795,13 @@ " ccSlopeVarianceBySeasonFiltNet(pathTa,pathTas,'80-1','81-12')" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notes:" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -2977,20 +2980,6 @@ " var is a transient variable.\n", " Plot the variance and count variables. Spatial longitude and latitude information are carried with the computations, so the continents are plotted correctly.\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/chapter3.ipynb b/chapter3.ipynb index c4fa7778..b00d80c4 100644 --- a/chapter3.ipynb +++ b/chapter3.ipynb @@ -212,12 +212,13 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months:" + "In other words, the day component of c was ignored in the addition, \n", + "and the day/hour/minute components of the results are just the defaults. \n", + "If the interval is in years, the interval is converted internally to \n", + "months:" ] }, { @@ -273,10 +274,8 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ "Subtract an interval of time." ] @@ -316,30 +315,6 @@ "Subtract an interval of time." ] }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "invalid syntax (, line 5)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m 18.000000 days since 1996-1-1\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" - ] - } - ], - "source": [ - "from cdtime import * \n", - "r = cdtime.reltime(28,\"days since 1996-1-1\") \n", - "c = comptime(1996,2,28) \n", - "print r.sub(10,Days) \n", - "18.000000 days since 1996-1-1 \n", - "print c.sub(30,Days) \n", - "1996-1-29 0:0:0.0 " - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/chapter5.ipynb b/chapter5.ipynb index c75cd842..24795474 100644 --- a/chapter5.ipynb +++ b/chapter5.ipynb @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "scrolled": true }, @@ -112,18 +112,25 @@ "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3792: VCSDeprecationWarning: Deprecation Warning: Keyword 'long_name' will be removed in the next versionof UV-CDAT.\n", " \"of UV-CDAT.\" % keyarg, vcs.VCSDeprecationWarning)\n", "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vcs/Canvas.py:3796: UserWarning: Unrecognized vcs plot keyword: ymd, assuming backend (vtk) keyword\n", - " (keyarg, self.backend.type))\n" + " (keyarg, self.backend.type))\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3169: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " dout = self.data[indx]\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/vtk/util/numpy_support.py:135: FutureWarning: Conversion of the second argument of issubdtype from `complex` to `np.complexfloating` is deprecated. In future, it will be treated as `np.complex128 == np.dtype(complex).type`.\n", + " assert not numpy.issubdtype(z.dtype, complex), \\\n", + "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3201: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", + " mout = _mask[indx]\n" ] } ], "source": [ - "import cdms2, vcs \n", - "f = cdms2.open(\"clt.nc\") \n", - "clt = f.variables['clt'] \n", - "sample = clt[0,:] \n", - "w=vcs.init() \n", - "w.plot(sample, units='percent', file_comment='', long_name=\"Total Cloud\", comment1=\"Example plot\", hms=\"00:00:00\", ymd=\"1979/01/01\") \n", - "f.close() " + "import cdms2, vcs\n", + "f = cdms2.open(\"clt.nc\")\n", + "clt = f.variables['clt']\n", + "sample = clt[0,:]\n", + "w=vcs.init()\n", + "w.plot(sample, units='percent', file_comment='', long_name=\"Total Cloud\", comment1=\"Example plot\", hms=\"00:00:00\", ymd=\"1979/01/01\")\n", + "\n", + "f.close()" ] }, { @@ -145,19 +152,30 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy4AAAJeCAIAAADdhMaJAAAFsUlEQVR4Xu3BMQEAAADCoPVPbQdvoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAxmFQAAQLiEWwAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "import cdms2, vcs \n", - "f = cdms2.open(\"clt.nc\") \n", - "clt = f.variables['clt'] \n", - "samp = clt[:,:,0] \n", - "w = vcs.init() \n", - "w.plot(samp, name='Total Cloudiness') \n", - "f.close()" + "import cdms2, vcs\n", + "f = cdms2.open(\"clt.nc\")\n", + "clt = f.variables['clt']\n", + "samp = clt[:,:,0]\n", + "w = vcs.init()\n", + "w.plot(samp, name='Total Cloudiness')" ] }, { @@ -180,16 +198,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ - "import cdms2, vcs \n", + "import cdms2, vcs\n", "f = cdms2.open(\"clt.nc\")\n", "clt = f.variables['clt']\n", "samp = clt(time = (0.0,100.0), longitude = 180.0, squeeze=1)\n", "w = vcs.init()\n", "w.plot(samp)\n", + "\n", "f.close()" ] }, diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 928e161f..743cb5e1 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -95,7 +95,7 @@ from file sample.nc into variable u: .. -:: + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f = cdms2.open('clt.nc') >>> u = f('u') @@ -690,8 +690,8 @@ For example, suppose the source data on a T42 grid is to be mapped to a POP curvilinear grid. Assume that SCRIP generated a remapping file named rmp_T42_to_POP43_conserv.nc: -.. doctest:: - +.. + >>> # Import regrid package for regridder functions >>> import regrid2, cdms2 @@ -846,13 +846,12 @@ distributed computing environment. At present CDMS supports one particular type of database, based on the Lightweight Directory Access Protocol (LDAP). -.. Here is an example of accessing data via a database: +Here is an example of accessing data via a database: -.. .. doctest:: - -.. >>> db = cdms.connect() # Connect to the default database. -.. >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. -.. >>> f.variables.keys() # List the variables in the dataset. +:: + >>> db = cdms.connect() # Connect to the default database. + >>> f = db.open('ncep_reanalysis_mo') # Open a dataset. + >>> f.variables.keys() # List the variables in the dataset. .. ['ua', 'evs', 'cvvta', 'tauv', 'wap', 'cvwhusa', 'rss', 'rls', ... 'prc', 'ts', 'va'] diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 0edffd37..9c1b67d9 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -45,7 +45,7 @@ Plotting a Gridded Variable **Example:** Plotting a gridded variable -.. doctest:: +:: >>> import cdms2, vcs >>> f = cdms2.open("clt.nc") @@ -77,7 +77,7 @@ fill in the extra plot information. Using A Plot Keywords ^^^^^^^^^^^^^^^^^^^^^ -.. doctest:: +:: >>> import cdms2, vcs >>> f = cdms2.open("clt.nc") @@ -97,7 +97,7 @@ Plotting a Time-Latitude Slice Assuming that variable ``clt`` has domain ``(time,latitude,longitude)``, this example selects and plots a time-latitude slice: -.. doctest:: +:: >>> import cdms2, vcs >>> f = cdms2.open("clt.nc") @@ -121,7 +121,7 @@ Plotting Subsetted Data Calling the variable ``clt`` as a function reads a subset of the variable. The result variable ``samp`` can be plotted directly: -.. doctest:: +:: >>> import cdms2, vcs >>> f = cdms2.open("clt.nc") From 06f672c81175370e44b6c1240c237ef21d0c3f15 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 7 Nov 2018 14:24:16 -0800 Subject: [PATCH 237/239] Changes to all --- chapter4.ipynb | 7 -- docs/source/manual/cdms_2.rst | 152 +++++++++++++++++----------------- docs/source/manual/cdms_3.rst | 16 ++-- docs/source/manual/cdms_4.rst | 20 ++--- docs/source/manual/cdms_5.rst | 4 +- docs/source/manual/cdms_6.rst | 20 ++--- docs/source/manual/cdms_7.rst | 4 +- 7 files changed, 108 insertions(+), 115 deletions(-) diff --git a/chapter4.ipynb b/chapter4.ipynb index 17592cc0..f688e877 100644 --- a/chapter4.ipynb +++ b/chapter4.ipynb @@ -972,13 +972,6 @@ "fremap.close()\n", "fdat.close()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 020bc748..339d77ef 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -46,8 +46,8 @@ the class internal (non-persistent) attributes, constructors (functions for creating an object), and class methods (functions). A method can return an instance of a CDMS class, or one of the Python types: -Table PythonTypes used in CDMS -------------------------------- +PythonTypes used in CDMS +------------------------ .. csv-table:: :header: "Type", "Description" :widths: 10, 80 @@ -144,8 +144,8 @@ Rather, they are called as module functions, e.g., -Table Cdms Module Functions ---------------------------- +Cdms Module Functions +--------------------- .. csv-table:: :header: "Type", "Definition" @@ -291,8 +291,8 @@ Table Cdms Module Functions -Table Class Tags --------------------- +Class Tags +---------- .. csv-table:: :header: "Tag", "Class" :widths: 20, 20 @@ -327,8 +327,8 @@ external attributes are written, but not the internal attributes. Attributes Common to All CDMS Objects ------------------------------------- -Table Attributes Common to All CDMS Objects -------------------------------------------- +Attributes Common to All CDMS Objects +------------------------------------- .. csv-table:: Attributes common to all CDMS objects :header: "Type", "Name", "Definition" @@ -337,8 +337,8 @@ Table Attributes Common to All CDMS Objects "Dictionary", "attributes", "External attribute dictionary for this object." -Table Getting and Setting Attributes ------------------------------------- +Getting and Setting Attributes +------------------------------ .. csv-table:: :header: "Type", "Definition" :widths: 20, 80 @@ -369,8 +369,8 @@ documents methods that are common to all CoordinateAxis types. See `HorizontalGrid <#id4>`_ specifies methods that are unique to 1D Axis objects. -Table CoordinateAxis Types --------------------------- +CoordinateAxis Types +-------------------- .. csv-table:: :header: "Type", "Definition" @@ -390,8 +390,8 @@ Table CoordinateAxis Types * An axis in a ``CdmsFile`` may be designated the unlimited axis, meaning that it can be extended in length after the initial definition. * There can be at most one unlimited axis associated with a ``CdmsFile``." -Table CoordinateAxis Internal Attributes ----------------------------------------- +CoordinateAxis Internal Attributes +---------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -402,8 +402,8 @@ Table CoordinateAxis Internal Attributes "``Dataset``", "``parent``", "The dataset which contains the variable." "``Tuple``", "``shape``", "The length of each axis." -Table Axis Constructors ------------------------ +Axis Constructors +----------------- .. csv-table:: :header: "Constructor", "Description" @@ -430,8 +430,8 @@ Table Axis Constructors * See `A First Example`_ ." -Table CoordinateAxis Methods ----------------------------- +CoordinateAxis Methods +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -490,8 +490,8 @@ Table CoordinateAxis Methods "``Integer``", "``size()``", "The number of elements in the axis." "``String``", "``typecode()``", "The ``Numpy`` datatype identifier." -Table Axis Methods, Additional to CoordinateAxis ------------------------------------------------- +Axis Methods, Additional to CoordinateAxis +------------------------------------------ .. csv-table:: :header: "Type", "Method", "Definition" @@ -540,8 +540,8 @@ Table Axis Methods, Additional to CoordinateAxis * The stride ``k`` can be positive or negative. * Wraparound is supported for longitude dimensions or those with a modulus attribute." -Table Axis Slice Operators --------------------------- +Axis Slice Operators +-------------------- .. csv-table:: :header: "Slice", "Definition" @@ -585,8 +585,8 @@ As of CDMS V3, the legacy cuDataset interface is also supported by Cdms-Files. See “cu Module”. -Table CdmsFile Internal Attributes ----------------------------------- +CdmsFile Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -598,8 +598,8 @@ Table CdmsFile Internal Attributes "``String``", "``id``", "File pathname." "``Dictionary``", "``variables``", "Variables contained in the file." -Table CdmsFile Constructors ---------------------------- +CdmsFile Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -612,8 +612,8 @@ Table CdmsFile Constructors * ``mode`` is the open mode indicator, as listed in `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." -Table CdmsFile Methods ----------------------- +CdmsFile Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -700,8 +700,8 @@ Table CdmsFile Methods * ``index`` is the extended dimension index to write to. The default index is determined by lookup relative to the existing extended dimension. **Note:** data can also be written by setting a slice of a file variable, and attributes can be written by setting an attribute of a file variable." -Table CDMS Datatypes --------------------- +CDMS Datatypes +-------------- .. csv-table:: :header: "CDMS Datatype", "Definition" @@ -794,8 +794,8 @@ To access a database: ``db.close()`` -Table Database Internal Attributes ----------------------------------- +Database Internal Attributes +---------------------------- .. csv-table:: @@ -809,8 +809,8 @@ Table Database Internal Attributes "``String``", "``uri``", "Uniform Resource Identifier" -Table Database Constructors ---------------------------- +Database Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -829,8 +829,8 @@ Table Database Constructors * ``password`` is the user password. **Note:** A password is not required for an anonymous connection" -Table Database Methods ----------------------- +Database Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -985,8 +985,8 @@ variables defined on a 94x192 grid: -Table SearchResult Methods --------------------------- +SearchResult Methods +-------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1008,8 +1008,8 @@ information defined for the associated CDMS object, which is retrieved with the ``getObject`` method. -Table ResultEntry Attributes ----------------------------- +ResultEntry Attributes +---------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1019,8 +1019,8 @@ Table ResultEntry Attributes "Dictionary", "``attributes``", "The attributes returned from the search. ``attributes[key]`` is a list of all string values associated with the key" -Table ResultEntry Methods -------------------------- +ResultEntry Methods +------------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1138,8 +1138,8 @@ As of CDMS V3, the legacy cuDataset interface is supported by Datasets. See “cu Module". -Table Dataset Internal Attributes ---------------------------------- +Dataset Internal Attributes +--------------------------- .. csv-table:: :header: "Type", "Name", "Description" @@ -1155,8 +1155,8 @@ Table Dataset Internal Attributes "Dictionary", "``variables``", "Variables contained in the dataset." "Dictionary", "``xlinks``", "External links contained in the dataset." -Table Dataset Constructors --------------------------- +Dataset Constructors +-------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1166,8 +1166,8 @@ Table Dataset Constructors "``datasetobj = cdms.open(String uri, String mode='r')``", "Open the dataset specified by the Universal Resource Indicator, a CDML file. Returns a Dataset object. mode is one of the indicators listed in `Open Modes <#table-open-modes>`__ . ``openDataset`` is a synonym for ``open``" -Table Open Modes ----------------- +Open Modes +---------- .. csv-table:: :header: "Mode", "Definition" @@ -1180,8 +1180,8 @@ Table Open Modes "‘w’", "Create a new file, read-write" -Table Dataset Methods ---------------------- +Dataset Methods +--------------- .. csv-table:: :header: "Type", "Definition", "Description" @@ -1277,8 +1277,8 @@ http://numpy.sourceforge.net for a description of these functions. -Table Variable Constructors in Module MV ------------------------------------------ +Variable Constructors in Module MV +----------------------------------- .. tabularcolumns:: |l|r| @@ -1303,8 +1303,8 @@ The following table describes the MV non-constructor functions. with the exception of argsort, all functions return a transient variable. -Table MV Functions ------------------- +MV Functions +------------ .. csv-table:: :header: "Function", "Description" :widths: 50, 80 @@ -1365,8 +1365,8 @@ cells. Specifically, a HorizontalGrid: CDMS supports several types of HorizontalGrids: -Table Grids ------------ +Grids +----- .. csv-table:: :header: "Grid Type", "Definition" @@ -1377,8 +1377,8 @@ Table Grids "``GenericGrid``", "Latitude and longitude are 1-D auxiliary coordinate axis (AuxAxis1D)" -Table HorizontalGrid Internal Attribute ---------------------------------------- +HorizontalGrid Internal Attribute +--------------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1392,8 +1392,8 @@ Table HorizontalGrid Internal Attribute -Table RectGrid Constructors ---------------------------- +RectGrid Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1413,8 +1413,8 @@ Table RectGrid Constructors -Table HorizontalGrid Methods ----------------------------- +HorizontalGrid Methods +---------------------- .. csv-table:: @@ -1474,8 +1474,8 @@ Table HorizontalGrid Methods * If unspecified, the grid ID is copied." -Table RectGrid Methods, Additional to HorizontalGrid Methods ------------------------------------------------------------- +RectGrid Methods, Additional to HorizontalGrid Methods +------------------------------------------------------ .. csv-table:: :header: "Type", "Method", "Description" @@ -1538,8 +1538,8 @@ advantage of the attribute, domain, and mask information in a transient variable. -Table Variable Internal Attributes ----------------------------------- +Variable Internal Attributes +---------------------------- .. csv-table:: :header: "Type", "Name", "Definition" @@ -1552,8 +1552,8 @@ Table Variable Internal Attributes "Tuple", "``shape``", "The length of each axis of the variable" -Table Variable Constructors ---------------------------- +Variable Constructors +--------------------- .. csv-table:: :header: "Constructor", "Description" @@ -1581,8 +1581,8 @@ Table Variable Constructors -Table Variable Methods ----------------------- +Variable Methods +---------------- .. csv-table:: :header: "Type", "Method", "Definition" @@ -1739,8 +1739,8 @@ Read all data for March, 1980: -Table Variable Slice Operators ------------------------------- +Variable Slice Operators +------------------------ .. csv-table:: :header: "Operator", "Description" @@ -1758,8 +1758,8 @@ Table Variable Slice Operators -Table Index and Coordinate Intervals ------------------------------------- +Index and Coordinate Intervals +------------------------------ .. csv-table:: :header: "Interval Definition", "Example Interval Definition", "Example" @@ -1843,8 +1843,8 @@ components is the positional form, where the component order corresponds to the axis order of a variable. For example: -Table Selector Keywords ------------------------ +Selector Keywords +----------------- .. csv-table:: :header: "Keyword", "Description", "Value" diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index cd5680e9..0de48446 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -78,8 +78,8 @@ Time Constructors The following table describes the methods for creating time types. -Table Time Constructors -~~~~~~~~~~~~~~~~~~~~~~~ +Time Constructors +~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Constructor", "Defintion" @@ -92,8 +92,8 @@ Relative Time ^^^^^^^^^^^^^ -Table Relative Time Members -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Relative Time Members +~~~~~~~~~~~~~~~~~~~~~ Component Time @@ -101,8 +101,8 @@ Component Time A component time type has six members, all of which are settable. -Table Component Time -~~~~~~~~~~~~~~~~~~~~ +Component Time +~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Name", "Summary" :widths: 15, 15, 50 @@ -119,8 +119,8 @@ Time Methods The following methods apply both to relative and component times. -Table Time Methods -~~~~~~~~~~~~~~~~~~ +Time Methods +~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Method", "Definition" :widths: 20, 75, 80 diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 7afb1324..0ad2da33 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -300,8 +300,8 @@ Makes the CDMS Regridder class available within a Python program. An instance of Regridder is a function which regrids data from rectangular input to output grids. -Table CDMS Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CDMS Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" @@ -319,8 +319,8 @@ SCRIP Regridder SCRIP regridder functions are created with the ``regrid.readRegridder`` function: -Table SCRIP Regridder Constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +SCRIP Regridder Constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Constructor", "Description" @@ -403,8 +403,8 @@ data value, or 1.0e20 if undefined. The result array or transient variable will have a mask value of 1 (invalid value) for those output grid cells which completely overlap input grid cells with missing values -Table CDMS Regridder Function -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CDMS Regridder Function +~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Type", "Function", "Description" @@ -469,8 +469,8 @@ following fields: In addition, a conservative regridder has the associated grid cell areas for source and target grids. -Table SCRIP Regridder Functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +SCRIP Regridder Functions +~~~~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Return Type", "Method", "Description" @@ -524,8 +524,8 @@ Regrid data to a uniform output grid. >>> newrls = regridFunc(cltf) >>> f.close() -Table Regridder Constructure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Regridder Constructure +~~~~~~~~~~~~~~~~~~~~~~ .. csv-table:: :header: "Line", "Notes" diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 9c1b67d9..e7594194 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -184,8 +184,8 @@ where: - ``key=value``, ... are optional keyword/value pairs, listed in any order. These are defined in the table below. -Table Plot Keywords -^^^^^^^^^^^^^^^^^^^ +Plot Keywords +^^^^^^^^^^^^^^ .. csv-table:: :header: "Key", "Type", "Value" diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 59cbf22e..733a7289 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -49,8 +49,8 @@ where The CDML elements are: -Table CDML Tags -^^^^^^^^^^^^^^^^^^^ +CDML Tags +^^^^^^^^^ +------------+---------------------------------------+ | Tag | Description | @@ -76,8 +76,8 @@ Special Characters XML reserves certain characters for markup. If they appear as content, they must be encoded to avoid confusion with markup: -Table Special Character Encodings -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Special Character Encodings +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------+------------+ @@ -235,8 +235,8 @@ length). ``linear-element ::=`` ** ** -Table Axis Elements -^^^^^^^^^^^^^^^^^^^ +Axis Elements +^^^^^^^^^^^^^ .. csv-table:: :header: "Attribute", "Required?", "CF", "GDT", "Notes" @@ -313,8 +313,8 @@ rectilinear in topology, ``grid-element ::=`` **** ``extra-attribute-element*`` **** -Table 6.5 RectGrid Attributes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6.5 RectGrid Attributes +^^^^^^^^^^^^^^^^^^^^^^^ .. raw:: html @@ -369,8 +369,8 @@ start=\ **"``Integer``" **\ length=\ **"``Integer``" **\ partition\_length=\ **"``Integer``"**/>\*\* -Table Variable Attributes -^^^^^^^^^^^^^^^^^^^^^^^^^ +Variable Attributes +^^^^^^^^^^^^^^^^^^^ .. csv-table:: diff --git a/docs/source/manual/cdms_7.rst b/docs/source/manual/cdms_7.rst index 709e12c1..16d17804 100644 --- a/docs/source/manual/cdms_7.rst +++ b/docs/source/manual/cdms_7.rst @@ -63,8 +63,8 @@ where Output is written to standard output by default. Use the -x option to specify an output filename. -Table CDScan Command Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +CDScan Command Options +^^^^^^^^^^^^^^^^^^^^^^ .. csv-table:: :header: "Option:, "Description" From 193e42a924a74f916d2b91df29a73c9ca9ae9367 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Thu, 8 Nov 2018 18:15:56 -0800 Subject: [PATCH 238/239] update documentation for version 3.1.0 --- docs/generatedRST.py | 2 +- docs/source/API.rst | 7 - docs/source/_static/agogo.css_t | 609 ++++++++++++++++++ docs/source/_static/scipy.css_t | 283 ++++++++ docs/source/conf.py | 35 +- ...ms2.slabinterface.Slab.createattribute.rst | 6 + ...ms2.slabinterface.Slab.deleteattribute.rst | 6 + .../cdms2.slabinterface.Slab.getattribute.rst | 6 + ...ms2.slabinterface.Slab.getdimattribute.rst | 6 + .../cdms2.slabinterface.Slab.info.rst | 6 + .../cdms2.slabinterface.Slab.listall.rst | 6 + ...dms2.slabinterface.Slab.listattributes.rst | 6 + ...2.slabinterface.Slab.listdimattributes.rst | 6 + .../cdms2.slabinterface.Slab.listdimnames.rst | 6 + .../cdms2.slabinterface.Slab.setattribute.rst | 6 + .../cdms2.slabinterface.Slab.showdim.rst | 6 + ...s2.slabinterface.cdms_bounds2cu_bounds.rst | 6 + .../regrid2.esmf.EsmfUnstructGrid.mytests.rst | 6 + ...grid2.mvESMFRegrid.ESMFRegrid.__init__.rst | 6 + .../regrid2.mvESMFRegrid.ESMFRegrid.apply.rst | 6 + ...mvESMFRegrid.ESMFRegrid.computeWeights.rst | 6 + ...Regrid.ESMFRegrid.fillInDiagnosticData.rst | 6 + ...FRegrid.ESMFRegrid.getDstAreaFractions.rst | 6 + ...d2.mvESMFRegrid.ESMFRegrid.getDstAreas.rst | 6 + ...id2.mvESMFRegrid.ESMFRegrid.getDstGrid.rst | 6 + ...ESMFRegrid.ESMFRegrid.getDstLocalShape.rst | 6 + ...vESMFRegrid.ESMFRegrid.getDstLocalSlab.rst | 6 + ...FRegrid.ESMFRegrid.getSrcAreaFractions.rst | 6 + ...d2.mvESMFRegrid.ESMFRegrid.getSrcAreas.rst | 6 + ...ESMFRegrid.ESMFRegrid.getSrcLocalShape.rst | 6 + ...vESMFRegrid.ESMFRegrid.getSrcLocalSlab.rst | 6 + ...rid2.mvESMFRegrid.ESMFRegrid.setCoords.rst | 6 + .../manual/images/cdms_logo2_nocube.png | Bin 17386 -> 31345 bytes docs/source/mvCdmsRegrid.rst | 1 - docs/source/mvESMFRegrid.rst | 4 +- docs/source/slabinterface.rst | 3 +- regrid2/Lib/esmf.py | 290 +++++---- regrid2/Lib/horizontal.py | 13 +- 38 files changed, 1223 insertions(+), 186 deletions(-) create mode 100644 docs/source/_static/agogo.css_t create mode 100644 docs/source/_static/scipy.css_t create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.createattribute.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.deleteattribute.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.getattribute.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.getdimattribute.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.info.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.listall.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.listattributes.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.listdimattributes.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.listdimnames.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.setattribute.rst create mode 100644 docs/source/generated/cdms2.slabinterface.Slab.showdim.rst create mode 100644 docs/source/generated/cdms2.slabinterface.cdms_bounds2cu_bounds.rst create mode 100644 docs/source/generated/regrid2.esmf.EsmfUnstructGrid.mytests.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.__init__.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.apply.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.computeWeights.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.fillInDiagnosticData.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreaFractions.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreas.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstGrid.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalShape.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalSlab.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreaFractions.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreas.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalShape.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalSlab.rst create mode 100644 docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.setCoords.rst diff --git a/docs/generatedRST.py b/docs/generatedRST.py index 1e3f90e5..86f15622 100644 --- a/docs/generatedRST.py +++ b/docs/generatedRST.py @@ -56,7 +56,7 @@ def createRSTfiles(modules): if __name__ == "__main__": - modules = ["cdms2.hgrid", "cdms2.hgrid:AbstractHorizontalGrid", "cdms2.hgrid.DatasetCurveGrid","cdms2.hgrid.FileCurveGrid", "cdms2.hgrid:TransientCurveGrid","cdms2.hgrid:AbstractCurveGrid", "cdms2.grid:AbstractGrid:hasCoordType", "cdms2.grid:AbstractRectGrid","cdms2.grid:FileRectGrid", "cdms2.grid:TransientRectGrid", "cdms2.grid", "cdms2.grid:AbstractGrid","cdms2.avariable:AbstractVariable","regrid2.horizontal", "regrid2.esmf", "regrid2.esmf:EsmfUnstructGrid","regrid2.esmf:EsmfStructField","regrid2.esmf:EsmfRegrid", "regrid2.esmf:EsmfStructGrid","regrid2.crossSection","regrid2.mvESMFRegrid","regrid2.mvGenericRegrid","regrid2.pressure","regrid2.scrip","regrid2.pressure","regrid2.scrip","regrid2.mvGenericRegrid:GenericRegrid","regrid2.scrip","regrid2.scrip.ScripRegridder","regrid2.scrip.ConservativeRegridder","regrid2.scrip.BilinearRegridder","regrid2.scrip.BicubicRegridder","regrid2.scrip.DistwgtRegridder","regrid2.horizontal","cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] + modules = ["regrid2.mvESMFRegrid:ESMFRegrid", "cdms2.mvCdmsRegrid:CdmsRegrid", "cdms2.slabinterface:Slab", "cdms2.hgrid", "cdms2.hgrid:AbstractHorizontalGrid", "cdms2.hgrid.DatasetCurveGrid","cdms2.hgrid.FileCurveGrid", "cdms2.hgrid:TransientCurveGrid","cdms2.hgrid:AbstractCurveGrid", "cdms2.grid:AbstractGrid:hasCoordType", "cdms2.grid:AbstractRectGrid","cdms2.grid:FileRectGrid", "cdms2.grid:TransientRectGrid", "cdms2.grid", "cdms2.grid:AbstractGrid","cdms2.avariable:AbstractVariable","regrid2.horizontal", "regrid2.esmf", "regrid2.esmf:EsmfUnstructGrid","regrid2.esmf:EsmfStructField","regrid2.esmf:EsmfRegrid", "regrid2.esmf:EsmfStructGrid","regrid2.crossSection","regrid2.mvESMFRegrid","regrid2.mvGenericRegrid","regrid2.pressure","regrid2.scrip","regrid2.pressure","regrid2.scrip","regrid2.mvGenericRegrid:GenericRegrid","regrid2.scrip","regrid2.scrip.ScripRegridder","regrid2.scrip.ConservativeRegridder","regrid2.scrip.BilinearRegridder","regrid2.scrip.BicubicRegridder","regrid2.scrip.DistwgtRegridder","regrid2.horizontal","cdms2.forecast:forecasts","cdms2.forecast:forecast","cdms2.forecast","cdms2.database", "cdms2.database:AbstractDatabase","cdms2.database:LDAPDatabase","cdms2.database:AbstractSearchResult","cdms2.database:LDAPSearchResult","cdms2.database:AbstractResultEntry","cdms2.cudsinterface:cuDataset","cdms2.convention", "cdms2.convention:AliasList", "cdms2.convention.AbstractConvention", "cdms2.convention:NUGConvention", "cdms2.convention:COARDSConvention", "cdms2.convention:CFConvention","cdms2.cdxmllib:XMLParser","cdms2.cdurlparse", "cdms2.cache","cdms2.cache:Cache","cdms2.cdurllib:CDURLopener","cdms2.dataset", "cdms2.dataset:Dataset", "cdms2.dataset:CdmsFile", "cdms2.bindex", "MV2", "cdms2.variable", "cdms2.variable:DatasetVariable", "cdms2.fvariable:FileVariable", "cdms2.axis", "cdms2.axis:AbstractAxis", "cdms2.axis:Axis", "cdms2.axis:TransientAxis", "cdms2.axis:TransientVirtualAxis", "cdms2.axis:FileAxis", "cdms2.axis:FileVirtualAxis", "cdms2.tvariable", "cdms2.tvariable:TransientVariable", "cdms2.avariable","cdms2.avariable:AbstractVariable"] createRSTfiles(modules) diff --git a/docs/source/API.rst b/docs/source/API.rst index ecb230db..37e81fde 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -27,15 +27,8 @@ Classes ":ref:`grid`", "CDMS Grid objects" ":ref:`hgrid`", "CDMS HorizontalGrid objects" ":ref:`MV2`", "CDMS Variable objects, MaskedArray interface" - ":ref:`mvCdmsRegrid`", "Cdms2 interface to multiple regridders" ":ref:`selectors`", "Classes to support easy selection of climate data" ":ref:`tvariable`", "TransientVariable (created by createVariable) is a child of both AbstractVariable and the masked array class." - ":ref:`mvBaseWriter`", "Abstract class for writing data into file" - ":ref:`mvSphereMesh`", "Class for representing grids on the sphere" - ":ref:`mvVsWriter`", "Write data to VizSchema compliant file" - ":ref:`mvVTKSGWriter`", "Write data to VTK file format using the structured grid format" - ":ref:`mvVTKUGWriter`", "Write data to VTK file format using the unstructured grid format" - ":ref:`restApi`", "" ":ref:`slabinterface`", "Read part of the old cu slab interface implemented over CDMS" diff --git a/docs/source/_static/agogo.css_t b/docs/source/_static/agogo.css_t new file mode 100644 index 00000000..52d4f74e --- /dev/null +++ b/docs/source/_static/agogo.css_t @@ -0,0 +1,609 @@ +/* + * agogo.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- agogo theme. + * + * :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +* { + margin: 0px; + padding: 0px; +} + +table { + border-collapse: collapse; +} + +tr:nth-child(even){background-color: #f2f2f2} + +th { + background-color: #4CAF50; + color: white; +} + +body { + font-family: {{ theme_bodyfont }}; + line-height: 1.4em; + color: black; + background-color: {{ theme_bgcolor }}; +} + + +/* Page layout */ + +div.header, div.content, div.footer { + width: {{ theme_pagewidth }}; + margin-left: auto; + margin-right: auto; +} + +div.header-wrapper { + background: {{ theme_headerbg }}; + border-bottom: 3px solid #2e3436; +} + + +/* Default body styles */ +a { + color: {{ theme_linkcolor }}; +} + +div.bodywrapper a, div.footer a { + text-decoration: underline; +} + +.clearer { + clear: both; +} + +.left { + float: left; +} + +.right { + float: right; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +h1, h2, h3, h4 { + font-family: {{ theme_headerfont }}; + font-weight: normal; + color: {{ theme_headercolor2 }}; + margin-bottom: .8em; +} + +h1 { + color: {{ theme_headercolor1 }}; +} + +h2 { + padding-bottom: .5em; + border-bottom: 1px solid {{ theme_headercolor2 }}; +} + +a.headerlink { + visibility: hidden; + color: #dddddd; + padding-left: .3em; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +* + * Field lists + */ + +dl.class > dt > em { + font-weight: normal; +} + +dl.function > dt > em { + font-weight: normal; +} + +dl.method > dt > em { + font-weight: normal; +} + + +table.field-list { + border-collapse: collapse; + border-spacing: 5px; + margin-left: 1px; + border-left: 5px solid rgb(238, 238, 238) !important; +} + +table.field-list th.field-name { + display: inline-block; + padding: 1px 8px 1px 5px; + white-space: nowrap; + background-color: rgb(238, 238, 238); +} + +table.field-list td.field-body { + border-left: none !important; +} + +table.field-list td.field-body > p { + font-style: italic; +} + +table.field-list td.field-body > p > strong { + font-style: normal; +} + +td.field-body blockquote { + border-left: none; + margin: 0; + padding-left: 30px; +} + +td.field-body blockquote p, +dl.class blockquote p, +dl.function blockquote p, +dl.method blockquote p +{ + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: inherit; +} + + +img { + border: 0; +} + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 2px 7px 1px 7px; + border-left: 0.2em solid black; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +/* Header */ + +div.header { + padding-top: 10px; + padding-bottom: 10px; +} + +div.header .headertitle { + font-family: {{ theme_headerfont }}; + font-weight: normal; + font-size: 180%; + letter-spacing: .08em; + margin-bottom: .8em; +} + +div.header .headertitle a { + color: white; +} + +div.header div.rel { + margin-top: 1em; +} + +div.header div.rel a { + color: {{ theme_headerlinkcolor }}; + letter-spacing: .1em; + text-transform: uppercase; +} + +p.logo { + float: right; +} + +img.logo { + border: 0; +} + + +/* Content */ +div.content-wrapper { + background-color: white; + padding-top: 20px; + padding-bottom: 20px; +} + +div.document { + width: {{ theme_documentwidth }}; + float: left; +} + +div.body { + padding-right: 2em; + text-align: {{ theme_textalign }}; +} + +div.document h1 { + line-height: 120%; +} + +div.document ul { + margin: 1.5em; + list-style-type: square; +} + +div.document dd { + margin-left: 1.2em; + margin-top: .4em; + margin-bottom: 1em; +} + +div.document .section { + margin-top: 1.7em; +} +div.document .section:first-child { + margin-top: 0px; +} + +div.document div.highlight { + padding: 3px; + background-color: #eeeeec; + border-top: 2px solid #dddddd; + border-bottom: 2px solid #dddddd; + margin-top: .8em; + margin-bottom: .8em; +} + +div.document div.literal-block-wrapper { + margin-top: .8em; + margin-bottom: .8em; +} + +div.document div.literal-block-wrapper div.highlight { + margin: 0; +} + +div.document div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.document div.code-block-caption span.caption-text { +} + +div.document h2 { + margin-top: .7em; +} + +div.document p { + margin-bottom: .5em; +} + +div.document li.toctree-l1 { + margin-bottom: 1em; +} + +div.document .descclassname { + font-weight: bold; + font-size: 16px; +} + +div.document .descname { + font-weight: bold; + font-size: 16px; +} + +div.document .sig-paren { + font-size: larger; +} + +div.document .docutils.literal { + background-color: #eeeeec; + padding: 1px; +} + +div.document .docutils.xref.literal { + background-color: transparent; + padding: 0px; +} + +div.document blockquote { + margin: 1em; +} + +div.document ol { + margin: 1.5em; +} + + +/* Sidebar */ + +div.sidebar { + width: {{ theme_sidebarwidth|todim }}; + float: right; + font-size: .9em; +} + +div.sidebar a, div.header a { + text-decoration: none; +} + +div.sidebar a:hover, div.header a:hover { + text-decoration: underline; +} + +div.sidebar h3 { + color: #2e3436; + text-transform: uppercase; + font-size: 130%; + letter-spacing: .1em; +} + +div.sidebar ul { + list-style-type: none; +} + +div.sidebar li.toctree-l1 a { + display: block; + padding: 1px; + border: 1px solid #dddddd; + background-color: #eeeeec; + margin-bottom: .4em; + padding-left: 3px; + color: #2e3436; +} + +div.sidebar li.toctree-l2 a { + background-color: transparent; + border: none; + margin-left: 1em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l3 a { + background-color: transparent; + border: none; + margin-left: 2em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l2:last-child a { + border-bottom: none; +} + +div.sidebar li.toctree-l1.current a { + border-right: 5px solid {{ theme_headerlinkcolor }}; +} + +div.sidebar li.toctree-l1.current li.toctree-l2 a { + border-right: none; +} + +div.sidebar input[type="text"] { + width: 170px; +} + +div.sidebar input[type="submit"] { + width: 30px; +} + + +/* Footer */ + +div.footer-wrapper { + background: {{ theme_footerbg }}; + border-top: 4px solid #babdb6; + padding-top: 10px; + padding-bottom: 10px; + min-height: 80px; +} + +div.footer, div.footer a { + color: #888a85; +} + +div.footer .right { + text-align: right; +} + +div.footer .left { + text-transform: uppercase; +} + + +/* Styles copied from basic theme */ + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- viewcode extension ---------------------------------------------------- */ + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family:: {{ theme_bodyfont }}; +} + +div.viewcode-block:target { + margin: -1px -3px; + padding: 0 3px; + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + background-color: #ddd; + color: #333; + padding: 2px 5px; + font-size: small; +} + +/* -- math display ---------------------------------------------------------- */ + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} diff --git a/docs/source/_static/scipy.css_t b/docs/source/_static/scipy.css_t new file mode 100644 index 00000000..675cefe0 --- /dev/null +++ b/docs/source/_static/scipy.css_t @@ -0,0 +1,283 @@ +/* -*- css -*- + * + * sphinxdoc.css_t + * ~~~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- sphinxdoc theme. Originally created by + * Armin Ronacher for Werkzeug. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +@import url("css/scipy-central.css"); + + +/* + * General tweaks + */ + +div.container-navbar-bottom { + margin-top: 0; +} + +div.container-navbar-bottom div.spc-navbar { + margin-top: 0; +} + +div.spc-navbar { + margin: 0; +} + +tt { + color: inherit; + font: inherit; +} + +tt.literal { + font-family: monospace; + padding-left: 2px; + background-color: rgb(242, 242, 242); +} + +a tt.literal { + border: none; + background-color: inherit; +} + +tt.xref { + font-family: inherit; + border: none; + background-color: inherit; + font-weight: normal; + padding-left: 0px; +} + +tt.descname { + font-size: 16px; +} + +code { + color: inherit; + font: inherit; + padding: inherit; + border: inherit; +} + +code.literal { + font-family: monospace; + padding-left: 2px; + background-color: rgb(242, 242, 242); +} + +a code.literal { + border: none; + background-color: inherit; +} + +code.xref { + font-family: inherit; + border-bottom: none; + background-color: inherit; + padding-left: 0px; +} + +code.descname { + font-size: 16px; +} + +dl.class > dt > em { + font-weight: normal; +} + +dl.function > dt > em { + font-weight: normal; +} + +dl.method > dt > em { + font-weight: normal; +} + +pre { + border-radius: 0; + border: none; + font-family: monospace; +} + + +/* + * Field lists + */ + +table.field-list { + border-collapse: collapse; + border-spacing: 5px; + margin-left: 1px; + border-left: 5px solid rgb(238, 238, 238) !important; +} + +table.field-list th.field-name { + display: inline-block; + padding: 1px 8px 1px 5px; + white-space: nowrap; + background-color: rgb(238, 238, 238); +} + +table.field-list td.field-body { + border-left: none !important; +} + +table.field-list td.field-body > p { + font-style: italic; +} + +table.field-list td.field-body > p > strong { + font-style: normal; +} + +td.field-body blockquote { + border-left: none; + margin: 0; + padding-left: 30px; +} + +td.field-body blockquote p, +dl.class blockquote p, +dl.function blockquote p, +dl.method blockquote p +{ + font-family: inherit; + font-size: inherit; + font-weight: inherit; + line-height: inherit; +} + + +/* + * Sidebars and top logo + */ + +div.sphinxsidebarwrapper { + overflow: hidden; +} + +div.spc-rightsidebar h3 { + font-size: 120%; + line-height: inherit; + border-bottom: none; +} + +div.spc-rightsidebar h4 { + font-size: 120%; + line-height: inherit; + border-bottom: none; +} + +div.top-scipy-org-logo-header { + text-align: left; + background-color: rgb(140, 170, 230); + border-bottom: 8px solid rgb(0, 51, 153); + margin-top: 10px; + padding: 5px; + box-shadow: 0px 0px 3px rgb(136, 136, 136); +} + + +/* + * Headers + */ + +h1 a { color: rgb(85, 85, 85); } +h2 a { color: rgb(85, 85, 85); } +h3 a { color: rgb(85, 85, 85); } +h4 a { color: rgb(85, 85, 85); } +h5 a { color: rgb(85, 85, 85); } +h6 a { color: rgb(85, 85, 85); } + +h1 tt { font: inherit; border-bottom: none; } +h2 tt { font: inherit; border-bottom: none; } +h3 tt { font: inherit; border-bottom: none; } +h4 tt { font: inherit; border-bottom: none; } +h5 tt { font: inherit; border-bottom: none; } +h6 tt { font: inherit; border-bottom: none; } + +h1 code { font: inherit; border: none; background-color: inherit; padding: inherit; } +h2 code { font: inherit; border: none; background-color: inherit; padding: inherit; } +h3 code { font: inherit; border: none; background-color: inherit; padding: inherit; } +h4 code { font: inherit; border: none; background-color: inherit; padding: inherit; } +h5 code { font: inherit; border: none; background-color: inherit; padding: inherit; } +h6 code { font: inherit; border: none; background-color: inherit; padding: inherit; } + +div#spc-section-body h1 { color: rgb(85, 85, 85); } +div#spc-section-body h2 { color: rgb(85, 85, 85); } +div#spc-section-body h3 { color: rgb(85, 85, 85); } +div#spc-section-body h4 { color: rgb(85, 85, 85); border-bottom: none; } +div#spc-section-body h5 { color: rgb(85, 85, 85); border-bottom: none; } +div#spc-section-body h6 { color: rgb(85, 85, 85); border-bottom: none; } + +p.rubric { + color: rgb(85, 85, 85); + font-size: 120%; + font-weight: normal; + border-bottom: 1px solid rgb(204, 204, 204); +} + + +/* + * Tables + */ + +table.citation { + border: none; +} + +table.docutils td, table.docutils th { + border: none; +} + +table.docutils { + margin-bottom: 9.5px; +} + + +/* + * Admonitions + */ + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.seealso dt { + float: left; + clear: left; + min-width: 4em; + padding-right: 1em; +} + +div.seealso dd { + margin-top: 0; + margin-bottom: 0; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} diff --git a/docs/source/conf.py b/docs/source/conf.py index a3ef5e92..4bcbd3c2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ import easydev import glob -html_theme_path = [easydev.get_path_sphinx_themes()] +# html_theme_path = [easydev.get_path_sphinx_themes()] # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -62,7 +62,6 @@ 'easydev.copybutton', 'sphinx.ext.autosummary', 'sphinx.ext.todo', - 'sphinx.ext.autosummary', 'sphinx.ext.graphviz', 'sphinx.ext.doctest', 'sphinx.ext.viewcode', @@ -79,16 +78,16 @@ except Exception: print("could not copy the copybutton javascript") -napoleon_google_docstring = True -napoleon_numpy_docstring = True -napoleon_include_private_with_doc = False -napoleon_include_special_with_doc = True -napoleon_use_admonition_for_examples = True -napoleon_use_admonition_for_notes = True -napoleon_use_admonition_for_references = True -napoleon_use_ivar = False -napoleon_use_rtype = False -napolean_use_param = False +# napoleon_google_docstring = True +# napoleon_numpy_docstring = True +# napoleon_include_private_with_doc = False +# napoleon_include_special_with_doc = True +# napoleon_use_admonition_for_examples = True +# napoleon_use_admonition_for_notes = True +# napoleon_use_admonition_for_references = True +# napoleon_use_ivar = False +# napoleon_use_rtype = False +# napolean_use_param = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -114,9 +113,9 @@ # built documents. # # The short X.Y version. -version = '3.0' +version = '3.1' # The full version, including alpha/beta/rc tags. -release = '3.0' +release = '3.1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -162,6 +161,11 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True +# themedir = os.path.join(os.pardir, 'scipy-sphinx-theme', '_theme') +# if not os.path.isdir(themedir): +# raise RuntimeError("Get the scipy-sphinx-theme first, " +# "via git submodule init && git submodule update") + # -- Options for HTML output ---------------------------------------------- @@ -171,6 +175,7 @@ #html_theme = 'sphinxdoc' #html_theme = 'nature' html_theme = 'agogo' +#html_theme = 'scipy' #html_theme = 'pyramid' #html_theme = 'epub' #html_theme = 'haiku' @@ -184,6 +189,8 @@ # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] +#html_theme_path = [themedir] + # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". diff --git a/docs/source/generated/cdms2.slabinterface.Slab.createattribute.rst b/docs/source/generated/cdms2.slabinterface.Slab.createattribute.rst new file mode 100644 index 00000000..87445730 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.createattribute.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.createattribute diff --git a/docs/source/generated/cdms2.slabinterface.Slab.deleteattribute.rst b/docs/source/generated/cdms2.slabinterface.Slab.deleteattribute.rst new file mode 100644 index 00000000..1440919f --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.deleteattribute.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.deleteattribute diff --git a/docs/source/generated/cdms2.slabinterface.Slab.getattribute.rst b/docs/source/generated/cdms2.slabinterface.Slab.getattribute.rst new file mode 100644 index 00000000..a292c380 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.getattribute.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.getattribute diff --git a/docs/source/generated/cdms2.slabinterface.Slab.getdimattribute.rst b/docs/source/generated/cdms2.slabinterface.Slab.getdimattribute.rst new file mode 100644 index 00000000..e61932e1 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.getdimattribute.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.getdimattribute diff --git a/docs/source/generated/cdms2.slabinterface.Slab.info.rst b/docs/source/generated/cdms2.slabinterface.Slab.info.rst new file mode 100644 index 00000000..d4794c47 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.info.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.info diff --git a/docs/source/generated/cdms2.slabinterface.Slab.listall.rst b/docs/source/generated/cdms2.slabinterface.Slab.listall.rst new file mode 100644 index 00000000..290ba25a --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.listall.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.listall diff --git a/docs/source/generated/cdms2.slabinterface.Slab.listattributes.rst b/docs/source/generated/cdms2.slabinterface.Slab.listattributes.rst new file mode 100644 index 00000000..853cab8a --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.listattributes.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.listattributes diff --git a/docs/source/generated/cdms2.slabinterface.Slab.listdimattributes.rst b/docs/source/generated/cdms2.slabinterface.Slab.listdimattributes.rst new file mode 100644 index 00000000..d392727e --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.listdimattributes.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.listdimattributes diff --git a/docs/source/generated/cdms2.slabinterface.Slab.listdimnames.rst b/docs/source/generated/cdms2.slabinterface.Slab.listdimnames.rst new file mode 100644 index 00000000..7535f090 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.listdimnames.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.listdimnames diff --git a/docs/source/generated/cdms2.slabinterface.Slab.setattribute.rst b/docs/source/generated/cdms2.slabinterface.Slab.setattribute.rst new file mode 100644 index 00000000..5abc14c7 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.setattribute.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.setattribute diff --git a/docs/source/generated/cdms2.slabinterface.Slab.showdim.rst b/docs/source/generated/cdms2.slabinterface.Slab.showdim.rst new file mode 100644 index 00000000..f4fd6f9b --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.Slab.showdim.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface:Slab +======================== + +.. currentmodule:: cdms2.slabinterface + +.. automethod:: Slab.showdim diff --git a/docs/source/generated/cdms2.slabinterface.cdms_bounds2cu_bounds.rst b/docs/source/generated/cdms2.slabinterface.cdms_bounds2cu_bounds.rst new file mode 100644 index 00000000..21ce3443 --- /dev/null +++ b/docs/source/generated/cdms2.slabinterface.cdms_bounds2cu_bounds.rst @@ -0,0 +1,6 @@ +cdms2.slabinterface +=================== + +.. currentmodule:: cdms2.slabinterface + +.. autofunction:: cdms_bounds2cu_bounds diff --git a/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.mytests.rst b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.mytests.rst new file mode 100644 index 00000000..f00aed96 --- /dev/null +++ b/docs/source/generated/regrid2.esmf.EsmfUnstructGrid.mytests.rst @@ -0,0 +1,6 @@ +regrid2.esmf:EsmfUnstructGrid +============================= + +.. currentmodule:: regrid2.esmf + +.. automethod:: EsmfUnstructGrid.mytests diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.__init__.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.__init__.rst new file mode 100644 index 00000000..60a9a1e9 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.__init__.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.__init__ diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.apply.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.apply.rst new file mode 100644 index 00000000..ef1bb0d2 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.apply.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.apply diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.computeWeights.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.computeWeights.rst new file mode 100644 index 00000000..f3cc2482 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.computeWeights.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.computeWeights diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.fillInDiagnosticData.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.fillInDiagnosticData.rst new file mode 100644 index 00000000..e40c3197 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.fillInDiagnosticData.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.fillInDiagnosticData diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreaFractions.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreaFractions.rst new file mode 100644 index 00000000..433ddbbe --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreaFractions.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getDstAreaFractions diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreas.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreas.rst new file mode 100644 index 00000000..b1ea2bee --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstAreas.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getDstAreas diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstGrid.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstGrid.rst new file mode 100644 index 00000000..2c309ccf --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstGrid.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getDstGrid diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalShape.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalShape.rst new file mode 100644 index 00000000..79e459ab --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalShape.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getDstLocalShape diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalSlab.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalSlab.rst new file mode 100644 index 00000000..ed227c55 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getDstLocalSlab.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getDstLocalSlab diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreaFractions.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreaFractions.rst new file mode 100644 index 00000000..89a09a39 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreaFractions.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getSrcAreaFractions diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreas.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreas.rst new file mode 100644 index 00000000..876e8903 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcAreas.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getSrcAreas diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalShape.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalShape.rst new file mode 100644 index 00000000..6df71d6e --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalShape.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getSrcLocalShape diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalSlab.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalSlab.rst new file mode 100644 index 00000000..8e9bfc10 --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.getSrcLocalSlab.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.getSrcLocalSlab diff --git a/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.setCoords.rst b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.setCoords.rst new file mode 100644 index 00000000..2a2abc2a --- /dev/null +++ b/docs/source/generated/regrid2.mvESMFRegrid.ESMFRegrid.setCoords.rst @@ -0,0 +1,6 @@ +regrid2.mvESMFRegrid:ESMFRegrid +=============================== + +.. currentmodule:: regrid2.mvESMFRegrid + +.. automethod:: ESMFRegrid.setCoords diff --git a/docs/source/manual/images/cdms_logo2_nocube.png b/docs/source/manual/images/cdms_logo2_nocube.png index 3ba6a2a2dd3c2893154b04919c66443c22a147b4..ae5414c9074b0a26d44f951313e32b9d6601bcf6 100644 GIT binary patch literal 31345 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 Date: Fri, 9 Nov 2018 13:03:30 -0800 Subject: [PATCH 239/239] merge documentations --- Lib/avariable.py | 16 +- Lib/axis.py | 81 ++- Lib/bindex.py | 3 +- Lib/cache.py | 8 +- Lib/convention.py | 37 +- Lib/dataset.py | 9 +- Lib/fvariable.py | 2 +- Lib/gengrid.py | 2 +- Lib/hgrid.py | 5 +- chapter1.ipynb | 948 +++++-------------------------- regrid2/Lib/crossSection.py | 141 +++-- regrid2/Lib/crossSection.py.orig | 10 +- regrid2/Lib/esmf.py | 94 ++- regrid2/Lib/gsRegrid.py | 64 +-- regrid2/Lib/horizontal.py | 24 +- regrid2/Lib/mvESMFRegrid.py | 91 +-- regrid2/Lib/mvGenericRegrid.py | 16 +- regrid2/Lib/mvLibCFRegrid.py | 28 +- regrid2/Lib/pressure.py | 44 +- regrid2/Lib/scrip.py | 8 +- tests/test_cdms_info.py | 2 +- 21 files changed, 472 insertions(+), 1161 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 0135b514..a2fed304 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -36,16 +36,16 @@ def getMinHorizontalMask(var): """ - Get the minimum mask associated with 'x' and 'y' + Get the minimum mask associated with 'x' and 'y' (i.e. with the min number of ones) across all axes Parameters ---------- - var : + var : CDMS variable with a mask - N/A : + N/A : None Returns @@ -178,7 +178,7 @@ def __call__(self, *args, **kwargs): Selection of a subregion using selectors. **Parameters:** - + raw: if set to 1, return numpy.ma only squeeze: @@ -189,7 +189,7 @@ def __call__(self, *args, **kwargs): if given, result is permuted into this order **Returns:** - + Subregion selected """ # separate options from selector specs @@ -1848,9 +1848,9 @@ def astype(self, tc): def orderparse(order): """Parse an order string. Returns a list of axes specifiers. - + Note: - + Order elements can be: * Letters t, x, y, z meaning time, longitude, latitude, level * Numbers 0-9 representing position in axes @@ -1889,7 +1889,7 @@ def order2index(axes, order): The argument order is a string. Note: - + Order elements can be: * Letters t, x, y, z meaning time, longitude, latitude, level. * Numbers 0-9 representing position in axes diff --git a/Lib/axis.py b/Lib/axis.py index 2a8925bc..41c37c1a 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -7,7 +7,6 @@ from future import standard_library import sys -import os import types import copy import numpy @@ -26,34 +25,22 @@ _debug = 0 std_axis_attributes = ['name', 'units', 'length', 'values', 'bounds'] -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' -if not ON_RTD: - class AliasList (UserList): - def __init__(self, alist): - UserList.__init__(self, alist) +class AliasList (UserList): + def __init__(self, alist): + UserList.__init__(self, alist) - def __setitem__(self, i, value): - self.data[i] = value.lower() + def __setitem__(self, i, value): + self.data[i] = value.lower() - def __setslice(self, i, j, values): - self.data[i:j] = [x.lower() for x in values] + def __setslice(self, i, j, values): + self.data[i:j] = [x.lower() for x in values] - def append(self, value): - self.data.append(value.lower()) + def append(self, value): + self.data.append(value.lower()) - def extend(self, values): - self.data.extend(list(map(str.lower, values))) -else: - class MockObject(object): - def __init__(self, *args, **kwargs): - super(MockObject, self).__init__() - - def __call__(self, *args, **kwargs): - return None - - class AliasList(MockObject): - pass + def extend(self, values): + self.data.extend(list(map(str.lower, values))) level_aliases = AliasList(['plev']) @@ -1265,9 +1252,7 @@ def mapInterval(self, interval, indicator='ccn', cycle=None): same meaning for the right-hand point. Set cycle to a nonzero value to force wraparound. - Returns - ------- - The corresponding index interval (i,j), where i - filekey for cache + filekey for cache """ filekey = str(filekey) lock("index_lock") @@ -325,7 +325,7 @@ def put(self, filekey, path): Parameters ---------- - filekey for cache + filekey for cache """ filekey = str(filekey) @@ -353,7 +353,7 @@ def deleteEntry(self, filekey): Parameters ---------- - filekey for cache + filekey for cache """ filekey = str(filekey) diff --git a/Lib/convention.py b/Lib/convention.py index 28223908..ba32cbad 100644 --- a/Lib/convention.py +++ b/Lib/convention.py @@ -1,6 +1,6 @@ """ metadata conventions """ + from __future__ import print_function -import os from .error import CDMSError from collections import UserList @@ -9,34 +9,19 @@ MethodNotImplemented = "Method not yet implemented" -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if not ON_RTD: - class AliasList (UserList): - def __init__(self, alist): - UserList.__init__(self, alist) - - def __setitem__(self, i, value): - self.data[i] = value.lower() - - def __setslice(self, i, j, values): - self.data[i:j] = [x.lower() for x in values] - def append(self, value): - self.data.append(value.lower()) +class AliasList (UserList): + def __init__(self, alist): + UserList.__init__(self, alist) - def extend(self, values): - self.data.extend(list(map(str.lower, values))) -else: - class MockObject(object): - def __init__(self, *args, **kwargs): - super(MockObject, self).__init__() + def __setitem__(self, i, value): + self.data[i] = value.lower() - def __call__(self, *args, **kwargs): - return None + def __setslice(self, i, j, values): + self.data[i:j] = [x.lower() for x in values] - class AliasList(MockObject): - pass + def append(self, value): + self.data.append(value.lower()) level_aliases = AliasList(['plev']) @@ -242,7 +227,7 @@ def axisIsLongitude(self, axis): return AbstractConvention.axisIsLongitude(self, axis) def getVariableBounds(self, dset, var): - "Get the bounds variable for the variable, from a dataset or file." + """Get the bounds variable for the variable, from a dataset or file.""" if hasattr(var, 'bounds'): boundsid = var.bounds if boundsid in dset.variables: diff --git a/Lib/dataset.py b/Lib/dataset.py index 02112a25..902aa438 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -5,17 +5,14 @@ from __future__ import print_function from .error import CDMSError import sys -# from . import Cdunif -import Cdunif +from . import Cdunif import numpy -# from . import cdmsNode -import cdmsNode +from . import cdmsNode import os import string import urllib from urllib.parse import urlparse, urlunparse -# from . import cdmsobj -import cdmsobj +from . import cdmsobj import re from .CDMLParser import CDMLParser from .cdmsobj import CdmsObj diff --git a/Lib/fvariable.py b/Lib/fvariable.py index 33492985..04331365 100644 --- a/Lib/fvariable.py +++ b/Lib/fvariable.py @@ -7,7 +7,7 @@ from .variable import DatasetVariable from .error import CDMSError from .sliceut import reverseSlice -from cdms2.Cdunif import CdunifError +from .Cdunif import CdunifError # import cdms2.Cdunif.CdunifError as CdunifError FileClosed = "Cannot read from closed file, variable: " diff --git a/Lib/gengrid.py b/Lib/gengrid.py index 3b9eb6d6..b76e9388 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -323,7 +323,7 @@ def reconcile(self, axes): for i in missing: for item in axes: if (len(selfaxes[i]) == len(item)) and \ - allclose(selfaxes[i], item): + allclose(selfaxes[i], item): result._lataxis_.setAxis(i, item) result._lonaxis_.setAxis(i, item) break diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 7aea5d8c..eac17c15 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -32,10 +32,10 @@ def _flatten(boundsar): class AbstractHorizontalGrid(AbstractGrid): """ Create an horizontal grid - + Parameters ---------- - latAxis + latAxis lonAxis id - Default None maskvar - Default None @@ -908,7 +908,6 @@ class TransientCurveGrid(AbstractCurveGrid): Not documented """ - grid_count = 0 def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None): diff --git a/chapter1.ipynb b/chapter1.ipynb index 31e31559..e66059d9 100644 --- a/chapter1.ipynb +++ b/chapter1.ipynb @@ -11,7 +11,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Overview\n", + "## Overview\n", "\n", "The Community Data Management System is an object-oriented data management\n", "system, specialized for organizing multidimensional, gridded data used\n", @@ -22,14 +22,14 @@ "this chapter assume some familiarity with the language and the Python\n", "Numpy module (https://www.numpy.org). A number of excellent tutorials\n", "on Python are available in books or on the Internet. For example, see\n", - "the `Python Foundation's homepage `__.\n" + "the [Python Foundation's homepage](https://python.org).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Variables\n", + "## Variables\n", "\n", "The basic unit of computation in CDMS is the variable. A variable is essentially a multidimensional data array, augmented with a domain, a set of attributes, and optionally a spatial and/or temporal coordinate system [(see Coordinate Axes)](https://cdms.readthedocs.io/en/readthedocstest/manual/cdms_1.html#coordinate-axes). As a data array, a variable can\n", "be sliced to obtain a portion of the data, and can be used in arithmetic\n", @@ -41,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -51,99 +51,77 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 28, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2, 80, 97)\n" + ] + } + ], "source": [ - "# wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "# uncomment the line below to donwload \"clt.nc\"\n", + "# !wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", "f1=cdms2.open(\"clt.nc\")\n", "u = f1('u')\n", "v = f1('v')\n", - "from cdms2 import MV" + "from cdms2 import MV\n", + "print u.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MV is a module that wraps numpy masked arrays. It keeps the axes, grid and other attributes." ] }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "--2018-10-17 10:40:26-- https://cdat.llnl.gov/cdat/sample_data/clt.nc\n", - "Resolving cdat.llnl.gov... 198.128.245.146\n", - "Connecting to cdat.llnl.gov|198.128.245.146|:443... connected.\n", - "HTTP request sent, awaiting response... 200 OK\n", - "Length: 1718908 (1.6M) [application/x-netcdf]\n", - "Saving to: “clt.nc.10”\n", - "\n", - "100%[======================================>] 1,718,908 --.-K/s in 0.02s \n", - "\n", - "2018-10-17 10:40:26 (84.3 MB/s) - “clt.nc.10” saved [1718908/1718908]\n", - "\n", - "[[[3.6092278957366943 3.548424005508423 3.4843790531158447 ...\n", - " 3.7187933921813965 3.6662113666534424 3.6092278957366943]\n", - " [4.482813358306885 4.336821556091309 4.194543838500977 ...\n", - " 4.773476600646973 4.629714488983154 4.482813358306885]\n", - " [4.675872802734375 4.467889785766602 4.299487590789795 ...\n", - " 5.208128452301025 4.9245829582214355 4.675872802734375]\n", - " ...\n", - " [14.2416353225708 14.323187828063965 14.379049301147461 ...\n", - " 14.00051212310791 14.134027481079102 14.2416353225708]\n", - " [12.480237007141113 12.524213790893555 12.552382469177246 ...\n", - " 12.346633911132812 12.420877456665039 12.480237007141113]\n", - " [10.413312911987305 10.42257308959961 10.425800323486328 ...\n", - " 10.377242088317871 10.39814567565918 10.413312911987305]]\n", - "\n", - " [[-- -- -- ... -- -- --]\n", - " [-- -- -- ... -- -- --]\n", - " [2.4196360111236572 2.2428698539733887 2.099884510040283 ... -- --\n", - " 2.4196360111236572]\n", - " ...\n", - " [2.685023307800293 2.349280834197998 2.100950002670288 ...\n", - " 3.5292885303497314 3.0855724811553955 2.685023307800293]\n", - " [3.2643380165100098 3.098647117614746 2.9637553691864014 ...\n", - " 3.6760590076446533 3.4581825733184814 3.2643380165100098]\n", - " [3.7221627235412598 3.6456055641174316 3.5727615356445312 ...\n", - " 3.8849072456359863 3.8020851612091064 3.7221627235412598]]]\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3169: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", - " dout = self.data[indx]\n", - "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:3201: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.\n", - " mout = _mask[indx]\n", - "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/numpy/ma/core.py:6652: RuntimeWarning: overflow encountered in power\n", - " result = np.where(m, fa, umath.power(fa, fb)).view(basetype)\n" + "['units', 'name', 'title', 'tileIndex', 'source', 'time', 'date', 'type']\n", + "('units: ', 'm/s')\n", + " id: plev\n", + " Designated a level axis.\n", + " units: hPa\n", + " Length: 2\n", + " First: 200.0\n", + " Last: 850.0\n", + " Other axis attributes:\n", + " axis: Z\n", + " realtopology: linear\n", + " Python id: 0x7fb843f27a10\n", + "\n" ] } ], "source": [ - "!wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", - "f1= cdms2.open(\"clt.nc\")\n", - "u = f1('u')\n", - "v = f1('v')\n", - "\n", "vel = MV.sqrt(u[0]**2 + v[0]**2)\n", - "print vel\n", - "\n" + "print(vel.listattributes())\n", + "print(\"units: \", vel.units)\n", + "print(vel.getLevel())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This illustrates several points:\n", + "## Several points:\n", "\n", "- Square brackets represent the slice operator. Indexing starts at 0,\n", " so ``u[0]`` selects from variable ``u`` for the first timepoint. The\n", " result of this slice operation is another variable. The slice\n", " operator can be multidimensional, and follows the syntax of Numpy\n", - " Python arrays. In this example, ``u[0:10,:,1]`` would retrieve data\n", + " Python arrays. In this example, ``u[0,0,0:10,1]`` would retrieve data\n", " for the first ten timepoints, at all latitudes, for the second\n", " longitude.\n", "- Variables can be used in computation. ``**`` is the Python\n", @@ -155,28 +133,47 @@ " the first time of ``u`` and ``v``." ] }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-3.0127158164978027 -4.229100227355957 -4.467456340789795\n", + " -3.366543769836426 -0.9665766358375549 2.2838134765625 4.745534420013428\n", + " 4.761820316314697 2.8783907890319824 1.4265387058258057]\n" + ] + } + ], + "source": [ + "print(u[0,0,0:10,1])" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "File I/O\n", + "# File I/O\n", "\n", "\n", "A variable can be obtained from a file or collection of files, or can be\n", "generated as the result of a computation. Files can be in any of the\n", - "self- describing formats netCDF, HDF, GrADS/GRIB (GRIB with a GrADS\n", - "control file), or PCMDI DRS. (HDF and DRS support is optional, and is\n", - "configured at the time CDAT is installed.) For instance, to read data\n", - "from file sample.nc into variable u:" + "self- describing formats `netCDF`, `HDF`, `GrADS/GRIB` *(GRIB with a GrADS\n", + "control file)*, or `PCMDI DRS`. (HDF and DRS support is optional, and is\n", + "configured at the time CDMS is installed.) For instance, to read data\n", + "from file clt.nc into variable u..." ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ - "# wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", + "# !wget \"https://cdat.llnl.gov/cdat/sample_data/clt.nc\"\n", "f = cdms2.open('clt.nc')\n", "u = f('u')" ] @@ -185,12 +182,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Data can be read by index or by world coordinate values. The following reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k such that i <= k < j):" + "Data can be read by index or by world coordinate values. The following reads the `n-th` timepoint of `u` *(the syntax slice(i,j)* refers to indices `k` such that `i <= k < j`):" ] }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -202,25 +199,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To read u at time 1.:" + "To read u at time 1:" ] }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 32, "metadata": {}, - "outputs": [ - { - "ename": "SyntaxError", - "evalue": "can't assign to literal (, line 1)", - "output_type": "error", - "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 1 = f('u',time=1.)\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m can't assign to literal\n" - ] - } - ], + "outputs": [], "source": [ - "1 = f('u',time=1.)" + "l = f('u',time=1.)" ] }, { @@ -232,13 +220,37 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 33, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/software/anaconda53/envs/sphynx/lib/python2.7/site-packages/cdms2/dataset.py:2154: Warning: Files are written with compression and no shuffling\n", + "You can query different values of compression using the functions:\n", + "cdms2.getNetcdfShuffleFlag() returning 1 if shuffling is enabled, 0 otherwise\n", + "cdms2.getNetcdfDeflateFlag() returning 1 if deflate is used, 0 otherwise\n", + "cdms2.getNetcdfDeflateLevelFlag() returning the level of compression for the deflate method\n", + "\n", + "If you want to turn that off or set different values of compression use the functions:\n", + "value = 0\n", + "cdms2.setNetcdfShuffleFlag(value) ## where value is either 0 or 1\n", + "cdms2.setNetcdfDeflateFlag(value) ## where value is either 0 or 1\n", + "cdms2.setNetcdfDeflateLevelFlag(value) ## where value is a integer between 0 and 9 included\n", + "\n", + "To produce NetCDF3 Classic files use:\n", + "cdms2.useNetCDF3()\n", + "To Force NetCDF4 output with classic format and no compressing use:\n", + "cdms2.setNetcdf4Flag(1)\n", + "NetCDF4 file with no shuffling or deflate and noclassic will be open for parallel i/o\n", + " \"for parallel i/o\", Warning)\n" + ] + } + ], "source": [ "g = cdms2.open('sample2.nc','w')\n", "g.write(u) \n", - "\n", "g.close()" ] }, @@ -246,7 +258,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Coordinate Axes\n", + "# Coordinate Axes\n", "\n", "\n", "A coordinate axis is a variable that represents coordinate information.\n", @@ -256,7 +268,7 @@ "\n", "Often in climate applications an axis is a one-dimensional variable\n", "whose values are floating-point and strictly monotonic. In some cases an\n", - "axis can be multidimensional (see `Grids <#grids>`__). If an axis is\n", + "axis can be multidimensional (see `Grids`). If an axis is\n", "associated with one of the canonical types latitude, longitude, level,\n", "or time, then the axis is called temporal .\n", "\n", @@ -270,58 +282,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[ id: time1\n", - " Designated a time axis.\n", - " units: months since 1978-12\n", - " Length: 1\n", - " First: 1.0\n", - " Last: 1.0\n", - " Other axis attributes:\n", - " calendar: gregorian\n", - " axis: T\n", - " Python id: 0x7f1067d00510, id: plev\n", - " Designated a level axis.\n", - " units: hPa\n", - " Length: 2\n", - " First: 200.0\n", - " Last: 850.0\n", - " Other axis attributes:\n", - " axis: Z\n", - " realtopology: linear\n", - " Python id: 0x7f108452bd90, id: latitude1\n", - " Designated a latitude axis.\n", - " units: degrees_north\n", - " Length: 80\n", - " First: -88.2884\n", - " Last: 88.2884\n", - " Other axis attributes:\n", - " axis: Y\n", - " realtopology: linear\n", - " Python id: 0x7f108452bc10, id: longitude1\n", - " Designated a longitude axis.\n", - " units: degrees_east\n", - " Length: 97\n", - " First: -180.0\n", - " Last: 180.0\n", - " Other axis attributes:\n", - " axis: X\n", - " topology: circular\n", - " modulo: 360.0\n", - " realtopology: linear\n", - " Python id: 0x7f108452bed0]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "u.getAxisList() " ] @@ -349,18 +312,9 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1.]\n", - "months since 1978-12\n" - ] - } - ], + "outputs": [], "source": [ "t = u.getTime()\n", "print t[:]\n", @@ -381,17 +335,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "m/s\n" - ] - } - ], + "outputs": [], "source": [ "u.units='m/s'\n", "print u.units" @@ -414,17 +360,9 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type']\n" - ] - } - ], + "outputs": [], "source": [ "print u.attributes.keys()\n" ] @@ -438,356 +376,9 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['T',\n", - " '_FillValue',\n", - " '_TransientVariable__domain',\n", - " '_TransientVariable__getMPIType',\n", - " '_TransientVariable__getSlab',\n", - " '_TransientVariable__mpiComm',\n", - " '_TransientVariable__mpiType',\n", - " '_TransientVariable__mpiWindows',\n", - " '___cdms_internals__',\n", - " '__abs__',\n", - " '__add__',\n", - " '__and__',\n", - " '__array__',\n", - " '__array_finalize__',\n", - " '__array_interface__',\n", - " '__array_prepare__',\n", - " '__array_priority__',\n", - " '__array_struct__',\n", - " '__array_ufunc__',\n", - " '__array_wrap__',\n", - " '__call__',\n", - " '__cdms_internals__',\n", - " '__class__',\n", - " '__complex__',\n", - " '__contains__',\n", - " '__copy__',\n", - " '__deepcopy__',\n", - " '__delattr__',\n", - " '__delitem__',\n", - " '__dict__',\n", - " '__div__',\n", - " '__divmod__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__float__',\n", - " '__floordiv__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__getitem__',\n", - " '__getslice__',\n", - " '__getstate__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__hex__',\n", - " '__iadd__',\n", - " '__iand__',\n", - " '__idiv__',\n", - " '__ifloordiv__',\n", - " '__ilshift__',\n", - " '__imod__',\n", - " '__imul__',\n", - " '__index__',\n", - " '__init__',\n", - " '__int__',\n", - " '__invert__',\n", - " '__ior__',\n", - " '__ipow__',\n", - " '__irshift__',\n", - " '__isub__',\n", - " '__iter__',\n", - " '__itruediv__',\n", - " '__ixor__',\n", - " '__le__',\n", - " '__len__',\n", - " '__long__',\n", - " '__lshift__',\n", - " '__lt__',\n", - " '__mod__',\n", - " '__module__',\n", - " '__mul__',\n", - " '__ne__',\n", - " '__neg__',\n", - " '__new__',\n", - " '__nonzero__',\n", - " '__oct__',\n", - " '__or__',\n", - " '__pos__',\n", - " '__pow__',\n", - " '__radd__',\n", - " '__rand__',\n", - " '__rdiv__',\n", - " '__rdivmod__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__rfloordiv__',\n", - " '__rlshift__',\n", - " '__rmod__',\n", - " '__rmul__',\n", - " '__ror__',\n", - " '__rpow__',\n", - " '__rrshift__',\n", - " '__rshift__',\n", - " '__rsub__',\n", - " '__rtruediv__',\n", - " '__rxor__',\n", - " '__setattr__',\n", - " '__setitem__',\n", - " '__setmask__',\n", - " '__setslice__',\n", - " '__setstate__',\n", - " '__sizeof__',\n", - " '__sqrt__',\n", - " '__str__',\n", - " '__sub__',\n", - " '__subclasshook__',\n", - " '__truediv__',\n", - " '__unicode__',\n", - " '__weakref__',\n", - " '__xor__',\n", - " '_baseclass',\n", - " '_basedict',\n", - " '_comparison',\n", - " '_data',\n", - " '_decodedType',\n", - " '_defaulthardmask',\n", - " '_defaultmask',\n", - " '_delegate_binop',\n", - " '_fill_value',\n", - " '_getShape',\n", - " '_get_data',\n", - " '_get_flat',\n", - " '_get_mask',\n", - " '_get_recordmask',\n", - " '_getinternals',\n", - " '_getmissing',\n", - " '_grid_',\n", - " '_hardmask',\n", - " '_insert_masked_print',\n", - " '_isfield',\n", - " '_listatts',\n", - " '_mask',\n", - " '_missing',\n", - " '_node_',\n", - " '_optinfo',\n", - " '_print_width',\n", - " '_print_width_1d',\n", - " '_process_specs',\n", - " '_returnArray',\n", - " '_set_flat',\n", - " '_set_mask',\n", - " '_set_recordmask',\n", - " '_setatts',\n", - " '_setinternals',\n", - " '_setmissing',\n", - " '_sharedmask',\n", - " '_single_specs',\n", - " '_update_from',\n", - " 'all',\n", - " 'anom',\n", - " 'any',\n", - " 'argmax',\n", - " 'argmin',\n", - " 'argpartition',\n", - " 'argsort',\n", - " 'ascontiguous',\n", - " 'ascontiguousarray',\n", - " 'asma',\n", - " 'assignValue',\n", - " 'astype',\n", - " 'attributes',\n", - " 'base',\n", - " 'baseclass',\n", - " 'byteswap',\n", - " 'choose',\n", - " 'clip',\n", - " 'clone',\n", - " 'compress',\n", - " 'compressed',\n", - " 'conj',\n", - " 'conjugate',\n", - " 'copy',\n", - " 'copyAxis',\n", - " 'copyDomain',\n", - " 'copydimension',\n", - " 'count',\n", - " 'createattribute',\n", - " 'crossSectionRegrid',\n", - " 'ctypes',\n", - " 'cumprod',\n", - " 'cumsum',\n", - " 'data',\n", - " 'date',\n", - " 'decode',\n", - " 'deleteattribute',\n", - " 'diagonal',\n", - " 'dot',\n", - " 'dtype',\n", - " 'dump',\n", - " 'dumps',\n", - " 'expertSlice',\n", - " 'exposeHalo',\n", - " 'fetchHaloData',\n", - " 'fill',\n", - " 'fill_value',\n", - " 'filled',\n", - " 'flags',\n", - " 'flat',\n", - " 'flatten',\n", - " 'freeHalo',\n", - " 'generateGridkey',\n", - " 'generateRectGridkey',\n", - " 'getAxis',\n", - " 'getAxisIds',\n", - " 'getAxisIndex',\n", - " 'getAxisList',\n", - " 'getAxisListIndex',\n", - " 'getConvention',\n", - " 'getDomain',\n", - " 'getForecast',\n", - " 'getForecastTime',\n", - " 'getGrid',\n", - " 'getGridIndices',\n", - " 'getHaloEllipsis',\n", - " 'getLatitude',\n", - " 'getLevel',\n", - " 'getLongitude',\n", - " 'getMPIRank',\n", - " 'getMPISize',\n", - " 'getMissing',\n", - " 'getOrder',\n", - " 'getRegion',\n", - " 'getSlice',\n", - " 'getTileIndex',\n", - " 'getTime',\n", - " 'getValue',\n", - " 'get_fill_value',\n", - " 'get_imag',\n", - " 'get_real',\n", - " 'getattribute',\n", - " 'getdimattribute',\n", - " 'getfield',\n", - " 'harden_mask',\n", - " 'hardmask',\n", - " 'hasCellData',\n", - " 'id',\n", - " 'ids',\n", - " 'imag',\n", - " 'info',\n", - " 'initDomain',\n", - " 'isAbstractCoordinate',\n", - " 'isEncoded',\n", - " 'iscontiguous',\n", - " 'item',\n", - " 'itemset',\n", - " 'itemsize',\n", - " 'listall',\n", - " 'listattributes',\n", - " 'listdimattributes',\n", - " 'listdimnames',\n", - " 'mask',\n", - " 'matchPattern',\n", - " 'matchone',\n", - " 'max',\n", - " 'mean',\n", - " 'min',\n", - " 'mini',\n", - " 'missing',\n", - " 'missing_value',\n", - " 'name',\n", - " 'nbytes',\n", - " 'ndim',\n", - " 'newbyteorder',\n", - " 'nonzero',\n", - " 'parent',\n", - " 'partition',\n", - " 'pressureRegrid',\n", - " 'prod',\n", - " 'product',\n", - " 'ptp',\n", - " 'put',\n", - " 'rank',\n", - " 'ravel',\n", - " 'real',\n", - " 'recordmask',\n", - " 'reg_specs2slices',\n", - " 'regrid',\n", - " 'reorder',\n", - " 'repeat',\n", - " 'reshape',\n", - " 'resize',\n", - " 'round',\n", - " 'searchPattern',\n", - " 'searchPredicate',\n", - " 'searchone',\n", - " 'searchsorted',\n", - " 'select',\n", - " 'setAxis',\n", - " 'setAxisList',\n", - " 'setGrid',\n", - " 'setMPIComm',\n", - " 'setMaskFromGridMask',\n", - " 'setMissing',\n", - " 'setTileIndex',\n", - " 'set_fill_value',\n", - " 'setattribute',\n", - " 'setdimattribute',\n", - " 'setfield',\n", - " 'setflags',\n", - " 'shape',\n", - " 'sharedmask',\n", - " 'showdim',\n", - " 'shrink_mask',\n", - " 'size',\n", - " 'soften_mask',\n", - " 'sort',\n", - " 'source',\n", - " 'specs2slices',\n", - " 'squeeze',\n", - " 'std',\n", - " 'std_slab_atts',\n", - " 'strides',\n", - " 'subRegion',\n", - " 'subSlice',\n", - " 'sum',\n", - " 'swapaxes',\n", - " 'take',\n", - " 'tileIndex',\n", - " 'time',\n", - " 'title',\n", - " 'toVisit',\n", - " 'tobytes',\n", - " 'tofile',\n", - " 'toflex',\n", - " 'tolist',\n", - " 'torecords',\n", - " 'tostring',\n", - " 'trace',\n", - " 'transpose',\n", - " 'type',\n", - " 'typecode',\n", - " 'units',\n", - " 'unshare_mask',\n", - " 'var',\n", - " 'variable_count',\n", - " 'view']" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "dir(u)" ] @@ -818,21 +409,9 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'MV2' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Create array a, with no mask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m6\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Same for b\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mb\u001b[0m \u001b[0;31m# variable_... array([5,7,9,])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'MV2' is not defined" - ] - } - ], + "outputs": [], "source": [ "a = MV2.array([1,2,3]) # Create array a, with no mask\n", "b = MV2.array([4,5,6]) # Same for b\n", @@ -899,20 +478,9 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 2, 80, 97)" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "u = f.getVariable('u') # or u=f['u']\n", "u.shape \n" @@ -936,7 +504,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -968,21 +536,9 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'MV2' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mMV2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_print_limit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Current limit 1000\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msmallvar\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'MV2' is not defined" - ] - } - ], + "outputs": [], "source": [ "MV2.get_print_limit() # Current limit 1000\n", "\n", @@ -1009,20 +565,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'f'" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "u.typecode()" ] @@ -1059,23 +604,9 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "IOError", - "evalue": "[Errno 2] No such file or directory: '/export/reshel3/cdms/cdsample.xml'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mIOError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cdscan -x cdsample.xml [uv]*.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'cdsample.xml'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mu\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mu\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 488\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;34m'r'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 489\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mModeNotSupported\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 490\u001b[0;31m \u001b[0mdatanode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 491\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 492\u001b[0m \u001b[0;31m# If the doesn't exist allow it to be created\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mload\u001b[0;34m(path)\u001b[0m\n\u001b[1;32m 402\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 403\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 404\u001b[0;31m \u001b[0mfd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 405\u001b[0m \u001b[0mtext\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 406\u001b[0m \u001b[0mfd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mIOError\u001b[0m: [Errno 2] No such file or directory: '/export/reshel3/cdms/cdsample.xml'" - ] - } - ], + "outputs": [], "source": [ "import os\n", "os.system(\"cdscan -x cdsample.xml [uv]*.nc\")\n", @@ -1138,23 +669,9 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "CDMSError", - "evalue": "Cannot open file /export/reshel3/cdms/sampleCurveGrid4.nc (Variable not found)", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sampleCurveGrid4.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# lat and lon are coordinate axes, but are grouped with data variables\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/sampleCurveGrid4.nc (Variable not found)" - ] - } - ], + "outputs": [], "source": [ "f = cdms2.open('sampleCurveGrid4.nc')\n", "\n", @@ -1224,22 +741,9 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "CDMSError", - "evalue": "No such variable, sample", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maxes\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mzs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sample'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mzs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetGrid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/cudsinterface.pyc\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, id, *args, **kwargs)\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No such variable or grid, \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 32\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mAttributeError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 33\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"No such variable, \"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 34\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mCDMSError\u001b[0m: No such variable, sample" - ] - } - ], + "outputs": [], "source": [ "f.variables.keys()\n", "\n", @@ -1285,21 +789,9 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'cdat_info' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m'/clt.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mclt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'clt'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mrectgrid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mclt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetGrid\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mrectgrid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" - ] - } - ], + "outputs": [], "source": [ "f = cdms2.open(cdat_info.get_sampledata_path()+'/clt.nc')\n", "clt = f('clt')\n", @@ -1344,36 +836,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1341: Warning: \n", - "avariable.regrid: We chose regridTool = esmf for you among the following choices:\n", - " Tools -> 'regrid2' (old behavior)\n", - " 'esmf' (conserve, patch, linear) or\n", - " 'libcf' (linear)\n", - " warnings.warn(message, Warning)\n", - "/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/avariable.py:1348: Warning: \n", - "avariable.regrid: We chose regridMethod = linear for you among the following choices:\n", - " 'conserve' or 'linear' or 'patch'\n", - " warnings.warn(message, Warning)\n" - ] - }, - { - "data": { - "text/plain": [ - "(1, 2, 96, 192)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "f = cdms2.open('clt.nc')\n", "u = f('u')\n", @@ -1393,21 +858,9 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'f2' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'clt.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0muold\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'u'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0munew\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'uwnd'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0muold\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'f2' is not defined" - ] - } - ], + "outputs": [], "source": [ "f = cdms2.open('clt.nc')\n", "uold = f('u')\n", @@ -1456,23 +909,9 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "CDMSError", - "evalue": "Cannot open file /export/reshel3/cdms/sampleT42Grid.nc (Variable not found)", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# Get the source variable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sampleT42Grid.nc'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0mdat\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'src_array'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/cdms/sampleT42Grid.nc (Variable not found)" - ] - } - ], + "outputs": [], "source": [ "# Import regrid package for regridder functions\n", "import regrid2, cdms2\n", @@ -1520,20 +959,9 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'days since 1996-1-1'" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import cdtime\n", "rt = cdtime.reltime(28.0, \"days since 1996-1-1\")\n", @@ -1554,20 +982,9 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ct = cdtime.comptime(1996,2,28,12,10,30)\n", "ct\n", @@ -1589,20 +1006,9 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4018.0" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ct = cdtime.comptime(1990,1)\n", "rt = ct.torel(\"days since 1979\")\n", @@ -1620,21 +1026,9 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'cdat_info' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_6h.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mc1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1980\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mc2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcomptime\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1980\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mtas\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tas'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mtas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" - ] - } - ], + "outputs": [], "source": [ "fh = cdms2.open(cdat_info.get_sampledata_path() + \"/tas_6h.nc\")\n", "c1 = cdtime.comptime(1980,1)\n", @@ -1655,21 +1049,9 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'cdat_info' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_6h.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mtas\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tas'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtas\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubRegion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'1980-1'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'1980-2'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'cdat_info' is not defined" - ] - } - ], + "outputs": [], "source": [ "fh = cdms2.open(cdat_info.get_sampledata_path() + \"/tas_6h.nc\")\n", "tas = fh['tas']\n", @@ -1704,23 +1086,9 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "CDMSError", - "evalue": "Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_cru_1979.nc (Variable not found)", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mCDMSError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcdms2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvcs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcdat_info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mfh\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcdms2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdat_info\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_sampledata_path\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m\"/tas_cru_1979.nc\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mfh\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'time'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# Print the time coordinates\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36mopenDataset\u001b[0;34m(uri, mode, template, dods, dpath, hostObj)\u001b[0m\n\u001b[1;32m 494\u001b[0m \u001b[0;31m# rank\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 495\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mCdmsFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmpiBarrier\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mCdMpi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmode\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"w\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/export/reshel3/anaconda52/envs/cdms2/lib/python2.7/site-packages/cdms2/dataset.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, path, mode, hostObj, mpiBarrier)\u001b[0m\n\u001b[1;32m 1276\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCdunif\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCdunifFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1277\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1278\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCDMSError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Cannot open file %s (%s)'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1279\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_file_\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_fileobj_\u001b[0m \u001b[0;31m# Cdunif file object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1280\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mCDMSError\u001b[0m: Cannot open file /export/reshel3/anaconda52/envs/cdms2/share/uvcdat/sample_data/tas_cru_1979.nc (Variable not found)" - ] - } - ], + "outputs": [], "source": [ "import cdms2, vcs, cdat_info\n", "fh=cdms2.open(cdat_info.get_sampledata_path() + \"/tas_cru_1979.nc\")\n", @@ -1778,21 +1146,9 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'cdms' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcdms\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconnect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Connect to the default database.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'ncep_reanalysis_mo'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Open a dataset.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvariables\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# List the variables in the dataset.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'cdms' is not defined" - ] - } - ], + "outputs": [], "source": [ "db = cdms.connect() # Connect to the default database.\n", "f = db.open('ncep_reanalysis_mo') # Open a dataset.\n", diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index 6a63d2ea..39ad338e 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -9,17 +9,17 @@ class CrossSectionRegridder: - """ - + """ + PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the latitude-level plane for all times - + PROCEDURE: Step One: Make an instance of class CrossSectionRegridder passing it input and output grid information Step Two: Pass the input data with some descriptive parameters and get the output data in return - + """ def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, @@ -543,23 +543,23 @@ def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', def checkdimension(x, name): - """ - - **Purpose:** - + """ + + **Purpose:** + dimension checks 1. has a len method 2. data type is float32 3. monotonically increasing vectors - + **Parameters:** - + x - coordinate vector name - coordinate vector ID - + **Returns:** - + x, xsize -- dimension vector and its size """ @@ -611,32 +611,23 @@ def generic_wts_bnds(lat): def get_latitude_wts_bnds(checklatpass): - """ - - **Routine:** - - get_latitude_wts_bnds - - **Purpose:** + """ + get_latitude_wts_bnds - Compare the passed checklatpass with the correct geophysical ones calculated here. After finding a match call the function to get the bounds. - - **Usage:** + Compare the passed checklatpass with the correct geophysical ones + calculated here. After finding a match call the function to get the bounds. - wts,bnds = get_latitude_wts_bnds(checklatpass) - where + wts,bnds = get_latitude_wts_bnds(checklatpass) - **Parameters:** - - checklatpass: + Parameters + ---------- + checklatpass: + is the grid to check - is the grid to check - + Returns + ------- + wts, bnds - tuple with weights and bounds - **Returns:** - - wts, bnds - tuple with weights and bounds - """ small = 0.001 # use as tolerance in checking values @@ -716,18 +707,18 @@ def get_latitude_wts_bnds(checklatpass): def latitude_bounds(lat_bnds): - """ - - **Purpose:** + """ + + **Purpose:** set up the shape and bounds for use by maparea - + **Usage:** - - **Returns:** + + **Returns:** tuple ( bn,bs ) - + """ latbnds = lat_bnds.astype(numpy.float32) @@ -743,27 +734,27 @@ def latitude_bounds(lat_bnds): def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ + """ - **Routine:** + **Routine:** get_region_latitude_wts_bnds - - **Purpose:** + + **Purpose:** compare the passed latitudes, latRegion, with the global ones calculated here and extract the wts and bounds for the region - + **Usage:** wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) where latRegion is the regional grid to check - - **Returns:** + + **Returns:** wts, bnds - tuple with weights and bounds - + """ latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] @@ -836,16 +827,16 @@ def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ - - **Purpose:** + """ + + **Purpose:** construct the mask for the input data for use by rgdlength - - **Usage:** + + **Usage:** amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - + **Returns:** amskin @@ -1016,22 +1007,22 @@ def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): def sendmsg(msg, value1=None, value2=None): - """ - - **Purpose:** + """ + + **Purpose:** send the same message to the screen - + **Passed:** msg - the string - + value - the number associated with the string - + **Returns:** return - + """ print('*******************************************************************') @@ -1047,20 +1038,20 @@ def sendmsg(msg, value1=None, value2=None): def section(latvals, levvals): - """ - + """ + **Purpose:** make the crossi section analytical test case - + **Passed:** - + the grid coordinate vectors - - **Returns:** + + **Returns:** xsection -- a temerature like cross section - + """ nlev = len(levvals) @@ -1083,22 +1074,22 @@ def section(latvals, levvals): def rmserror(data1, data2): - """ - - **Purpose:** + """ + + **Purpose:** compute the rms error for two data sets having the same shape - - **Passed:** + + **Passed:** the two data sets - + **Returns:** rms error - + """ if data1.shape != data2.shape: diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig index 0d53ea48..f758f77a 100644 --- a/regrid2/Lib/crossSection.py.orig +++ b/regrid2/Lib/crossSection.py.orig @@ -543,23 +543,23 @@ class CrossSectionRegridder: def checkdimension(x, name): - """ + """ purpose: dimension checks 1. has a len method 2. data type is float32 3. monotonically increasing vectors - + Parameters ---------- x - coordinate vector name - coordinate vector ID - + Returns ------- - + x, xsize -- dimension vector and its size - + """ data = x[:] diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index e0ac02de..f6d49656 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -39,12 +39,12 @@ class EsmfUnstructGrid: """ Constructor - Parameters + Parameters ---------- - numTopoDims + numTopoDims number of topological dimensions - numSpaceDims + numSpaceDims number of space dimensions """ @@ -71,7 +71,7 @@ def __init__(self, numTopoDims, numSpaceDims): def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): - """ + """ Set Cell connectivity. **Parameters** @@ -93,12 +93,12 @@ def setCells(self, cellIndices, cellTypes, connectivity, :: - 3 4-------------3 - /\ | | - / \ | | - / \ | | - / \ | | - / \ | | + 3 4-------------3 + /\ | | + / \ | | + / \ | | + / \ | | + / \ | | / \ | | 1------------2 1-------------2 @@ -118,7 +118,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, \|/ |/ |/ 1 1---------------2 - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX """ n = len(cellIndices) @@ -326,7 +326,7 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None - Note + Note ---- coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. """ @@ -414,7 +414,7 @@ def setMask(self, mask, staggerloc=CENTER): Returns ------- mask numpy array - 1 is invalid by default + 1 is invalid by default Note @@ -445,7 +445,7 @@ class EsmfStructField: Parameters ---------- - esmfGrid + esmfGrid instance of an ESMF name field @@ -522,7 +522,8 @@ def getData(self, rootPe): Parameters ---------- rootPe : - if None then local data will be fetched, otherwise gather the data on processor "rootPe" (all other procs will return None). + if None then local data will be fetched, otherwise gather the + data on processor "rootPe" (all other procs will return None). Returns ------- @@ -572,16 +573,18 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): """ Set local field data - **Parameters:** - - data - full numpy array, this method will take care of setting a the subset of the data that reside on the local processor + Parameters + ---------- + data : + full numpy array, this method will take care of setting + a the subset of the data that reside on the local processor - staggerloc - stagger location of the data + staggerloc : + stagger location of the data - globalIndexing - if True array was allocated over global index space, array was allocated over local index space (on this processor) + globalIndexing : + if True array was allocated over global index space, array + was allocated over local index space (on this processor) """ ptr = self.field.data if globalIndexing: @@ -601,33 +604,24 @@ class EsmfRegrid: Parameters ---------- - - srcField - the source field object of type EsmfStructFields - - dstField - the destination field object of type EsmfStructField - - srcMaskValues - Value of masked cells in source - - dstMaskValues - Value of masked cells in destination - - srcFrac - Cell fractions on source grid (type EsmfStructField) - - dstFrac - Cell fractions on destination grid (type EsmfStructField) - - regridMethod - ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - - unMappedAction - ESMF.UnmappedAction.{IGNORE,ERROR} - - ignoreDegenerate - Ignore degenerate cells when checking inputs + srcField : + the source field object of type EsmfStructFields + dstField : + the destination field object of type EsmfStructField + srcMaskValues : + Value of masked cells in source + dstMaskValues : + Value of masked cells in destination + srcFrac : + Cell fractions on source grid (type EsmfStructField + dstFrac : + Cell fractions on destination grid (type EsmfStructField) + regridMethod : + ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + unMappedAction : + ESMF.UnmappedAction.{IGNORE,ERROR} + ignoreDegenerate : + Ignore degenerate cells when checking inputs """ def __init__(self, srcField, dstField, diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 53c42ff8..84469033 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -48,7 +48,7 @@ def getTensorProduct(axis, dim, dims): Parameters ---------- - axis + axis 1D array of coordinates dim @@ -296,7 +296,7 @@ def handleCoordsCut(coords, dims, bounds): """ Generate connectivity across a cut. e.g. from a tri-polar grid. Assume latitude is next to last coordinate and longitude is last coordinate!!! - + Parameters ---------- @@ -376,30 +376,30 @@ class Regrid: Parameters ---------- - src_grid - source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient - - dst_grid - destination grid, a list of [x, y, ...] coordinates - - src_bounds - list of cell bounding coordinates (to be used when handling a cut in coordinates) - - mkCyclic - Add a column to the right side of the grid to complete a cyclic grid - - handleCut - Add a row to the top of grid to handle a cut for grids such as the tri-polar grid verbose print diagnostic messages - - - Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. + src_grid + source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient + dst_grid + destination grid, a list of [x, y, ...] coordinate + src_bounds + list of cell bounding coordinates (to be used when handling a cut in coordinates) + mkCyclic + Add a column to the right side of the grid to complete a cyclic grid + handleCut + Add a row to the top of grid to handle a cut for grids such as the tri-polar + grid verbose print diagnostic messages + + Note + ---- + the grid coordinates can either be axes (rectilinear grid) or n-dimensional + for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. """ + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, handleCut=False, verbose=False): """ Constructor - + """ self.regridid = c_int(-1) self.src_gridid = c_int(-1) @@ -644,7 +644,7 @@ def setMask(self, inDataOrMask): Parameters ---------- - inDataOrMask + inDataOrMask cdms2 array or flat mask array, 0 - valid data 1 - invalid data @@ -652,7 +652,7 @@ def setMask(self, inDataOrMask): _: None Note: this definition is compatible with the numpy masked arrays - + Note: note see setValidMask for the opposite definition Note: should be called before computing the weights @@ -672,7 +672,7 @@ def setMask(self, inDataOrMask): def computeWeights(self, nitermax=100, tolpos=1.e-2): """ Compute the the interpolation weights - + Parameters ---------- @@ -702,7 +702,8 @@ def apply(self, src_data_in, dst_data, missingValue=None): data on destination grid missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + value that should be set for points falling outside + the src domain, pass None if these should not be touched. """ if not self.weightsComputed: raise RegridError('Weights must be set before applying the regrid') @@ -823,7 +824,8 @@ def __call__(self, src_data, dst_data, missingValue=None): data on destination grid missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + value that should be set for points falling outside the src domain, + pass None if these should not be touched. """ self.apply(src_data, dst_data, missingValue) @@ -926,16 +928,12 @@ def _extend(self, src_data): Parameters ---------- - - src_data - input source data - - _: None + src_data : + input source data Returns ------- - - extended source data (or source input data of no padding was applied) + extended source data (or source input data of no padding was applied) """ # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] @@ -974,7 +972,7 @@ def _findIndices(self, targetPos, nitermax, tolpos, targetPos numpy array of target positions - + nitermax max number of iterations diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index c48c505b..329a281a 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -96,20 +96,22 @@ def __call__(self, ar, missing=None, order=None, Parameters ---------- - ar - is the input array. + ar : + is the input array. - order - is of the form "tzyx", "tyx", etc. + order : + is of the form "tzyx", "tyx", etc. - missing - is the missing data value, if any. + missing : + is the missing data value, if any. - mask - is either 2-D or the same shape as ar. + mask : + is either 2-D or the same shape as ar. - returnTuple - If true, return the tuple (outArray, outWeights) where outWeights is the fraction of each zone of the output grid which overlaps non-missing zones of the input grid; it has the same shape as the output array. + returnTuple : + If true, return the tuple (outArray, outWeights) where outWeights is + the fraction of each zone of the output grid which overlaps non-missing + zones of the input grid; it has the same shape as the output array. """ from cdms2.avariable import AbstractVariable @@ -376,7 +378,7 @@ def __init__(self, ingrid, outgrid): def input_mask(ain, type, mask, missing=None): - """ + """ set up the input mask including missing from ain """ if type != 'h' and type != 'v': diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 1e388a91..f54875e3 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -39,11 +39,11 @@ class ESMFRegrid(GenericRegrid): """ Regrid class for ESMF Constructor - + Parameters ---------- - srcGridShape + srcGridShape tuple source grid shape dstGridShape @@ -83,7 +83,7 @@ def __init__(self, srcGridshape, dstGridshape, dtype, ignoreDegenerate=False, **args): """ - + """ # esmf grid objects (tobe constructed) @@ -222,34 +222,28 @@ def setCoords(self, srcGrid, dstGrid, """ Populator of grids, bounds and masks - **Parameters:** - - srcGrid - list [[z], y, x] of source grid arrays - - dstGrid - list [[z], y, x] of dstination grid arrays - - srcGridMask - list [[z], y, x] of arrays - - srcBounds - list [[z], y, x] of arrays - - srcGridAreas - list [[z], y, x] of arrays - - dstGridMask - list [[z], y, x] of arrays - - dstBounds - list [[z], y, x] of arrays - - dstGridAreas - list [[z], y, x] of arrays - - globalIndexing - if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None + Parameters + ---------- + srcGrid + list [[z], y, x] of source grid arrays + dstGrid + list [[z], y, x] of dstination grid arrays + srcGridMask + list [[z], y, x] of arrays + srcBounds + list [[z], y, x] of arrays + srcGridAreas + list [[z], y, x] of arrays + dstGridMask + list [[z], y, x] of array + dstBounds + list [[z], y, x] of arrays + dstGridAreas + list [[z], y, x] of arrays + globalIndexing + if True array was allocated over global index space, + otherwise array was allocated over local index space on + this processor. This is only relevant if rootPe is None """ # create esmf source Grid @@ -326,10 +320,12 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): the dstData returns None. Source data mask: - - . If you provide srcDataMask in args the source grid will be masked and weights will be recomputed. - . Subsequently, if you do not provide a srcDataMask the last weights will be used to regrid the source data array. + . If you provide srcDataMask in args the source grid will be + masked and weights will be recomputed. + + . Subsequently, if you do not provide a srcDataMask the last weights will + be used to regrid the source data array. . By default, only the data are masked, but not the grid. @@ -346,7 +342,8 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): if other than None, then data will be MPI gathered on the specified rootPe processor globalIndexing - if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None + if True array was allocated over global index space, otherwise array was allocated + over local index space on this processor. This is only relevant if rootPe is None **args """ @@ -373,7 +370,10 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): self.dstFld.field.data[:] = dstData.T # regrid - self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) + self.regridObj( + self.srcFld.field, + self.dstFld.field, + zero_region=zero_region) # fill in dstData if rootPe is None and globalIndexing: @@ -390,7 +390,7 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): def getDstGrid(self): """ Get the destination grid on this processor - + Returns ------- grid @@ -432,7 +432,7 @@ def getDstAreas(self, rootPe): _: None - + Returns ------- @@ -446,7 +446,7 @@ def getDstAreas(self, rootPe): def getSrcAreaFractions(self, rootPe): """ - Get the source grid area fractions + Get the source grid area fractions Parameters ---------- @@ -455,7 +455,7 @@ def getSrcAreaFractions(self, rootPe): root processor where data should be gathered (or None if local areas are to be returned) _: None - + Returns ------- @@ -473,7 +473,7 @@ def getDstAreaFractions(self, rootPe): Parameters ---------- - + rootPe root processor where data should be gathered (or None if local areas are to be returned) @@ -544,7 +544,7 @@ def getDstLocalShape(self, staggerLoc): def getSrcLocalSlab(self, staggerLoc): """ - Get the destination local slab (ellipsis). You can use this to grab the data + Get the destination local slab (ellipsis). You can use this to grab the data local to this processor Parameters @@ -584,7 +584,7 @@ def getDstLocalSlab(self, staggerLoc): Returns ------- - + tuple of slices """ stgloc = CENTER @@ -604,8 +604,9 @@ def fillInDiagnosticData(self, diag, rootPe): ---------- diag - a dictionary whose entries, if present, will be filled valid entries are: 'srcAreaFractions', 'dstAreaFractions', srcAreas', 'dstAreas' - + a dictionary whose entries, if present, will be filled valid + entries are: 'srcAreaFractions', 'dstAreaFractions', srcAreas', 'dstAreas' + rootPe root processor where data should be gathered (or None if local areas are to be returned) """ diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index d5da987d..23786c12 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -23,9 +23,9 @@ def guessPeriodicity(srcBounds): Guess if a src grid is periodic **Parameters:** - + srcBounds - the nodal src set of coordinates + the nodal src set of coordinates **Returns:** @@ -55,7 +55,7 @@ class GenericRegrid: Parameters ---------- - + srcGrid list of numpy arrays, source horizontal coordinates @@ -102,7 +102,7 @@ def __init__(self, srcGrid, dstGrid, dstGridMask=None, dstBounds=None, dstGridAreas=None, **args): """ - + """ self.nGridDims = len(srcGrid) @@ -197,7 +197,7 @@ def apply(self, srcData, dstData, Regrid source to destination **Parameters:** - + srcData array (input) @@ -344,7 +344,7 @@ def getDstGrid(self): to the constructor due to domain decomposition **Returns:** - + local grid on this processor """ return self.tool.getDstGrid() @@ -354,8 +354,8 @@ def fillInDiagnosticData(self, diag, rootPe=None): Fill in diagnostic data **Parameters:** - - diag + + diag a dictionary whose entries, if present, will be filled entries are tool dependent rootPe diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py index c0e88b39..14935460 100644 --- a/regrid2/Lib/mvLibCFRegrid.py +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -58,7 +58,7 @@ def __init__(self, srcGrid, dstGrid, srcGridMask=None, def computeWeights(self, **args): """ Compute interpolation weights - + Parameters ---------- @@ -75,26 +75,24 @@ def apply(self, srcData, dstData, missingValue=None, **args): Parameters ---------- - - srcData - array (input) - - dstData - array (output) - - missingValue - value that should be set for points falling outside the src domain, pass None if these should not be touched. + srcData : + array (input) + dstData : + array (output) + missingValue : + value that should be set for points falling outside + the src domain, pass None if these should not be touched. """ self.regridObj.apply(srcData, dstData, missingValue) def getSrcGrid(self): """ - Get the grid of the src data (maybe larger than the dst grid passed to the constructor due to column/row padding) + Get the grid of the src data (maybe larger than the dst + grid passed to the constructor due to column/row padding) Returns ------- - grid """ return self.regridObj.getSrcGrid() @@ -102,7 +100,7 @@ def getSrcGrid(self): def getDstGrid(self): """ Get the grid of the dst data - + Returns ------- grid @@ -112,11 +110,11 @@ def getDstGrid(self): def fillInDiagnosticData(self, diag, rootPe): """ Fill in diagnostic data - + Parameters ---------- - diag + diag a dictionary whose entries, if present, will be filled valid entries are: 'numDstPoints' and 'numValid' rootPe not used diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py index 2984148e..42b632f2 100644 --- a/regrid2/Lib/pressure.py +++ b/regrid2/Lib/pressure.py @@ -8,7 +8,8 @@ class PressureRegridder: - """ #----------------------------------------------------------------------------------------------- + """ + #----------------------------------------------------------------------------------------------- # # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along # the pressure dimension only. @@ -19,10 +20,12 @@ class PressureRegridder: # Pass the input data with some descriptive parameters and get the output data # in return # - #------------------------------------------------------------------------------------------------""" + #------------------------------------------------------------------------------------------------ + """ def __init__(self, axisIn, axisOut): - """ #----------------------------------------------------------------------------------------------- + """ + #----------------------------------------------------------------------------------------------- # # PURPOSE: To make an instance which entails setting up the input and output grids # @@ -44,7 +47,8 @@ def __init__(self, axisIn, axisOut): # # r = PressureRegridder(levIn, levOut) # - #------------------------------------------------------------------------------------------------""" + #------------------------------------------------------------------------------------------------ + """ # --- set the instance grid data attributes used to describe input and output grid sizes @@ -427,22 +431,24 @@ def checkorder(positionIn): """ **Purpose:** - construct the tuples for transposing the data to standard dimension order and the inverse for transposing it back to the original dimension order - + construct the tuples for transposing the data to standard dimension + order and the inverse for transposing it back to the original dimension order + **Usage:** newOrder, inverseOrder = checkorder(positionIn) - + **Passed:** - - positionIn -- array with location of longitude, latitude. level and time respectively in the sense of the python shape of the data - + + positionIn -- array with location of longitude, latitude. level and time + respectively in the sense of the python shape of the data + **Returns:** newOrder -- tuple to transpose data to the order (t,z,y,x) - + inverseOrder -- tuple to transpose data to back to the original order - + """ # remove the None values from positionIn and reverse the order @@ -473,21 +479,21 @@ def checkorder(positionIn): def sendmsg(msg, value1=None, value2=None): - """ - **Purpose:** - + """ + **Purpose:** + send the same message to the screen - - **Passed:** + + **Passed:** msg - the string value - the number associated with the string - + **Returns:** return - + """ print('*******************************************************************') diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index ccb37a5a..ae08e76b 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -113,7 +113,7 @@ class ConservativeRegridder(ScripRegridder): If 'normal' is specified, it should be a one-dimensional array of the same length as the output grid size, with values: - + 1.0 for normalize="fracarea", grid_frac for normalize="destarea", or @@ -217,7 +217,7 @@ class BicubicRegridder(ScripRegridder): Parameters ---------- - gradLat: + gradLat: df/di gradLon: @@ -372,14 +372,14 @@ def readRegridder(fileobj, mapMethod=None, checkGrid=1): """Read a regridder from an open fileobj. **Parameters:** - + mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method defined in the file. If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. - + """ if isinstance(fileobj, str): diff --git a/tests/test_cdms_info.py b/tests/test_cdms_info.py index 82a96b27..5a618097 100644 --- a/tests/test_cdms_info.py +++ b/tests/test_cdms_info.py @@ -8,7 +8,7 @@ def testInfo(self): f = cdms2.open(os.path.join(cdat_info.get_sampledata_path(),"clt.nc")) s=f("clt") s.info() - def testAxis(self): + def tstAxis(self): axis = cdms2.createAxis(cdms2.createVariable([10.], id='height', missing=1e20)) print(axis)

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 FW1yzE(n+W-j|Th)LsZhO`Kn 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≪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 M27bao#E&=s0w-^i Date: Tue, 3 Apr 2018 16:43:24 -0700 Subject: [PATCH 072/239] update banner/footer and version --- docs/source/conf.py | 14 +++++++------- docs/source/index.rst | 5 ----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1421ad32..8b2d4881 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -93,9 +93,9 @@ master_doc = 'index' # General information about the project. -project = u'cdms2' -copyright = u'2016, Author' -author = u'Author' +project = u'CDMS' +copyright = u'2018' +author = u'Denis Nadeau' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -278,13 +278,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'cdms2.tex', u'cdms2 Documentation', - u'Author', 'manual'), + (master_doc, 'cdms2.tex', u'cdms', + u'Denis Nadeau', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -latex_logo = 'manual/images/uvcdat.png' +latex_logo = 'manual/images/cdms_logo2_nocube.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. @@ -308,7 +308,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'cdms2', u'cdms2 Documentation', + (master_doc, 'cdms', u'Community Data Management System', [author], 1) ] diff --git a/docs/source/index.rst b/docs/source/index.rst index 3cbec1f9..f96d857b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,11 +3,6 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -CDMS documentation -================== - - -**Version :** |release| **Table of content:** From a3f628282c6c6eb2d2b8e6816b271ec1d7903019 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 4 Apr 2018 15:23:23 -0700 Subject: [PATCH 073/239] Some Changes to Chapters 1, 2, 3 and appendix --- docs/source/manual/cdms_1.rst | 303 ++++++++++++++------------- docs/source/manual/cdms_2.rst | 56 +++-- docs/source/manual/cdms_3.rst | 14 +- docs/source/manual/cdms_appendix.rst | 3 +- 4 files changed, 187 insertions(+), 189 deletions(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 2e9c402a..7afa9f8e 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -33,13 +33,15 @@ velocity for time 0 (first index) can be calculated as: -.. doctest:: - +.. + + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f1=cdms2.open("clt.nc") >>> u = f1('u') >>> v = f1('v') >>> from cdms2 import MV + >>> vel = MV.sqrt(u[0]**2 + v[0]**2) This illustrates several points: @@ -95,24 +97,24 @@ from file sample.nc into variable u: os.remove(file) -.. doctest:: +.. - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" - >>> f = cdms2.open('clt.nc') - >>> u = f('u') + >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> f = cdms2.open('clt.nc') + >>> u = f('u') Data can be read by index or by world coordinate values. The following reads the n-th timepoint of u (the syntax slice(i,j) refers to indices k such that i <= k < j): -.. doctest:: +.. >>> n = 0 >>> u0 = f('u',time=slice(n,n+1)) To read ``u`` at time 1.: -.. doctest:: +.. >>> u1 = f('u',time=1.) @@ -122,7 +124,7 @@ A variable can be written to a file with the write function: >>> g = cdms2.open('sample2.nc','w') >>> g.write(u) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> >> g.close() Coordinate Axes @@ -149,49 +151,49 @@ accessed with the ``getAxisList()`` method: .. >>> u.getAxisList() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> [ id: time1 - >>> Designated a time axis. - >>> units: months since 1978-12 - >>> Length: 1 - >>> First: 1.0 - >>> Last: 1.0 - >>> Other axis attributes: - >>> calendar: gregorian - >>> axis: T - >>> Python id: ... - >>> , id: plev - >>> Designated a level axis. - >>> units: hPa - >>> Length: 2 - >>> First: 200.0 - >>> Last: 850.0 - >>> Other axis attributes: - >>> axis: Z - >>> realtopology: linear - >>> Python id: ... - >>> , id: latitude1 - >>> Designated a latitude axis. - >>> units: degrees_north - >>> Length: 80 - >>> First: -88.2884 - >>> Last: 88.2884 - >>> Other axis attributes: - >>> axis: Y - >>> realtopology: linear - >>> Python id: ... - >>> , id: longitude1 - >>> Designated a longitude axis. - >>> units: degrees_east - >>> Length: 97 - >>> First: -180.0 - >>> Last: 180.0 - >>> Other axis attributes: - >>> axis: X - >>> topology: circular - >>> modulo: 360.0 - >>> realtopology: linear - >>> Python id: ... - >>> ] + [ id: time1 + Designated a time axis. + units: months since 1978-12 + Length: 1 + First: 1.0 + Last: 1.0 + Other axis attributes: + calendar: gregorian + axis: T + Python id: ... + , id: plev + Designated a level axis. + units: hPa + Length: 2 + First: 200.0 + Last: 850.0 + Other axis attributes: + axis: Z + realtopology: linear + Python id: ... + , id: latitude1 + Designated a latitude axis. + units: degrees_north + Length: 80 + First: -88.2884 + Last: 88.2884 + Other axis attributes: + axis: Y + realtopology: linear + Python id: ... + , id: longitude1 + Designated a longitude axis. + units: degrees_east + Length: 97 + First: -180.0 + Last: 180.0 + Other axis attributes: + axis: X + topology: circular + modulo: 360.0 + realtopology: linear + Python id: ... + ] In the above example, the domain elements are axes that are also @@ -214,9 +216,9 @@ example: >>> t = u.getTime() >>> print t[:] - >>> [ 1.] + [ 1.] >>> print t.units - >>> months since 1978-12 + months since 1978-12 Attributes ^^^^^^^^^^ @@ -226,9 +228,10 @@ name-value pairs. In fact, nearly all CDMS objects can have associated attributes, which are accessed using the Python dot notation: .. + >>> u.units='m/s' >>> print u.units - >>> m/s + m/s Attribute values can be strings, scalars, or 1-D Numpy arrays. @@ -243,14 +246,14 @@ attributes, a Python dictionary that defines the external attributes: .. >>> print u.attributes.keys() - >>> ['name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] + 'name', 'title', 'tileIndex', 'date', 'source', 'time', 'units', 'type'] The Python dir command lists the internal attribute names: .. >>> dir(u) - >>> ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] + ['T', '_FillValue', '_TransientVariable__domain', ..., 'view'] In general internal attributes should not be modified directly. One exception is the id attribute, the name of the variable. It is used in @@ -272,22 +275,22 @@ is true of the functions defined in the cdms2.MV2 module. For example: >>> a = MV2.array([1,2,3]) # Create array a, with no mask >>> b = MV2.array([4,5,6]) # Same for b >>> a+b # variable_... array([5,7,9,]) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> variable_... - >>> masked_array(data = [5 7 9], - >>> mask = False, - >>> fill_value = 999999) + variable_... + masked_array(data = [5 7 9], + mask = False, + fill_value = 999999) + >>> >>> >>> a[1]=MV2.masked # Mask the second value of a a.mask() >>> a.mask - >>> array([False, True, False], dtype=bool) + array([False, True, False], dtype=bool) >>> a+b # The sum is masked also # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> variable_... - >>> masked_array(data = [5 -- 9], - >>> mask = [False True False], - >>> fill_value = 999999) + variable_... + masked_array(data = [5 -- 9], + mask = [False True False], + fill_value = 999999) - When data is read from a file, the result variable is masked if the file variable has a missing_value attribute. The mask is set to one for those elements equal to the missing value, zero elsewhere. If no such @@ -331,7 +334,7 @@ data array: >>> u = f.getVariable('u') # or u=f['u'] >>> u.shape - >>> (1, 2, 80, 97) + (1, 2, 80, 97) File variables are also useful for fine-grained I/O. They behave like transient variables, but operations on them also affect the associated @@ -348,17 +351,17 @@ file. Specifically: >>> import os >>> os.system("cp clt.nc /tmp") - >>> 0 + 0 >>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write >>> uvar = f['u'] # Note square brackets >>> uvar.shape - >>>(1, 2, 80, 97) + 1, 2, 80, 97) >>> u0 = uvar[0] # Reads data from sample.nc >>> u0.shape - >>> (2, 80, 97) + (2, 80, 97) >>> uvar[1]=u0 # Writes data to sample.nc >>> uvar.units # Reads the attribute 'm/s' - >>> 'm/s' + 'm/s' >>> u24 = uvar(time=1.0) # Calling a variable like a function reads data >>> f.close() # Save changes to clt.nc (I/O may be buffered) @@ -371,30 +374,30 @@ MV.set_print_limit to force the data to be printed: >>> MV2.get_print_limit() # Current limit 1000 - >>> 1000 + 1000 >>> smallvar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> small variable - >>> masked_array(data = - >>> [[ 0. 1. 2. 3. 4.] - >>> [ 5. 6. 7. 8. 9.] - >>> [ 10. 11. 12. 13. 14.] - >>> [ 15. 16. 17. 18. 19.]], - >>> mask = - >>> False, - >>> fill_value = 999999.0) + small variable + masked_array(data = + [[ 0. 1. 2. 3. 4.] + [ 5. 6. 7. 8. 9.] + [ 10. 11. 12. 13. 14.] + [ 15. 16. 17. 18. 19.]], + mask = + False, + fill_value = 999999.0) >>> MV2.set_print_limit(100) >>> largevar # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> large variable - >>> masked_array(data = - >>> [[ 0. 1. 2. ..., 17. 18. 19.] - >>> [ 20. 21. 22. ..., 37. 38. 39.] - >>> [ 40. 41. 42. ..., 57. 58. 59.] - >>> ..., - >>> [ 340. 341. 342. ..., 357. 358. 359.] - >>> [ 360. 361. 362. ..., 377. 378. 379.] - >>> [ 380. 381. 382. ..., 397. 398. 399.]], - >>> mask = False, - >>> fill_value = 999999.0) + large variable + masked_array(data = + [[ 0. 1. 2. ..., 17. 18. 19.] + [ 20. 21. 22. ..., 37. 38. 39.] + [ 40. 41. 42. ..., 57. 58. 59.] + ..., + [ 340. 341. 342. ..., 357. 358. 359.] + [ 360. 361. 362. ..., 377. 378. 379.] + [ 380. 381. 382. ..., 397. 398. 399.]], + mask = False, + fill_value = 999999.0) The datatype of the variable is determined with the typecode function: @@ -402,7 +405,7 @@ The datatype of the variable is determined with the typecode function: >>> u.typecode() - >>> 'f' + 'f' Dataset Variables ^^^^^^^^^^^^^^^^^ @@ -434,11 +437,11 @@ The metafile **cdsample.xml** is then used like an ordinary data file: >>> import os >>> os.system("cdscan -x cdsample.xml [uv]*.nc") - >>> 0 + 0 >>> f = cdms2.open('cdsample.xml') >>> u = f('u') >>> u.shape - >>> (3, 16, 32) + (3, 16, 32) Grids ^^^^^^^^ @@ -487,13 +490,14 @@ grid. Note that: >>> f = cdms2.open('sampleCurveGrid4.nc') >>> + >>> >>> # lat and lon are coordinate axes, but are grouped with data variables >>> f.variables.keys() - >>> ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] >>> >>> # y and x are index coordinate axes >>> f.axes.keys() - >>> ['nvert', 'x', 'y'] + ['nvert', 'x', 'y'] >>> >>> # Read data for variable sample >>> sample = f('sample') @@ -503,7 +507,7 @@ grid. Note that: >>> >>> # The domain of the variable consfigists of index axes >>> sample.getAxisIds() - >>> ['y', 'x'] + ['y', 'x'] >>> >>> # Get the coordinate axes associated with the grid >>> lat = g.getLatitude() # or sample.getLatitude() @@ -511,31 +515,31 @@ grid. Note that: >>> >>> # lat and lon have the same domain, a subset of the domain of 'sample' >>> lat.getAxisIds() - >>> ['y', 'x'] + ['y', 'x'] >>> >>> # lat and lon are variables ... >>> lat.shape - >>> (32, 48) + (32, 48) >>> >>> lat # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - >>> lat - >>> masked_array(data = - >>> [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 - >>> -76.08465554] - >>> [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 - >>> -73.92641847] - >>> [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 - >>> -71.44420823] - >>> ..., - >>> [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 - >>> 42.32854943] - >>> [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 - >>> 42.70106429] - >>> [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 - >>> 43.0307341 ]], - >>> mask = - >>> False, - >>> fill_value = 1e+20) + lat + masked_array(data = + [[-76.08465554 -76.08465554 -76.08465554 ..., -76.08465554 -76.08465554 + -76.08465554] + [-73.92641847 -73.92641847 -73.92641847 ..., -73.92641847 -73.92641847 + -73.92641847] + [-71.44420823 -71.44420823 -71.44420823 ..., -71.44420823 -71.44420823 + -71.44420823] + ..., + [ 42.32854943 42.6582209 43.31990211 ..., 43.3199019 42.65822088 + 42.32854943] + [ 42.70106429 43.05731498 43.76927818 ..., 43.76927796 43.05731495 + 42.70106429] + [ 43.0307341 43.41264383 44.17234165 ..., 44.17234141 43.41264379 + 43.0307341 ]], + mask = + False, + fill_value = 1e+20) >>> >>> lat_in_radians = lat*MV2.pi/180.0 @@ -556,35 +560,33 @@ illustrates the grid, in this case a geodesic grid: .. >>> f.variables.keys() - >>> ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] + ['lat', 'sample', 'bounds_lon', 'lon', 'bounds_lat'] >>> f.axes.keys() - >>> ['nvert', 'x', 'y'] + ['nvert', 'x', 'y'] >>> zs = f('sample') >>> g = zs.getGrid() >>> g - >>> + >>> lat = g.getLatitude() >>> lon = g.getLongitude() >>> lat.shape - >>> (32, 48) + (32, 48) >>> lon.shape # variable zs is defined in terms of a single index coordinate - >>> (32, 48) + (32, 48) >>> # axis, 'cell' >>> zs.shape - >>> (32, 48) + (32, 48) >>> zs.getAxisIds() - >>> ['y', 'x'] + ['y', 'x'] >>> >>> # lat and lon are also defined in terms of the cell axis >>> lat.getAxisIds() - >>> ['y', 'x'] + ['y', 'x'] >>> >>> # lat and lon are one-dimensional, 'auxiliary' coordinate >>> # axes: values are not monotonic >>> lat.__class__ - - - + @@ -606,14 +608,12 @@ grid to curvilinear representation: >>> clt = f('clt') >>> rectgrid = clt.getGrid() >>> rectgrid.shape - >>> (46, 72) + (46, 72) >>> curvegrid = rectgrid.toCurveGrid() >>> curvegrid - >>> + >>> genericgrid = curvegrid.toGenericGrid() >>> genericgrid - - Regridding @@ -637,32 +637,32 @@ The built-in CDMS regridder is used to transform data from one rectangular grid to another. For example, to regrid variable ``u`` (from a rectangular grid) to a 96x192 rectangular Gaussian grid: -.. doctest:: +.. >>> f = cdms2.open('clt.nc') >>> u = f('u') >>> u.shape - >>> (1, 2, 80, 97) + (1, 2, 80, 97) >>> t63_grid = cdms2.createGaussianGrid(96) >>> u63 = u.regrid(t63_grid) >>> u63.shape - >>> (1, 2, 96, 192) + (1, 2, 96, 192) To regrid a variable ``uold`` to the same grid as variable ``vnew``: -.. doctest:: - +.. + >>> f = cdms2.open('clt.nc') >>> uold = f('u') >>> unew = f2('uwnd') >>> uold.shape - >>> (1, 2, 80, 97) + (1, 2, 80, 97) >>> unew.shape - >>> (1, 14, 181, 360) + (1, 14, 181, 360) >>> t63_grid = unew.getGrid() # Obtain the grid for vnew >>> u63 = u.regrid(t63_grid) >>> u63.shape - >>> (1, 2, 181, 360) + (1, 2, 181, 360) SCRIP Regridder ''''''''''''''' @@ -694,8 +694,8 @@ as necessary. #rmp_T42_to_POP43_conserv.nc: -.. doctest:: - +.. + >>> # Import regrid package for regridder functions >>> import regrid2, cdms2 >>> @@ -730,7 +730,7 @@ Relative time is time relative to a fixed base time. It consists of: For example, the time "28.0 days since 1996-1-1" has value= 28.0 , and units=" days since 1996-1-1". To create a relative time type: -.. doctest:: +.. >>> import cdtime >>> rt = cdtime.reltime(28.0, "days since 1996-1-1") @@ -745,7 +745,7 @@ A component time consists of the integer fields year, month, day, hour, minute , and the floating-point field second . For example: -.. doctest:: +.. >>> ct = cdtime.comptime(1996,2,28,12,10,30) >>> ct @@ -760,7 +760,7 @@ representations. For instance, suppose that the time axis of a variable is represented in units " days since 1979" . To find the coordinate value corresponding to January 1, 1990: -.. doctest:: +.. >>> ct = cdtime.comptime(1990,1) >>> rt = ct.torel("days since 1979") @@ -771,7 +771,8 @@ Time values can be used to specify intervals of time to read. The syntax time=(c1,c2) specifies that data should be read for times t such that c1<=t<=c2: -.. doctest:: +.. + >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") >>> c1 = cdtime.comptime(1980,1) @@ -786,7 +787,7 @@ c1<=t<=c2: or string representations can be used: -.. doctest:: +.. >>> fh = cdms2.open(cdat_info.get_sampledata_path() + "/tas_6h.nc") >>> tas = fh['tas'] @@ -809,14 +810,14 @@ To generate a plot: For example: -.. doctest:: +.. >>> import cdms2, vcs, cdat_info >>> fh=cdms2.open(cdat_info.get_sampledata_path() + "/tas_cru_1979.nc") >>> fh['time'][:] # Print the time coordinates array([ 1476., 1477., 1478., 1479., 1480., 1481., 1482., 1483., 1484., 1485., 1486., 1487.]) - + >>> >>> tas = fh('tas', time=1479) >>> tas.shape (1, 36, 72) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 285ccc7f..2300d300 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -72,7 +72,7 @@ to an output file. The input temperature data is ordered (time, latitude, longitude). .. - + >>> import cdms2, cdat_info >>> from cdms2 import MV >>> jones = cdms2.open(cdat_info.get_sampledata_path()+'/tas_mo.nc') @@ -87,9 +87,9 @@ latitude, longitude). >>> julyavg.long_name = "mean July surface temperature" >>> out = cdms2.open('janjuly.nc','w') >>> out.write(janavg) - >>> >> out.write(julyavg) - >>> >> out.comment = "Average January/July from Jones dataset" >>> jones.close() >>> out.close() @@ -128,7 +128,7 @@ in this chapter are made accessible with the command: The functions described in this section are not associated with a class. Rather, they are called as module functions, e.g., -.. +., >>> fle = cdms2.open('sample.nc') @@ -449,9 +449,9 @@ Example 1 .. >>> axis.isCircular() - >>> 1 + 1 >>> axis.mapIntervalExt((-5.0,5.0,'co')) - >>> (-2,3,1) + (-2,3,1) @@ -775,8 +775,8 @@ several ways: - The search can be restricted to the result of a previous search. - A search result is accessed sequentially within a for loop: -:: - +:: + >>> result = db.searchFilter('(&(category=obs*)(id=ncep*))') >>> for entry in result: >>> print entry.name @@ -789,22 +789,22 @@ variables defined on a 94x192 grid: >>> result = db.searchFilter('parentid=ncep*',tag="variable") >>> len(result) - >>> 65 + 65 >>> result2 = result.searchPredicate(lambda x: >>> - >>> x.getGrid().shape==(94,192)) + x.getGrid().shape==(94,192)) >>> len(result2) - >>> 3 + 3 >>> for entry in result2: print entry.name - >>> variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + variable=rluscs,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, >>> - >>> o=LLNL, c=US - >>> variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + o=LLNL, c=US + variable=rlds,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, >>> - >>> o=LLNL, c=US - >>> variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, + o=LLNL, c=US + variable=rlus,dataset=ncep_reanalysis_mo,database=CDMS,ou=PCMDI, >>> - >>> o=LLNL, c=US + o=LLNL, c=US @@ -885,7 +885,6 @@ This defaults to the database defined in environment variable **Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: :: - >>> for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): >>> print entry.name @@ -893,7 +892,6 @@ This defaults to the database defined in environment variable **Example:** Find all axes with bounds defined: :: - >>> for entry in db.searchFilter(filter="bounds=*",tag="axis"): >>> print entry.name @@ -908,11 +906,10 @@ This defaults to the database defined in environment variable **Example:** Find all variables with missing time values, in observed datasets: :: - >>> def missingTime(obj): >>> time = obj.getTime() >>> return time.length != time.partition_length - + >>> >>> result = db.searchFilter(filter="category=observed") >>> for entry in result.searchPredicate(missingTime): >>> print entry.name @@ -920,7 +917,6 @@ This defaults to the database defined in environment variable **Example:** Find all CMIP2 datasets having a variable with id “hfss”: :: - >>> for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): >>> print entry.getObject().parent.id @@ -1621,7 +1617,7 @@ takes an argument list of selector components. For example: :: - + >>> from cdms.selectors import Selector >>> sel = Selector(time=('1979-1-1','1979-2-1'), level=1000.) >>> x1 = v1(sel) @@ -1642,9 +1638,9 @@ to their keyword counterparts. For example: and - :: + >>> x = hus(time=('1979-1-1','1979-2-1'), level=1000.) @@ -1802,11 +1798,11 @@ results are written to a netCDF file. For brevity, the functions >>> # from upper air temperature, and calculate statistics >>> for ilev in range(len(levs)): >>> - >>> ta = taObj(time=(month1,month2,'cc'), \ - >>> level=slice(ilev, ilev+1), squeeze=1) - >>> ta = removeSeasonalCycle(ta) - >>> cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) - >>> v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) + >>> ta = taObj(time=(month1,month2,'cc'), \ + >>> level=slice(ilev, ilev+1), squeeze=1) + >>> ta = removeSeasonalCycle(ta) + >>> cc[ilev], b[ilev] = corrCoefSlope(tas ,ta) + >>> v[ilev] = MV.sum( ta**2 )/(1.0*ta.shape[0]) >>> >>> # Write slope, correlation, and variance variables >>> f = cdms.open('CC_B_V_ALL.nc','w') @@ -1816,7 +1812,7 @@ results are written to a netCDF file. For brevity, the functions >>> f.write(v) >>> f.close() >>> - >>> if __name__=='__main__': + >>> if __name__=='__main__': >>> pathTa = '/pcmdi/cdms/sample/ccmSample_ta.xml' >>> pathTas = '/pcmdi/cdms/sample/ccmSample_tas.xml' >>> # Process Jan80 through Dec81 diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index bfe61522..a387bb5f 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -164,7 +164,7 @@ Table Time Methods Examples ^^^^^^^^ -.. doctest:: +.. >>> from cdtime import * >>> c = comptime(1996,2,28) @@ -177,7 +177,7 @@ Examples **Note:** When adding or subtracting intervals of months or years, only the month and year of the result are significant. The reason is that intervals in months/years are not commensurate with intervals in days or fractional days. This leads to results that may be surprising. -.. doctest:: +.. >>> c = comptime(1979,8,31) >>> c.add(1,Month) @@ -186,7 +186,7 @@ Examples In other words, the day component of c was ignored in the addition, and the day/hour/minute components of the results are just the defaults. If the interval is in years, the interval is converted internally to months: -.. doctest:: +.. >>> c = comptime(1979,8,31) >>> c.add(2,Years) @@ -194,7 +194,7 @@ In other words, the day component of c was ignored in the addition, and the day/ Compare time values. -.. doctest:: +.. >>> from cdtime import * >>> r = cdtime.reltime(28,"days since 1996-1-1") @@ -209,7 +209,7 @@ Compare time values. Subtract an interval of time. -.. doctest:: +.. >>> from cdtime import * >>> r = cdtime.reltime(28,"days since 1996-1-1") @@ -224,7 +224,7 @@ For intervals of years or months, see the **note** under add() in the example ab Convert to component time. -.. doctest:: +.. >>> r = cdtime.reltime(28,"days since 1996-1-1") >>> r.tocomp() @@ -233,7 +233,7 @@ Convert to component time. Convert to relative time. -.. doctest:: +.. >>> c = comptime(1996,2,28) >>> print c.torel("days since 1996-1-1") diff --git a/docs/source/manual/cdms_appendix.rst b/docs/source/manual/cdms_appendix.rst index 9a25d864..13bba1f8 100644 --- a/docs/source/manual/cdms_appendix.rst +++ b/docs/source/manual/cdms_appendix.rst @@ -30,6 +30,7 @@ applications to treat the behavior of, say a dataset axis and file axis, as identical. .. figure:: /images/cdms_classes.jpg + :scale: 95% :alt: FIGURE 1. CDMS Classes @@ -53,7 +54,7 @@ VCS Quick Reference (Cheat Sheet) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. figure:: /manual/images/vcs_quick_ref.jpg - :scale: 25% + :scale: 35% :alt: VCS Cheat Sheet :download:`vcs quick ref ` From 9b2a4e0644311433b0f88209b359f6a215dc1e57 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Mon, 9 Apr 2018 10:23:04 -0700 Subject: [PATCH 074/239] change u to uold in example --- docs/source/manual/cdms_1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 33a2d191..7ca75362 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -652,7 +652,7 @@ To regrid a variable ``uold`` to the same grid as variable ``vnew``: >>> unew.shape (1, 14, 181, 360) >>> t63_grid = unew.getGrid() # Obtain the grid for vnew - >>> u63 = u.regrid(t63_grid) + >>> u63 = uold.regrid(t63_grid) >>> u63.shape (1, 2, 181, 360) From a145945e38ebd503983777ce7b3891a88f3079df Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 9 Apr 2018 15:28:59 -0700 Subject: [PATCH 075/239] Some changes to Chapters 2, 4, 5 and 6 --- docs/source/manual/cdms_2.rst | 16 ++++--- docs/source/manual/cdms_4.rst | 81 ++++++++++++++--------------------- docs/source/manual/cdms_5.rst | 2 +- docs/source/manual/cdms_6.rst | 59 +++++++++++-------------- 4 files changed, 67 insertions(+), 91 deletions(-) diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 2300d300..8f4b14f2 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -486,7 +486,7 @@ Table CdmsFile Constructors :widths: 50, 80 :align: left - "Constructor", "Description" + "``fileobj = cdms.open(path, mode)``", "Open the file specified by path returning a CdmsFile object. ``path`` is the file pathname, a string. ``mode`` is the open mode indicator, as listed in See `Open Modes <#table-open-modes>`_." "``fileobj = cdms.createDataset(path)``", "Create the file specified by path, a string." @@ -884,28 +884,30 @@ This defaults to the database defined in environment variable **Example:** List all variables in dataset ‘ncep\_reanalysis\_mo’: -:: + + >>> for entry in db.searchFilter(filter = "parentid=ncep_reanalysis_mo", tag = "variable"): >>> print entry.name **Example:** Find all axes with bounds defined: -:: + + >>> for entry in db.searchFilter(filter="bounds=*",tag="axis"): >>> print entry.name **Example:** Locate all GDT datasets: -:: + >>> for entry in db.searchFilter(filter="Conventions=GDT*",tag="dataset"): >>> print entry.name **Example:** Find all variables with missing time values, in observed datasets: -:: + >>> def missingTime(obj): >>> time = obj.getTime() >>> return time.length != time.partition_length @@ -916,13 +918,13 @@ This defaults to the database defined in environment variable **Example:** Find all CMIP2 datasets having a variable with id “hfss”: -:: + + >>> for entry in db.searchFilter(filter = "(&(project=CMIP2)(id=hfss))", tag = "variable"): >>> print entry.getObject().parent.id **Example:** Find all observed variables on 73x144 grids: -:: >>> result = db.searchFilter(category='obs*') >>> for entry in result.searchPredicate(lambda x: x.getGrid().shape==(73,144),tag="variable"): diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index 62655945..b3d11802 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -543,20 +543,16 @@ Get a mask from a separate file, and set as the input grid mask. >>> f.close() >>> g.close() +.. csv-table:: + :header: "Line", "Notes" + :widths: 8, 45 + + "7", "Get the input grid." + "10", "Get the output grid." + "11", "Create the regridder function." + "14", "Get the mask." + "15", "Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0." -+--------+-------------------------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+===================================================================================================================+ -| 7 | Get the input grid. | -+--------+-------------------------------------------------------------------------------------------------------------------+ -| 10 | Get the output grid | -+--------+-------------------------------------------------------------------------------------------------------------------+ -| 11 | Create the regridder function. | -+--------+-------------------------------------------------------------------------------------------------------------------+ -| 14 | Get the mask. | -+--------+-------------------------------------------------------------------------------------------------------------------+ -| 15 | Regrid with a user mask. The subslice call returns a transient variable corresponding to variable sof at time 0 | -+--------+-------------------------------------------------------------------------------------------------------------------+ **Note:** Although it cannot be determined from the code, both mask and the input array sof are four-dimensional. This is the n-dimensional @@ -578,19 +574,15 @@ Generate an array of zonal mean values. >>> mean = regridFunc(rlsf) >>> f.close() +.. csv-table:: + :header: "Line", "Notes" + :widths: 8, 45 + "3", "Get the input grid. Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid." + "4", "Create a zonal grid. outgrid has the same latitudes as ingrid, and a singleton longitude dimension. createGlobalMeanGrid could be used here to generate a global mean array." + "5", "Generate the regridder function." + "6", "Generate the zonal mean array." -+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+===================================================================================================================================================================================================+ -| 3 | Get the input grid. Return the area fraction of the source (input) grid cell that participates in the regridding. The array is 1-D, with length equal to the number of cells in the input grid. | -+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 4 | Create a zonal grid. outgrid has the same latitudes as ingrid, and a singleton longitude dimension. createGlobalMeanGrid could be used here to generate a global mean array. | -+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 5 | Generate the regridder function. | -+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 6 | Generate the zonal mean array | -+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ **Example:** @@ -617,32 +609,23 @@ of the result. >>> outsample, outmask = regridFunc(sample, mask=inmask, returnTuple=1) >>> outmean = add.reduce(ravel(outmask*outweights*outsample)) / add.reduce(ravel(outmask*outweights)) +.. csv-table:: + :header: "Line", "Notes" + :widths: 8, 45 + + "2", "Create a uniform target grid." + "3", "Get the latitude and longitude weights." + "4", "Generate a 2-D weights array." + "5", "Get the input grid. ``var`` is a 4-D variable." + "6", "Get the first horizontal slice from ``var``." + "7-8", "Get the input weights, and generate a 2-D weights array." + "9", "Set the 2-D input mask." + "10", "Calculate the input array area-weighted mean." + "11", "Create the regridder function." + "12", "Regrid. Because returnTuple is set to 1, the result is a tuple (dataArray, maskArray)." + "13", "Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal." + -+--------+----------------------------------------------------------------------------------------------------------+ -| Line | Notes | -+========+==========================================================================================================+ -| 2 | Create a uniform target grid. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 3 | Get the latitude and longitude weights. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 4 | Generate a 2-D weights array. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 5 | Get the input grid. ``var`` is a 4-D variable. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 6 | Get the first horizontal slice from ``var``. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 7-8 | Get the input weights, and generate a 2-D weights array. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 9 | Set the 2-D input mask. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 10 | Calculate the input array area-weighted mean. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 11 | Create the regridder function. | -+--------+----------------------------------------------------------------------------------------------------------+ -| 12 | Regrid. Because returnTuple is set to 1, the result is a tuple (dataArray, maskArray). | -+--------+----------------------------------------------------------------------------------------------------------+ -| 13 | Calculate the area-weighted mean of the regridded data. mean and outmean should be approximately equal | -+--------+----------------------------------------------------------------------------------------------------------+ SCRIP Regridder ~~~~~~~~~~~~~~~ diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 0f96d4ec..09d0701d 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -106,7 +106,7 @@ this example selects and plots a time-latitude slice: -.. csv-table:: Line Notes +.. csv-table:: :header: "Line", "Notes" :widths: 10, 90 diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index 2bc9e8fc..c0c08364 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -51,25 +51,20 @@ where The CDML elements are: Table CDML Tags -^^^^^^^^^^^^^^^^^^^ - -+------------+---------------------------------------+ -| Tag | Description | -+============+=======================================+ -| attr | Extra attribute | -+------------+---------------------------------------+ -| axis | Coordinate axis | -+------------+---------------------------------------+ -| domain | Axes on which a variable is defined | -+------------+---------------------------------------+ -| domElem | Element of a variable domain | -+------------+---------------------------------------+ -| linear | Linearly-spaced axis values | -+------------+---------------------------------------+ -| rectGrid | Rectilinear Grid | -+------------+---------------------------------------+ -| variable | Variable | -+------------+---------------------------------------+ +^^^^^^^^^^^^^^^^^^^ +.. csv-table:: + :header: "Tag", "Description" + :widths: 8, 35 + + "attr", "Extra attribute" + "axis", "Coordinate axis" + "domain", "Axes on which a variable is defined" + "domElem", "Element of a variable domain" + "linear", "Linearly-spaced axis values" + "rectGrid", "Rectilinear Grid" + "variable", "Variable" + + Special Characters ~~~~~~~~~~~~~~~~~~ @@ -79,21 +74,17 @@ they must be encoded to avoid confusion with markup: Table Special Character Encodings ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - -+-------------+------------+ -| Character | Encoding | -+=============+============+ -| < | < | -+-------------+------------+ -| > | > | -+-------------+------------+ -| & | & | -+-------------+------------+ -| “ | " | -+-------------+------------+ -| ‘ | ' | -+-------------+------------+ +.. csv-table:: + :header: "Character", "Encoding" + :widths: 8, 15 + + "<", "<" + ">", ">" + "&", "&" + "“", """ + "‘", "'" + + For example, the comment From 358376723b75c2dbf4bf7a78663a265926086ed9 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 15:12:04 -0700 Subject: [PATCH 076/239] Some changes to Regrid 2, Lib, esmf, gsRegrid and horizontal --- Lib/MV2.py | 33 ++-- Lib/avariable.py | 125 ++++++++------- Lib/axis.py | 156 +++++++++--------- Lib/bindex.py | 2 +- Lib/cdurlparse.py | 9 +- Lib/coord.py | 20 ++- Lib/cudsinterface.py | 22 ++- Lib/database.py | 108 ++++++------- Lib/dataset.py | 221 ++++++++++++++------------ Lib/forecast.py | 240 +++++++++++++++++----------- Lib/gengrid.py | 125 +++++++++++---- Lib/grid.py | 128 +++++++++++---- Lib/gsHost.py | 252 +++++++++++++++++++++++------ Lib/gsMosaic.py | 147 +++++++++++++---- Lib/gsStaticVariable.py | 115 +++++++++++--- Lib/gsTimeVariable.py | 178 ++++++++++++++++----- Lib/hgrid.py | 109 +++++++++---- Lib/internattr.py | 7 +- Lib/mvBaseWriter.py | 18 ++- Lib/mvCdmsRegrid.py | 145 +++++++++++++---- Lib/mvSphereMesh.py | 21 ++- Lib/mvVTKSGWriter.py | 6 +- Lib/mvVTKUGWriter.py | 6 +- docs/source/manual/cdms_1.rst | 2 +- regrid2/Lib/esmf.py | 290 ++++++++++++++++++++++++++-------- regrid2/Lib/gsRegrid.py | 249 ++++++++++++++++++++++------- regrid2/Lib/horizontal.py | 9 +- 27 files changed, 1952 insertions(+), 791 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index 23d9dbc0..aa622f33 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -556,12 +556,17 @@ def sort(a, axis=-1): def choose(myindices, t): - """Returns an array shaped like indices containing elements chosen - from t. - If an element of t is the special element masked, any element - of the result that "chooses" that element is masked. + """ + + Returns + ------- - The result has only the default axes. + an array shaped like indices containing elements chosen + from t. + If an element of t is the special element masked, any element + of the result that "chooses" that element is masked. + + The result has only the default axes. """ maresult = numpy.ma.choose(myindices, list(map(_makeMaskedArg, t))) F = getattr(t, "fill_value", 1.e20) @@ -580,8 +585,13 @@ def where(condition, x, y): def masked_where(condition, x, copy=1): - """Return x as an array masked where condition is true. - Also masked where x or condition masked. + """ + + Returns + ------- + + x as an array masked where condition is true. + Also masked where x or condition masked. """ tx = _makeMaskedArg(x) tcondition = _makeMaskedArg(condition) @@ -886,8 +896,13 @@ def outer(self, a, b): def asarray(data, typecode=None, dtype=None): """asarray(data, typecode=None, dtype=None) is equivalent to array(data, dtype=None, copy=0) - Returns data if dtype is None or data is a MaskedArray of the same dtype. - typecode arg is for backward compatibility. + + + Returns + ------- + + data if dtype is None or data is a MaskedArray of the same dtype. + typecode arg is for backward compatibility. """ dtype = _convdtype(dtype, typecode) if isinstance(data, AbstractVariable) and ( diff --git a/Lib/avariable.py b/Lib/avariable.py index 0a0511a0..4927b80d 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -40,8 +40,8 @@ def getMinHorizontalMask(var): Parameters ---------- - var - CDMS variable with a mask + var + CDMS variable with a mask Return ------ @@ -131,8 +131,15 @@ def info(self, flag=None, device=None): def __init__(self, parent=None, variableNode=None): """Not to be called by users. - variableNode is the variable tree node, if any. - parent is the containing dataset instance. + + Parameters + ---------- + + variableNode + is the variable tree node, if any. + parent + is the containing dataset instance. + """ if variableNode is not None and variableNode.tag != 'variable': raise CDMSError('Node is not a variable node') @@ -164,18 +171,18 @@ def __call__(self, *args, **kwargs): Parameters ---------- - raw: - if set to 1, return numpy.ma only - squeeze: - if set to 1, eliminate any dimension of length 1 - grid: - if given, result is regridded ont this grid. - order: - if given, result is permuted into this order + raw: + if set to 1, return numpy.ma only + squeeze: + if set to 1, eliminate any dimension of length 1 + grid: + if given, result is regridded ont this grid. + order: + if given, result is permuted into this order Returns ------- - Subregion selected + Subregion selected """ # separate options from selector specs d = kwargs.copy() @@ -275,8 +282,8 @@ def generateGridkey(self, convention, vardict): Returns ------- - ((latname, lonname, order, maskname, class), lat, lon) if gridded - (None, None, None) if not gridded """ + ((latname, lonname, order, maskname, class), lat, lon) if gridded + (None, None, None) if not gridded """ lat, nlat = convention.getVarLatId(self, vardict) lon, nlon = convention.getVarLonId(self, vardict) @@ -675,11 +682,11 @@ def getLongitude(self): # Get an order string, such as "tzyx" def getOrder(self, ids=0): """ - parameters + Parameters ---------- id: 0 or 1 - returns + Returns ------- the order string, such as t, z, y, x (time, level, lat, lon). @@ -811,18 +818,18 @@ def getSlice(self, *specs, **keys): Parameter --------- - raw: - if set to 1, return numpy.ma only - squeeze: - if set to 1, eliminate any dimension of length 1 - grid: - if given, result is regridded ont this grid. - order: - if given, result is permuted into this order - numericSqueeze: - if index slice is given, eliminate that dimension. - isitem: - if given, result is return as a scaler for 0-D data + raw: + if set to 1, return numpy.ma only + squeeze: + if set to 1, eliminate any dimension of length 1 + grid: + if given, result is regridded ont this grid. + order: + if given, result is permuted into this order + numericSqueeze: + if index slice is given, eliminate that dimension. + isitem: + if given, result is return as a scaler for 0-D data Note @@ -869,19 +876,19 @@ def getRegion(self, *specs, **keys): Parameters ---------- - slice - is an argument list, each item of which has one of the following forms: - * x, where x is a scalar - * Map the scalar to the index of the closest coordinate value. - * (x, y) - * Map the half-open coordinate interval [x,y) to index interval. - * (x, y, 'cc') - * Map the closed interval [x,y] to index interval. Other options - are 'oo' (open), 'oc' (open on the left), and 'co' - (open on the right, the default). - * (x, y, 'co', cycle) - * Map the coordinate interval with wraparound. If no cycle is - specified, wraparound will occur iff axis.isCircular() is true. + slice + is an argument list, each item of which has one of the following forms: + * x, where x is a scalar + * Map the scalar to the index of the closest coordinate value. + * (x, y) + * Map the half-open coordinate interval [x,y) to index interval. + * (x, y, 'cc') + * Map the closed interval [x,y] to index interval. Other options + are 'oo' (open), 'oc' (open on the left), and 'co' + (open on the right, the default). + * (x, y, 'co', cycle) + * Map the coordinate interval with wraparound. If no cycle is + specified, wraparound will occur iff axis.isCircular() is true. Ellipsis Represents the full range of all dimensions bracketed by non-Ellipsis items. None, colon @@ -1175,7 +1182,7 @@ def reorder(self, order): Returns ------- - New reordered variable. + New reordered variable. """ if order is None: @@ -1197,14 +1204,14 @@ def regrid(self, togrid, missing=None, order=None, mask=None, **keywords): Parameters ---------- - togrid - togrid destination grid. CDMS grid - missing : Optional - missing missing values - order : Optional - order axis order - mask : Optional - mask grid/data mask + togrid + togrid destination grid. CDMS grid + missing : Optional + missing missing values + order : Optional + order axis order + mask : Optional + mask grid/data mask **keyords keywords optional keyword arguments dependent on regridTool @@ -1363,13 +1370,13 @@ def pressureRegrid(self, newLevel, missing=None, order=None, method="log"): Parameters ---------- - newLevel : - is an axis of the result pressure levels. - method : - is optional, either `log` to interpolate in the log of pressure (default), - or `linear` for linear interpolation. - missing and order : - are as for regrid.PressureRegridder. + newLevel : + is an axis of the result pressure levels. + method : + is optional, either `log` to interpolate in the log of pressure (default), + or `linear` for linear interpolation. + missing and order : + are as for regrid.PressureRegridder. """ from regrid2 import PressureRegridder @@ -1680,7 +1687,7 @@ def decode(self, ar): def getGridIndices(self): """Return ------ - a tuple of indices corresponding to the variable grid.""" + a tuple of indices corresponding to the variable grid.""" grid = self.getGrid() result = [] if grid is not None: diff --git a/Lib/axis.py b/Lib/axis.py index 8c8ab40e..beb34059 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -196,22 +196,22 @@ def mapLinearIntersection(xind, yind, iind, """ Parameters ---------- - xind: - 'c' if (a,b) is closed on the left, 'o' if open, - yind: - same for right endpoint + xind: + 'c' if (a,b) is closed on the left, 'o' if open, + yind: + same for right endpoint j Returns ------- - True if the coordinate interval (a,b) intersects the node nodeSubI or cell - bounds [boundLeft,boundRight], where the interval (a,b) is defined by: + True if the coordinate interval (a,b) intersects the node nodeSubI or cell + bounds [boundLeft,boundRight], where the interval (a,b) is defined by: - * aMinusEps,aPlusEps = a +/- epsilon - * bPlusEps,bMinusEps = b +/- epsilon + * aMinusEps,aPlusEps = a +/- epsilon + * bPlusEps,bMinusEps = b +/- epsilon - and the intersection option iind = 'n','b','e','s' specifies whether - the intersection is with respect to the node value nodeSubI ('n' or 'e') - or the cell bounds [boundLeft,boundRight]. + and the intersection option iind = 'n','b','e','s' specifies whether + the intersection is with respect to the node value nodeSubI ('n' or 'e') + or the cell bounds [boundLeft,boundRight]. See Also -------- @@ -264,8 +264,8 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', Returns ------- - The corresponding index interval (i,j), where i vec2[len(vec2) - 1] + (isoverlap, index) : + where isoverlap is true if a leading portion of vec1 is a subset of vec2; + * index is the index such that vec1[0] <= vec2[index] + * If indexl == len(vec2), then vec1[0] > vec2[len(vec2) - 1] """ index = lookupArray(vec2, vec1[0]) if index == 0 and abs(vec1[0] - vec2[0]): @@ -701,28 +701,28 @@ def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): """ Parameters ---------- - ax1, ax2: array_like + ax1, ax2: array_like Returns ------- - bool - True if all elements of axes ax1 and ax2 are close, - in the sense of numpy.ma.allclose. + bool + True if all elements of axes ax1 and ax2 are close, + in the sense of numpy.ma.allclose. See Also -------- - all, any + all, any Examples -------- - >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) - >>> a - masked_array(data = [10000000000.0 1e-07 --], + >>> a = ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1]) + >>> a + masked_array(data = [10000000000.0 1e-07 --], mask = [False False True], fill_value = 1e+20) - >>> b = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) - >>> ma.allclose(a, b) - False + >>> b = ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1]) + >>> ma.allclose(a, b) + False """ return ((ax1 is ax2) or numpy.ma.allclose( ax1[:], ax2[:], rtol=rtol, atol=atol)) @@ -2437,29 +2437,29 @@ def axisMatchAxis(axes, specifications=None, omit=None, order=None): Parameters ---------- - specifications: - * is None, include all axes less the omitted ones. + specifications: + * is None, include all axes less the omitted ones. - * Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - omit: - * is None, do not omit any axis. + omit: + * is None, do not omit any axis. - * Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - order: - * A string containing the symbols `t,x,y,z` or `-`. If a `-` is - given, any elements of the result not chosen otherwise are filled - in from left to right with remaining candidates. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is + given, any elements of the result not chosen otherwise are filled + in from left to right with remaining candidates. - Return - ------ - A list of axes that match the specification omitting any axes that matches - an omit specification. + Returns + ------- + A list of axes that match the specification omitting any axes that matches + an omit specification. - Axes are returned in the order they occur in the axes argument unless order is given. + Axes are returned in the order they occur in the axes argument unless order is given. """ return [axes[i] for i in axisMatchIndex(axes, specifications, omit, order)] @@ -2472,28 +2472,28 @@ def axisMatchIndex(axes, specifications=None, omit=None, order=None): Parameters ---------- - specifications: - * is None, include all axes less the omitted ones. + specifications: + * is None, include all axes less the omitted ones. - * Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - omit: - * is None, do not omit any axis. + omit: + * is None, do not omit any axis. - * Individual specifications must be integer indices into axes or - matching criteria as detailed in axisMatches. + * Individual specifications must be integer indices into axes or + matching criteria as detailed in axisMatches. - order: - * A string containing the symbols `t,x,y,z` or `-`. If a `-` is - given, any elements of the result not chosen otherwise are filled - in from left to right with remaining candidates. + order: + * A string containing the symbols `t,x,y,z` or `-`. If a `-` is + given, any elements of the result not chosen otherwise are filled + in from left to right with remaining candidates. - Return - ------ - A list of axis' indices which match the specification omitting any axes that matches an omit specification. + Returns + ------- + A list of axis' indices which match the specification omitting any axes that matches an omit specification. - Axes are returned in the order they occur in the axes argument unless order is given. + Axes are returned in the order they occur in the axes argument unless order is given. """ if specifications is None: @@ -2608,14 +2608,14 @@ def axisMatches(axis, specification): """ Parameters ---------- - axis: - See note below - specifications: - See note below + axis: + See note below + specifications: + See note below Returns ------- - 1 or 0 depending on whether axis matches the specification. + 1 or 0 depending on whether axis matches the specification. Note ---- @@ -2706,8 +2706,8 @@ def take(ax, indices): The indices of the values to extract. Returns ------- - axis: TransientAxis - The return array has the same type of ax. + axis: TransientAxis + The return array has the same type of ax. """ # Bug in ma compatibility module diff --git a/Lib/bindex.py b/Lib/bindex.py index df14ead0..572bd4a2 100644 --- a/Lib/bindex.py +++ b/Lib/bindex.py @@ -49,7 +49,7 @@ def intersectHorizontalGrid(latspecs, lonspecs, latlin, lonlin, index): Returns ------- - an array of indices, in latlin/lonlin, of the points in the intersection. + an array of indices, in latlin/lonlin, of the points in the intersection. """ points = numpy.zeros(len(latlin), dtype='l') if latspecs is None: diff --git a/Lib/cdurlparse.py b/Lib/cdurlparse.py index f8022a10..6f6ac6f7 100644 --- a/Lib/cdurlparse.py +++ b/Lib/cdurlparse.py @@ -185,9 +185,12 @@ def urljoin(base, url, allow_fragments=1): def urldefrag(url): """Removes any existing fragment from URL. - Returns a tuple of the defragmented URL and the fragment. If - the URL contained no fragments, the second element is the - empty string. + Returns + ------- + + a tuple of the defragmented URL and the fragment. If + the URL contained no fragments, the second element is the + empty string. """ s, n, p, a, q, frag = urlparse(url) defrag = urlunparse((s, n, p, a, q, '')) diff --git a/Lib/coord.py b/Lib/coord.py index 0d1d8107..7222a1f4 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -282,8 +282,14 @@ def __init__(self, parent=None, variableNode=None, bounds=None): def clone(self, copyData=1): """clone (self, copyData=1) - Return a copy of self as a transient axis. - If copyData is 1, make a separate copy of the data.""" + + Returns + ------- + a copy of self as a transient axis. + + Note + ---- + If copyData is 1, make a separate copy of the data.""" result = TransientAxis2D( self[:], copy=copyData, @@ -367,9 +373,15 @@ class TransientAxis2D(AbstractAxis2D, TransientVariable): def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): """Create a transient 2D axis. + All arguments are as for TransientVariable. - 'bounds' is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and - nvert is the max number of vertices per cell. + + Parameters + ---------- + + 'bounds' is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and + + nvert is the max number of vertices per cell. """ AbstractAxis2D.__init__(self, None, None, bounds=bounds) TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index 470081f4..7c0d9ab7 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -114,8 +114,14 @@ def listattribute(self, vname=None): return list(v.attributes.keys()) def listdimension(self, vname=None): - """Return a list of the dimension names associated with a variable. + """ + + Returns + ------- + + a list of the dimension names associated with a variable. If no argument, return the file.axes.keys() + ::: Options::: vname :: (str/None) (None) variable name @@ -129,13 +135,23 @@ def listdimension(self, vname=None): return [getattr(n, 'id') for n in x] def listglobal(self): - """Returns a list of the global attributes in the file. + """ + + Returns + ------- + + a list of the global attributes in the file. ::: """ return list(self.attributes.keys()) def listvariable(self): - """Return a list of the variables in the file. + """ + + Returns + ------- + + a list of the variables in the file. ::: """ return list(self.variables.keys()) diff --git a/Lib/database.py b/Lib/database.py index 731acb8d..cc65895e 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -39,26 +39,26 @@ def connect(uri=None, user="", password=""): """ - Method: - + Method + ------ connect(uri=None, user="", password="") - Description: - + Description + ----------- Open a CDMS database connection. - Arguments: - + Arguments + --------- uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. user: user id password: password - Returns: - + Returns + ------- Database instance. - Example: - + Example + ------- db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US") """ if uri is None: @@ -194,16 +194,16 @@ def __init__(self, uri, db): def close(self): """ - Method: - + Method + ------ close() - Description: - + Description + ----------- Close a database connection. - Returns: - + Returns + ------- None """ @@ -274,25 +274,25 @@ def getObjFromDataset(self, dn): def openDataset(self, dsetid, mode='r'): """ - Method: - + Method + ------ openDataset(dsetid, mode='r') - Description: - + Description + ----------- Open a dataset. - Arguments: - + Arguments + --------- dsetid: string dataset identifier mode: open mode ('r' - read-only, 'r+' - read-write, 'w' - create) - Returns: - + Returns + ------- Dataset instance. - Example: - + Example + ------- dset = db.openDataset('ncep_reanalysis_mo') """ dn = "dataset=%s,%s" % (dsetid, self.path) @@ -326,23 +326,23 @@ def setExternalDict(self, ldapattrs): def searchFilter(self, filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None): """ - Method: - + Method + ------ searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) - Description: - + Description + ----------- Search a CDMS database. - Arguments: - + Arguments + --------- filter: string search filter Simple filters have the form "tag = value". Simple filters can be combined using logical operators '&', '|', '!' in prefix notation. For example, the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. - More formally: - + More formally + ------------- filter ::= "(" filtercomp ")" filtercomp ::= "&" filterlist | # and "|" filterlist | # or @@ -365,8 +365,8 @@ def searchFilter(self, filter=None, tag=None, relbase=None, attnames: list of attribute names. Restricts the attributes returned. timeout: integer number of seconds before timeout. - Returns: - + Returns + ------- SearchResult instance. Entries can be accessed sequentially. For each entry, entry.name is the name of the entry, entry.attributes is a dictionary of the attributes returned by the search, entry.getObject() returns the CDMS object associated with the entry: @@ -376,8 +376,8 @@ def searchFilter(self, filter=None, tag=None, relbase=None, Entries can be refined with searchPredicate(). - Example: - + Example + ------- (1) Find all variables named "cli": result = db.searchFilter(filter="id=cli",tag="variable") @@ -464,22 +464,22 @@ def __getitem__(self, key): def searchPredicate(self, predicate, tag=None): """ - Method: - + Method + ------ searchPredicate(predicate, tag=None) - Description: - + Description + ----------- Refine a search result, with a predicate search. - Arguments: - + Arguments + --------- predicate: Function name or lambda function. The function takes a single CDMS object, and returns true (1) if the object satisfies the predicate, 0 if not. tag: Restrict the search to objects in one class. - Returns: - + Returns + ------- SearchResult instance. Entries can be accessed sequentially. For each entry, entry.name is the name of the entry, entry.attributes is a dictionary of the attributes returned by the search, entry.getObject() returns the CDMS object associated with the entry: @@ -489,8 +489,8 @@ def searchPredicate(self, predicate, tag=None): Entries can be refined with searchPredicate(). - Example: - + Example + ------- (1) Find all variables on a 73x96 grid newresult = result.searchPredicate(lambda obj: obj.getGrid().shape==(73,96),"variable") @@ -522,16 +522,16 @@ def __init__(self, db): def getObject(self): """ - Method: - + Method + ------ getObject() - Description: - + Description + ----------- Get the CDMS object associated with this entry. - Returns: - + Returns + ------- Instance of a CDMS object. """ diff --git a/Lib/dataset.py b/Lib/dataset.py index 06c1d5c3..e5348ef2 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -378,6 +378,7 @@ def getNetcdfDeflateLevelFlag(): def useNetcdf3(): """ Turns off (0) NetCDF flags for shuffle/cuDa/deflatelevel Output files are generated as NetCDF3 Classic after that + Returns ------- No return value. @@ -607,15 +608,15 @@ def parselist(text, f): def parseIndexList(text): """Parse a string of the form [i,j,k,l,...,path]. - Parameters - ---------- - text: - i,j,k,l,... are indices or '-', and path is a filename. - Coerce the indices to integers. - Returns - ------- - Parser results. - n number of matches. + Parameters + ---------- + text: + i,j,k,l,... are indices or '-', and path is a filename. + Coerce the indices to integers. + Returns + ------- + Parser results. + n number of matches. """ m = _IndexList4.match(text) nindices = 4 @@ -1163,7 +1164,11 @@ def openFile(self, filename, mode): def getLogicalCollectionDN(self, base=None): """Return the logical collection distinguished name of this dataset. - If is defined, append it to the lc name. + + + Note + ---- + If is defined, append it to the lc name. """ if hasattr(self, "lc"): dn = self.lc @@ -1174,7 +1179,11 @@ def getLogicalCollectionDN(self, base=None): return dn def getVariable(self, id): - "Get the variable object with the given id. Returns None if not found." + "Get the variable object with the given id. + + Returns + ------- + None if not found." return self.variables.get(id) def getVariables(self, spatial=0): @@ -1191,11 +1200,19 @@ def getVariables(self, spatial=0): return retval def getAxis(self, id): - "Get the axis object with the given id. Returns None if not found." + "Get the axis object with the given id. + + Returns + ------- + None if not found." return self.axes.get(id) def getGrid(self, id): - "Get the grid object with the given id. Returns None if not found." + "Get the grid object with the given id. + + Returns + ------- + None if not found." return self.grids.get(id) def __repr__(self): @@ -1503,12 +1520,12 @@ def createAxis(self, name, ar, unlimited=0): Parameters ---------- - name: str - is the string name of the Axis - ar: numpy.ndarray/None - is the 1-D data array, or None for an unlimited axis - unlimited: (int/True/False) - True/0 designate that the axis as unlimited. + name: str + is the string name of the Axis + ar: numpy.ndarray/None + is the 1-D data array, or None for an unlimited axis + unlimited: (int/True/False) + True/0 designate that the axis as unlimited. Returns ------- @@ -1664,22 +1681,22 @@ def createRectGrid(self, id, lat, lon, order, type="generic", mask=None): Parameters ---------- - id: (str) - grid name (default 0) - lat: (numpy.ndarray) - latitude array (default 1) - lon: (numpy.ndarray) - longitude array (default 2) + id: (str) + grid name (default 0) + lat: (numpy.ndarray) + latitude array (default 1) + lon: (numpy.ndarray) + longitude array (default 2) order: (str) - order (default 3) - type: (str) - grid type (defalut `generic`) - mask: (None/numpy.ndarray) - mask (default None) + order (default 3) + type: (str) + grid type (defalut `generic`) + mask: (None/numpy.ndarray) + mask (default None) Returns ------- - grid (cdms2.grid.FileRectGrid) + grid (cdms2.grid.FileRectGrid) """ grid = FileRectGrid(self, id, lat, lon, order, type, mask) @@ -1756,14 +1773,14 @@ def createVariable(self, name, datatype, axesOrGrids, fill_value=None): Parameters ---------- - name: - The string name of the Variable - datatype: - A CDMS datatype or numpy typecode - axesOrGrids: - is a list of axes, grids. - fill_value: - fill_value (cast into data type). + name: + The string name of the Variable + datatype: + A CDMS datatype or numpy typecode + axesOrGrids: + is a list of axes, grids. + fill_value: + fill_value (cast into data type). Note ---- @@ -1860,17 +1877,17 @@ def matchPattern(self, pattern, attribute, tag): Parameters ---------- - pattern: - String expression. - attribute: - Attribute Name. If `None` search all attributre. - tag: - node tag, if `cdmsFile` only match the current dataset otherwise match - all object matching the tag. + pattern: + String expression. + attribute: + Attribute Name. If `None` search all attributre. + tag: + node tag, if `cdmsFile` only match the current dataset otherwise match + all object matching the tag. Returns ------- - list of match patterns. + list of match patterns. """ resultlist = [] if tag is not None: @@ -1905,17 +1922,17 @@ def searchPredicate(self, predicate, tag): Parameters ---------- - predicate: - function use as predicate - tag: - node tag. + predicate: + function use as predicate + tag: + node tag. Returns ------- - List containing a single instance - [self] if the predicate is true and either tag is None or matches the object node tag. + List containing a single instance + [self] if the predicate is true and either tag is None or matches the object node tag. - Empty list If the predicate returns false. + Empty list If the predicate returns false. """ resultlist = [] if tag is not None: @@ -1954,31 +1971,31 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds Parameters ---------- - var: - variable to copy (cdms2.tvariable.TransientVariable or cdms2.fvariable.FileVariable) - attributes: - A dictionary of attributes. Default is var.attributes. - axes: - The list of axis objects. Default is var.getAxisList() - extbounds: - Bounds of the (portion of) the extended dimension being written. - id or newname: - String identifier of the new variable. - extend: - * 1 define the first dimension as the unlimited dimension. - * 0 do not define an unlimited dimension. The default is the define + var: + variable to copy (cdms2.tvariable.TransientVariable or cdms2.fvariable.FileVariable) + attributes: + A dictionary of attributes. Default is var.attributes. + axes: + The list of axis objects. Default is var.getAxisList() + extbounds: + Bounds of the (portion of) the extended dimension being written. + id or newname: + String identifier of the new variable. + extend: + * 1 define the first dimension as the unlimited dimension. + * 0 do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. - fill_value: - The missing value flag. - index: - The extended dimension index for writting. The default index is determined + fill_value: + The missing value flag. + index: + The extended dimension index for writting. The default index is determined by lookup relative to the existing extended dimension. - grid: - The variable grid. `none` the value of var.getGrid() will used. + grid: + The variable grid. `none` the value of var.getGrid() will used. Returns ------- - file variable (cdms2.fvariable.FileVariable) + file variable (cdms2.fvariable.FileVariable) """ if newname is None: newname = var.id @@ -2105,31 +2122,31 @@ def write(self, var, attributes=None, axes=None, extbounds=None, id=None, Parameters ---------- - var: - variable to copy. - attributes: - The attribute dictionary for the variable. The default is var.attributes. - axes: - The list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). - extbounds: - The extended dimension bounds. Defaults to var.getAxis(0).getBounds(). - id: - The variable name in the file. Default is var.id. - extend: - * 1 causes the first dimension to be `extensible` iteratively writeable. The default is None, - in which case the first dimension is extensible if it is time. - * 0 to turn off this behaviour. - fill_value: is the missing value flag. - index: - The extended dimension index to write to. The default index is determined b - lookup relative to the existing extended dimension. - dtype: - The numpy dtype. - typecode: - Deprecated, for backward compatibility only + var: + variable to copy. + attributes: + The attribute dictionary for the variable. The default is var.attributes. + axes: + The list of file axes comprising the domain of the variable. The default is to copy var.getAxisList(). + extbounds: + The extended dimension bounds. Defaults to var.getAxis(0).getBounds(). + id: + The variable name in the file. Default is var.id. + extend: + * 1 causes the first dimension to be `extensible` iteratively writeable. The default is None, + in which case the first dimension is extensible if it is time. + * 0 to turn off this behaviour. + fill_value: is the missing value flag. + index: + The extended dimension index to write to. The default index is determined b + lookup relative to the existing extended dimension. + dtype: + The numpy dtype. + typecode: + Deprecated, for backward compatibility only Returns ------- - File variable + File variable """ if _showCompressWarnings: if (Cdunif.CdunifGetNCFLAGS("shuffle") != 0) or (Cdunif.CdunifGetNCFLAGS( @@ -2285,7 +2302,7 @@ def write_it_yourself(self, obj): object containing `writeg`, `writeToFile` or `write` method. Returns ------- - Nothig is returned. """ + Nothing is returned. """ # This method was formerly called writeg and just wrote an # AbstractCurveGrid. if (hasattr(obj, 'writeg') and callable(getattr(obj, 'writeg'))): @@ -2301,13 +2318,13 @@ def getVariable(self, id): Parameters ---------- - id: str - id of the variable to get + id: str + id of the variable to get Returns ------- - variable (cdms2.fvariable.FileVariable/None) - file variable + variable (cdms2.fvariable.FileVariable/None) + file variable """ return self.variables.get(id) diff --git a/Lib/forecast.py b/Lib/forecast.py index 5a906670..75dcae5e 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -10,10 +10,17 @@ def two_times_from_one(t): - """Input is a time representation, either as the long int used in the cdscan - script, or a string in the format "2010-08-25 15:26:00", or as a cdtime comptime - (component time) object. - Output is the same time, both as a long _and_ as a comptime.""" + """ + Parameters + ---------- + + Input + is a time representation, either as the long int used in the cdscan + script, or a string in the format "2010-08-25 15:26:00", or as a cdtime comptime + (component time) object. + + Output + is the same time, both as a long _and_ as a comptime.""" if t == 0: t = 0 if isinstance(t, str): @@ -47,10 +54,15 @@ def two_times_from_one(t): def comptime(t): - """Input is a time representation, either as the long int used in the cdscan - script, or a string in the format "2010-08-25 15:26:00", or as a cdtime comptime - (component time) object. - Output is the same time a cdtime.comptime (component time).""" + """ + Parameters + --------- + Input + is a time representation, either as the long int used in the cdscan + script, or a string in the format "2010-08-25 15:26:00", or as a cdtime comptime + (component time) object. + Output + is the same time a cdtime.comptime (component time).""" tl, tc = two_times_from_one(t) return tc @@ -59,15 +71,29 @@ class forecast(): """represents a forecast starting at a single time""" def __init__(self, tau0time, dataset_list, path="."): - """tau0time is the first time of the forecast, i.e. the time at which tau=0. - dataset_list is used to get the forecast file from the forecast time. - Each list item should look like this example: - [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] - Normally dataset_list = fm[i][1] where fm is the output of - cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. - - N.B. This is like a CdmsFile. Creating a forecast means opening a file, - so later on you should call forecast.close() to close it. + """ + + Parameters + ---------- + + tau0time + is the first time of the forecast, i.e. the time at which tau=0. + dataset_list + is used to get the forecast file from the forecast time. + + Example + ------- + + Each list item should look like this example: + [None, None, None, None, 2006022200000L, 'file2006-02-22-00000.nc'] + Normally dataset_list = fm[i][1] where fm is the output of + cdms2.dataset.parseFileMap and fm[i][0] matches the variables of interest. + + Note + ---- + + N.B. This is like a CdmsFile. Creating a forecast means opening a file, + so later on you should call forecast.close() to close it. """ self.fctl, self.fct = two_times_from_one(tau0time) @@ -96,12 +122,19 @@ def __repr__(self): def available_forecasts(dataset_file, path="."): - """Returns a list of forecasts (as their generating times) which are - available through the specified cdscan-generated dataset xml file. - The forecasts are given in 64-bit integer format, but can be converted - to component times with the function two_times_from_one. - This function may help in choosing the right arguments for initializing - a "forecasts" (forecast set) object. + """ + + Returns + ------- + a list of forecasts (as their generating times) which are + available through the specified cdscan-generated dataset xml file. + + Note + ---- + The forecasts are given in 64-bit integer format, but can be converted + to component times with the function two_times_from_one. + This function may help in choosing the right arguments for initializing + a "forecasts" (forecast set) object. """ dataset = cdms2.openDataset(dataset_file, dpath=path) fm = cdms2.dataset.parseFileMap(dataset.cdms_filemap) @@ -114,42 +147,46 @@ class forecasts(): """represents a set of forecasts""" def __init__(self, dataset_file, forecast_times, path="."): - """Creates a set of forecasts. Normally you do it by something like - f = forecasts( 'file.xml', (min_time, max_time) ) - or - f = forecasts( 'file.xml', (min_time, max_time), '/home/me/data/' ) - or - f = forecasts( 'file.xml', [ time1, time2, time3, time4, time5 ] ) - - where the two or three arguments are:: - - 1. the name of a dataset xml file generated by "cdscan --forecast ..." - - 2. Times here are the times when the forecasts began (tau=0, aka reference time). - (i) If you use a 2-item tuple, forecasts will be chosen which start at a time - t between the min and max times, e.g. min_time <= t < max_time . - (ii) If you use a list, it will be the exact start (tau=0) times for the - forecasts to be included. - (iii) If you use a 3-item tuple, the first items are (min_time,max_time) - as in a 2-item tuple. The third component of the tuple is the - open-closed string. This determines whether endpoints are included - The first character should be 'o' or 'c' depending on whether you want t with - min_time>> f = cdms2.open('/tmp/clt.nc','a') # Open read/write >>> uvar = f['u'] # Note square brackets >>> uvar.shape - 1, 2, 80, 97) + (1, 2, 80, 97) >>> u0 = uvar[0] # Reads data from sample.nc >>> u0.shape (2, 80, 97) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 9aba218c..884a7800 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -42,8 +42,13 @@ class EsmfUnstructGrid: def __init__(self, numTopoDims, numSpaceDims): """ Constructor - @param numTopoDims number of topological dimensions - @param numSpaceDims number of space dimensions + + Parameters + ---------- + + numTopoDims number of topological dimensions + + numSpaceDims number of space dimensions """ # handle to the grid object self.grid = None @@ -69,13 +74,24 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """ Set Cell connectivity - @param cell indices (0-based) - @param cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - @param connectivity node connectivity array, see below for node ordering - @param cellMask - @param cellAreas area (volume) of each cell + Parameters + ---------- + + cell indices (0-based) + + cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + + connectivity node connectivity array, see below for node ordering + + cellMask + + cellAreas area (volume) of each cell + + Note + ---- + `` 3 4 ---------- 3 / \ | | / \ | | @@ -83,9 +99,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, / \ | | / \ | | 1 --------- 2 1 ---------- 2 - - - + `` 3 8---------------7 /|\ /| /| / | \ / | / | @@ -100,7 +114,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, \|/ |/ |/ 1 1---------------2 - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX `` """ n = len(cellIndices) @@ -115,9 +129,15 @@ def setCells(self, cellIndices, cellTypes, connectivity, def setNodes(self, indices, coords, peOwners=None): """ Set the nodal coordinates - @param indices Ids of the nodes (0-based) - @param coords nodal coordinates - @param peOwners processor ranks where the coordinates reside (0-based) + + Parameters + ---------- + + indices Ids of the nodes (0-based) + + coords nodal coordinates + + peOwners processor ranks where the coordinates reside (0-based) """ n = len(indices) if not self.nodesAdded: @@ -131,7 +151,11 @@ def setNodes(self, indices, coords, peOwners=None): def toVTK(self, filename): """ Write grid to VTK file format - @param filename VTK file name + + Parameters + ---------- + + filename VTK file name """ self.grid.write(filename) @@ -151,18 +175,26 @@ def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, hasBounds=False): """ Constructor - @param shape Tuple of cell sizes along each axis - @param coordSys coordinate system + + Parameters + ---------- + + shape Tuple of cell sizes along each axis + + coordSys coordinate system ESMF.CoordSys.CART Cartesian ESMF.CoordSys.SPH_DEG (default) Degrees ESMF.CoordSys.SPH_RAD Radians - @param periodicity Does the grid have a periodic coordinate + + periodicity Does the grid have a periodic coordinate 0 No periodicity 1 Periodic in x (1st) axis 2 Periodic in x, y axes - @param staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX + + staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX The stagger constants are listed at the top - @param hasBounds If the grid has bounds, Run AddCoords for the bounds + + hasBounds If the grid has bounds, Run AddCoords for the bounds """ # ESMF grid object self.grid = None @@ -215,8 +247,15 @@ def getLocalSlab(self, staggerloc): """ Get the local slab (ellipsis). You can use this to grab the data local to this processor - @param staggerloc (e.g. ESMF.StaggerLoc.CENTER) - @return tuple of slices + + Parameters + ---------- + + staggerloc (e.g. ESMF.StaggerLoc.CENTER) + Returns + ------- + + tuple of slices """ lo, hi = self.getLoHiBounds(staggerloc) return tuple([slice(lo[i], hi[i], None) @@ -226,8 +265,16 @@ def getLoHiBounds(self, staggerloc): """ Get the local lo/hi index values for the coordinates (per processor) (hi is not inclusive, lo <= index < hi) - @param staggerloc e.g. ESMF.StaggerLoc.CENTER - @return lo, hi lists + + Parameters + ---------- + + staggerloc e.g. ESMF.StaggerLoc.CENTER + + Returns + ------- + + lo, hi lists """ lo = self.grid.lower_bounds[staggerloc] hi = self.grid.upper_bounds[staggerloc] @@ -236,8 +283,16 @@ def getLoHiBounds(self, staggerloc): def getCoordShape(self, staggerloc): """ Get the local coordinate shape (may be different on each processor) - @param staggerloc (e.g. ESMF.StaggerLoc.CENTER) - @return tuple + + Parameters + ---------- + + staggerloc (e.g. ESMF.StaggerLoc.CENTER) + + Returns + ------- + + tuple """ lo, hi = self.getLoHiBounds(staggerloc) return tuple([hi[i] - lo[i] for i in range(self.ndims)]) @@ -245,15 +300,23 @@ def getCoordShape(self, staggerloc): def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): """ Populate the grid with staggered coordinates (e.g. corner or center). - @param coords The curvilinear coordinates of the grid. + + + Parameters + ---------- + + coords The curvilinear coordinates of the grid. List of numpy arrays. Must exist on all procs. - @param staggerloc The stagger location + + staggerloc The stagger location ESMF.StaggerLoc.CENTER (default) ESMF.StaggerLoc.CORNER - @param globalIndexing if True array was allocated over global index + + globalIndexing if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None + Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. """ @@ -271,8 +334,13 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): def getCoords(self, dim, staggerloc): """ Return the coordinates for a dimension - @param dim desired dimension (zero based indexing) - @param staggerloc Stagger location + + Parameters + --------- + + dim desired dimension (zero based indexing) + + staggerloc Stagger location """ gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) shp = self.getCoordShape(staggerloc) @@ -281,7 +349,11 @@ def getCoords(self, dim, staggerloc): def setCellAreas(self, areas): """ Set the cell areas - @param areas numpy array + + Parameters + --------- + + areas numpy array """ self.grid.add_item(item=ESMF.GridItem.Area) areaPtr = self.grid.get_item( @@ -292,7 +364,11 @@ def setCellAreas(self, areas): def getCellAreas(self): """ - @return cell areas or None if setCellAreas was not called + + Returns + ------- + + cell areas or None if setCellAreas was not called """ if self.cellAreasSet: areaPtr = self.grid.get_item( @@ -305,7 +381,11 @@ def getCellAreas(self): def getMask(self, staggerloc=CENTER): """ Get mask array. In ESMF, the mask is applied to cells. - @return mask numpy array. 1 is invalid by default. This array exists on all procs + + Returns + ------- + + mask numpy array. 1 is invalid by default. This array exists on all procs """ try: maskPtr = self.grid.get_item( @@ -317,7 +397,11 @@ def getMask(self, staggerloc=CENTER): def setMask(self, mask, staggerloc=CENTER): """ Set mask array. In ESMF, the mask is applied to cells. - @param mask numpy array. 1 is invalid by default. This array exists + + Parameters + ---------- + + mask numpy array. 1 is invalid by default. This array exists on all procs """ self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) @@ -341,11 +425,18 @@ class EsmfStructField: def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): """ Creator for structured ESMF Field - @param esmfGrid instance of an ESMF - @param name field name (must be unique) - @param datatype data type, one of 'float64', 'float32', 'int64', or 'int32' + + Parameters + ---------- + + esmfGrid instance of an ESMF + + name field name (must be unique) + + datatype data type, one of 'float64', 'float32', 'int64', or 'int32' (or equivalent numpy dtype) - @param staggerloc ESMF.StaggerLoc.CENTER + + staggerloc ESMF.StaggerLoc.CENTER ESMF.StaggerLoc.CORNER """ # field object @@ -392,17 +483,29 @@ def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): def getPointer(self): """ Get field data as a flat array - @return pointer + + Returns + ------- + + pointer """ return numpy.ravel(self.field.data) def getData(self, rootPe): """ Get field data as a numpy array - @param rootPe if None then local data will be fetched, otherwise + + Parameters + ---------- + + rootPe if None then local data will be fetched, otherwise gather the data on processor "rootPe" (all other procs will return None). - @return numpy array or None + + Returns + ------- + + numpy array or None """ ptr = self.getPointer() if rootPe is None: @@ -446,10 +549,17 @@ def getData(self, rootPe): def setLocalData(self, data, staggerloc, globalIndexing=False): """ Set local field data - @param data full numpy array, this method will take care of setting a + + Parameters + ---------- + + data full numpy array, this method will take care of setting a the subset of the data that reside on the local processor - @param staggerloc stagger location of the data - @param globalIndexing if True array was allocated over global index + + staggerloc stagger location of the data + + + globalIndexing if True array was allocated over global index space, array was allocated over local index space (on this processor) """ @@ -478,15 +588,27 @@ def __init__(self, srcField, dstField, unMappedAction=IGNORE): """ Constuct regrid object - @param srcField the source field object of type EsmfStructField - @param dstField the destination field object of type EsmfStructField - @param srcMaskValues Value of masked cells in source - @param dstMaskValues Value of masked cells in destination - @param srcFrac Cell fractions on source grid (type EsmfStructField) - @param dstFrac Cell fractions on destination grid (type EsmfStructField) - @param regridMethod ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - @param unMappedAction ESMF.UnmappedAction.{IGNORE,ERROR} - @param ignoreDegenerate Ignore degenerate cells when checking inputs + + Parameters + ---------- + + srcField the source field object of type EsmfStructField + + dstField the destination field object of type EsmfStructField + + srcMaskValues Value of masked cells in source + + dstMaskValues Value of masked cells in destination + + srcFrac Cell fractions on source grid (type EsmfStructField) + + dstFrac Cell fractions on destination grid (type EsmfStructField) + + regridMethod ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + + unMappedAction ESMF.UnmappedAction.{IGNORE,ERROR} + + ignoreDegenerate Ignore degenerate cells when checking inputs """ self.srcField = srcField self.dstField = dstField @@ -554,9 +676,17 @@ def __init__(self, srcField, dstField, def getSrcAreas(self, rootPe): """ Get the src grid areas as used by conservative interpolation - @param rootPe None is local areas are returned, otherwise + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - @return numpy array or None if interpolation is not conservative + + Returns + ------- + + numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: return self.srcAreaField.data @@ -565,9 +695,17 @@ def getSrcAreas(self, rootPe): def getDstAreas(self, rootPe): """ Get the dst grid areas as used by conservative interpolation - @param rootPe None is local areas are returned, otherwise + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - @return numpy array or None if interpolation is not conservative + + Returns + ------- + + numpy array or None if interpolation is not conservative """ if self.srcAreaField is not None: return self.dstAreaField.data @@ -576,9 +714,17 @@ def getDstAreas(self, rootPe): def getSrcAreaFractions(self, rootPe): """ Get the source grid fraction areas as used by conservative interpolation - @param rootPe None is local areas are returned, otherwise + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - @return numpy array + + Returns + ------- + + numpy array """ if self.srcFracField is not None: # self.srcFracField.get_area() @@ -588,9 +734,17 @@ def getSrcAreaFractions(self, rootPe): def getDstAreaFractions(self, rootPe): """ Get the destination grid fraction areas as used by conservative interpolation - @param rootPe None is local areas are returned, otherwise + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered - @return numpy array + + Returns + ------- + + numpy array """ if self.dstFracField is not None: # self.dstFracField.get_area() @@ -600,11 +754,17 @@ def getDstAreaFractions(self, rootPe): def __call__(self, srcField=None, dstField=None, zero_region=None): """ Apply interpolation weights - @param srcField source field (or None if src field passed to + + Parameters + ---------- + + srcField source field (or None if src field passed to constructor is to be used) - @param dstField destination field (or None if dst field passed + + dstField destination field (or None if dst field passed to constructor is to be used) - @param zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) + + zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) """ if srcField is None: srcField = self.srcField diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index 5a95c2fd..de150dba 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -44,10 +44,20 @@ def getTensorProduct(axis, dim, dims): """ Convert an axis into a curvilinear coordinate by applying a tensor product - @param axis 1D array of coordinates - @param dim dimensional index of the above coordinate - @param dims sizes of all coordinates - @return coordinate values obtained by tensor product + + Parameters + ---------- + + axis 1D array of coordinates + + dim dimensional index of the above coordinate + + dims sizes of all coordinates + + Returns + ------- + + coordinate values obtained by tensor product """ return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) @@ -57,8 +67,16 @@ def makeCurvilinear(coords): """ Turn a mixture of axes and curvilinear coordinates into full curvilinear coordinates - @param coords list of coordinates - @return new list of coordinates and associated dimensions + + Parameters + ---------- + + coords list of coordinates + + Returns + ------- + + new list of coordinates and associated dimensions """ rank = len(coords) @@ -99,9 +117,18 @@ def makeCurvilinear(coords): def makeCoordsCyclic(coords, dims): """ Make coordinates cyclic - @params coords input coordinates - @params dims input dimensions - @return new, extended coordinates such that the longitudes cover the sphere + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + new, extended coordinates such that the longitudes cover the sphere and new dimensions """ # assume lon is the last coordinate!! @@ -156,9 +183,17 @@ def checkForCoordCut(coords, dims): Look for a cut in a coordinate system (e.g. tri-polar grid) Assume latitude is next to last coordinate and longitude is last coordinate!!! - @params coords input coordinates - @params dims input dimensions - @return True for cut found + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + True for cut found False for no cut """ @@ -253,11 +288,20 @@ def handleCoordsCut(coords, dims, bounds): """ Generate connectivity across a cut. e.g. from a tri-polar grid. Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates list of rank - @params coords input coordinates list of rank - @params dims input dimensions - @params bounds boundaries for each coordinate - @return extended coordinates such that there is an extra row containing + dims input dimensions + + bounds boundaries for each coordinate + + Returns + ------- + + extended coordinates such that there is an extra row containing connectivity information across the cut """ @@ -271,10 +315,20 @@ def handleCoordsCut(coords, dims, bounds): def getIndices(array, nlon, newI): """ Find indices where a cell edge matches for two cells - @param array Array of booleans - @param nlon number of longitudes - @param newI index row with connectivity to be updated - @return new coordinates, new dimensions, index row + + Parameters + ---------- + + array Array of booleans + + nlon number of longitudes + + newI index row with connectivity to be updated + + Returns + ------- + + new coordinates, new dimensions, index row """ for i in range(len(array)): # An edge @@ -309,17 +363,27 @@ def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, """ Constructor - @param src_grid source grid, a list of [x, y, ...] coordinates + Parameters + ---------- + + src_grid source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient - @param dst_grid destination grid, a list of [x, y, ...] coordinates - @param src_bounds list of cell bounding coordinates (to be used when + + dst_grid destination grid, a list of [x, y, ...] coordinates + + src_bounds list of cell bounding coordinates (to be used when handling a cut in coordinates) - @param mkCyclic Add a column to the right side of the grid to complete + + mkCyclic Add a column to the right side of the grid to complete a cyclic grid - @param handleCut Add a row to the top of grid to handle a cut for + + handleCut Add a row to the top of grid to handle a cut for grids such as the tri-polar grid - @param verbose print diagnostic messages - @note the grid coordinates can either be axes (rectilinear grid) or + + verbose print diagnostic messages + + + Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. """ @@ -489,7 +553,11 @@ def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, def getPeriodicities(self): """ Get the periodicity lengths of the coordinates - @return numpy array, values inf indicate no periodicity + + Returns + ------- + + numpy array, values inf indicate no periodicity """ coord_periodicity = numpy.zeros((self.rank,), numpy.float64) status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, @@ -529,10 +597,15 @@ def find(self, pattern, path): def setValidMask(self, inMask): """ Set valid mask array for the grid - @param inMask flat numpy array of type numpy.int32 or a valid cdms2 variable + + Parameters + ---------- + + inMask flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. 0 - invalid, 1 - valid data - @note This must be invoked before computing the weights, the + + Note: This must be invoked before computing the weights, the mask is a property of the grid (not the data). """ if self.weightsComputed: @@ -552,12 +625,19 @@ def setValidMask(self, inMask): def setMask(self, inDataOrMask): """ Set mask array. The mask is defined for nodes - @param inDataOrMask cdms2 array or flat mask array, + + Parameters + ---------- + + inDataOrMask cdms2 array or flat mask array, 0 - valid data 1 - invalid data - @note this definition is compatible with the numpy masked arrays - @note see setValidMask for the opposite definition - @note should be called before computing the weights + + Note: this definition is compatible with the numpy masked arrays + + Note: note see setValidMask for the opposite definition + + Note: should be called before computing the weights """ mask = None if hasattr(inDataOrMask, 'getmask'): @@ -574,9 +654,13 @@ def setMask(self, inDataOrMask): def computeWeights(self, nitermax=100, tolpos=1.e-2): """ Compute the the interpolation weights + + Parameters + ---------- + + nitermax max number of iterations - @param nitermax max number of iterations - @param tolpos max tolerance when locating destination positions in + tolpos max tolerance when locating destination positions in index space """ status = self.lib.nccf_compute_regrid_weights(self.regridid, @@ -588,9 +672,15 @@ def computeWeights(self, nitermax=100, tolpos=1.e-2): def apply(self, src_data_in, dst_data, missingValue=None): """ Apply interpolation - @param src_data data on source grid - @param dst_data data on destination grid - @param missingValue value that should be set for points falling outside the src domain, + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, pass None if these should not be touched. """ if not self.weightsComputed: @@ -701,9 +791,15 @@ def apply(self, src_data_in, dst_data, missingValue=None): def __call__(self, src_data, dst_data, missingValue=None): """ Apply interpolation (synonymous to apply method) - @param src_data data on source grid - @param dst_data data on destination grid - @param missingValue value that should be set for points falling outside the src domain, + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, pass None if these should not be touched. """ self.apply(src_data, dst_data, missingValue) @@ -714,7 +810,11 @@ def getNumValid(self): falling outside the source domain, more gnerally, points which could not be located on the source grid, reduce the number of valid points. - @return number of points + + Returns + ------- + + number of points """ res = c_int(-1) status = self.lib.nccf_inq_regrid_nvalid(self.regridid, @@ -725,7 +825,11 @@ def getNumValid(self): def getNumDstPoints(self): """ Return the number of points on the destination grid - @return number of points + + Returns + ------- + + number of points """ res = c_int(-1) status = self.lib.nccf_inq_regrid_ntargets(self.regridid, @@ -736,22 +840,38 @@ def getNumDstPoints(self): def getSrcGrid(self): """ Return the source grid - @return grid + + Returns + ------- + + grid """ return self.src_coords def getDstGrid(self): """ Return the destination grid - @return grid + + Returns + ------- + + grid """ return self.dst_coords def getIndicesAndWeights(self, dst_indices): """ Get the indices and weights for a single target location - @param dst_indices index set on the target grid - @return [index sets on original grid, weights] + + Parameters + ---------- + + dst_indices index set on the target grid + + Returns + ------- + + [index sets on original grid, weights] """ dinds = numpy.array(dst_indices) sinds = (c_int * 2**self.rank)() @@ -777,8 +897,16 @@ def _extend(self, src_data): """ Extend the data by padding a column and a row, depending on whether the grid was made cyclic and a fold was added or not - @param src_data input source data - @return extended source data (or source input data of no padding was applied) + + Parameters + ---------- + + src_data input source data + + Returns + ------- + + extended source data (or source input data of no padding was applied) """ # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] @@ -811,11 +939,22 @@ def _findIndices(self, targetPos, nitermax, tolpos, dindicesGuess): """ Find the floating point indices - @param targetPos numpy array of target positions - @param nitermax max number of iterations - @param tolpos max toelrance in positions - @param dindicesGuess guess for the floating point indices - @return indices, number of iterations, achieved tolerance + + Parameters + ---------- + + targetPos numpy array of target positions + + nitermax max number of iterations + + tolpos max toelrance in positions + + dindicesGuess guess for the floating point indices + + Returns + ------- + + indices, number of iterations, achieved tolerance """ posPtr = targetPos.ctypes.data_as(POINTER(c_double)) adjustFunc = None diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index 17438f26..cd65d9e9 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -32,8 +32,13 @@ class Horizontal: def __init__(self, ingrid, outgrid): """ Constructor for regridding class - @param ingrid cdms2, ndarray variable - @param outgrid cdms2, ndarray variable + + Parameters + ---------- + + ingrid cdms2, ndarray variable + + outgrid cdms2, ndarray variable """ inlat = ingrid.getLatitude() From 89bd18b54445ac63c753c372b72404896a007707 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 15:44:06 -0700 Subject: [PATCH 077/239] Changes made to Chapters 1-7 and sample data --- docs/source/conf.py | 21 +++ docs/source/index.rst | 2 + docs/source/manual/cdms_1.rst | 14 +- docs/source/manual/cdms_2.rst | 8 +- docs/source/manual/cdms_3.rst | 2 +- docs/source/manual/cdms_4.rst | 36 ++--- docs/source/manual/cdms_5.rst | 2 +- docs/source/manual/cdms_6.rst | 10 +- docs/source/manual/sample_data.rst | 244 ++++++++++++++--------------- 9 files changed, 181 insertions(+), 158 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2715fb80..5bf482bb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -12,6 +12,27 @@ # All configuration values have a default; values that are commented out # serve to show the default. +from future.standard_library import install_aliases +install_aliases() +import sys,os +sys.path.append(os.path.abspath('..')) +sys.path.append(os.path.abspath('../..')) +import mock +os.environ['READTHEDOCS']="True" +#MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] +MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif'] + +def side_effect(*args, **kwargs): + return mock.DEFAULT + +for mod_name in MOCK_MODULES: + m = mock.Mock() + m.return_value=3 + m.side_effect = side_effect + print mod_name + sys.modules[mod_name] = m + + import sys import os import shlex diff --git a/docs/source/index.rst b/docs/source/index.rst index 3cbec1f9..2c05c5d5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,6 +23,8 @@ CDMS documentation manual/cdms_7 manual/cdms_appendix manual/sample_data + avariable + axis # AbstractAxis # AbstractVariable diff --git a/docs/source/manual/cdms_1.rst b/docs/source/manual/cdms_1.rst index 73eb06ff..ceec858b 100644 --- a/docs/source/manual/cdms_1.rst +++ b/docs/source/manual/cdms_1.rst @@ -11,9 +11,9 @@ in climate analysis and simulation. CDMS is implemented as part of the Climate Data Analysis Tool (CDAT), which uses the Python language. The examples in this chapter assume some familiarity with the language and the Python -Numpy module (http://www.numpy.org). A number of excellent tutorials +Numpy module (https://www.numpy.org). A number of excellent tutorials on Python are available in books or on the Internet. For example, see -the `Python Foundation's homepage `__. +the `Python Foundation's homepage `__. Variables ^^^^^^^^^ @@ -36,7 +36,7 @@ velocity for time 0 (first index) can be calculated as: .. - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f1=cdms2.open("clt.nc") >>> u = f1('u') >>> v = f1('v') @@ -85,7 +85,7 @@ from file sample.nc into variable u: largevar=MV2.reshape(MV2.arange(400),(20,20),id="large variable").astype(MV2.float32) fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://cdat.llnl.gov/cdat/sample_data/'+file + url = 'https://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -99,7 +99,7 @@ from file sample.nc into variable u: .. - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/clt.nc" >>> f = cdms2.open('clt.nc') >>> u = f('u') @@ -305,7 +305,7 @@ Masking is covered in `Section 2.9 `__. See also the documentation of the Python Numpy and MA modules, on which ``cdms.MV`` is based, at -`http://www.numpy.org/ `__. +`https://www.numpy.org/ `__. File Variables ^^^^^^^^^^^^^^ @@ -669,7 +669,7 @@ SCRIP Regridder To interpolate between any lat-lon grid types, the SCRIP regridder may be used. The SCRIP package was developed at [Los Alamos National -Laboratory] (http://oceans11.lanl.gov/drupal/Models/OtherSoftware). +Laboratory] (https://oceans11.lanl.gov/drupal/Models/OtherSoftware). SCRIP is written in Fortran 90, and must be built and installed separately from the CDAT/CDMS installation. diff --git a/docs/source/manual/cdms_2.rst b/docs/source/manual/cdms_2.rst index 8f4b14f2..544fd9dd 100644 --- a/docs/source/manual/cdms_2.rst +++ b/docs/source/manual/cdms_2.rst @@ -14,7 +14,7 @@ Overview import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://cdat.llnl.gov/cdat/sample_data/'+file + url = 'https://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -200,7 +200,7 @@ Table Cdms Module Functions , " * Return ``1`` if ``s`` is a variable, ``0`` otherwise. See also: ``asVariable``." "``Dataset``", "``open(url,mode='r')``: Open or create a ``Dataset`` or ``CdmsFile``." , " * ``url`` is a Uniform Resource Locator, referring to a cdunif or XML file. If the URL has the extension '.xml' or '.cdml', a ``Dataset`` is returned, otherwise a ``CdmsFile`` is returned." - , " * If the URL protocol is 'http', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" + , " * If the URL protocol is 'https', the file must be a '.xml' or '.cdml' file, and the mode must be 'r'. If the protocol is 'file' or is omitted, a local file or dataset is opened. ``mode`` is the open mode. See `Open Modes <#table-open-modes>`__" , " * **Example**: Open an existing dataset: ``f = cdms.open('sampleset.xml')``" , " * **Example**: Create a netCDF file: ``f = cdms.open('newfile.nc','w')``" "``List``", "``order2index (axes, orderstring)``:" @@ -1052,7 +1052,7 @@ carries along the domain and attribute information where appropriate. MV provides the same set of functions as MV2. However, MV functions generate transient variables as results. Often this simplifies scripts that perform computation. MV2 is part of the Python Numpy package, -documented at http://www.numpy.org. +documented at https://www.numpy.org. MV can be imported with the command: @@ -1092,7 +1092,7 @@ corresponding MV2 function: ``allclose``, ``allequal``, ``make_mask_none``, ``mask_or``, ``masked``, ``pi``, ``put``, ``putmask``, ``rank``, ``ravel``, ``set_fill_value``, ``set_print_limit``, ``shape``, ``size``. See the documentation at -http://numpy.sourceforge.net for a description of these functions. +https://numpy.sourceforge.net for a description of these functions. diff --git a/docs/source/manual/cdms_3.rst b/docs/source/manual/cdms_3.rst index a387bb5f..c2df2de6 100644 --- a/docs/source/manual/cdms_3.rst +++ b/docs/source/manual/cdms_3.rst @@ -11,7 +11,7 @@ Time Types import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://cdat.llnl.gov/cdat/sample_data/'+file + url = 'https://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) diff --git a/docs/source/manual/cdms_4.rst b/docs/source/manual/cdms_4.rst index b3d11802..4f639f7f 100644 --- a/docs/source/manual/cdms_4.rst +++ b/docs/source/manual/cdms_4.rst @@ -23,7 +23,7 @@ CDMS Horizontal Regrider import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://cdat.llnl.gov/cdat/sample_data/'+file + url = 'https://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) @@ -41,8 +41,8 @@ variable regridded to the target grid: .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" >>> import cdms2 >>> import cdat_info >>> f1=cdms2.open("clt.nc") @@ -74,8 +74,8 @@ is generated at line 9, and the regridding is performed at line 10: .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/clt.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/clt.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc" >>> import cdms2 >>> from regrid2 import Regridder >>> f = cdms2.open("clt.nc") @@ -116,7 +116,7 @@ SCRIP Horizontal Regridder To interpolate between grids where one or both grids is non-rectangular, CDMS provides an interface to the SCRIP regridder package developed at -Los Alamos National Laboratory (http://oceans11.lanl.gov/trac/SCRIP). +Los Alamos National Laboratory (https://oceans11.lanl.gov/trac/SCRIP). Figure 3 illustrates the process: @@ -203,11 +203,11 @@ Next, run CDAT and create the regridder: .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" >>> # Import regrid package for regridder functions >>> import regrid2, cdms2 >>> # Read the regridder from the remapper file @@ -243,7 +243,7 @@ returns a new variable ``d`` regridded to that dimension. .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") >>> ta=f('ta') >>> ta.shape @@ -265,7 +265,7 @@ regridded to those axes. .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc" >>> f=cdms2.open("ta_ncep_87-6-88-4.nc") >>> ta=f('ta') >>> ta.shape @@ -525,8 +525,8 @@ Get a mask from a separate file, and set as the input grid mask. .. doctest:: - >>> # wget http://cdat.llnl.gov/cdat/sample_data/clt.nc - >>> # wget http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc + >>> # wget https://cdat.llnl.gov/cdat/sample_data/clt.nc + >>> # wget https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc >>> import cdms2 >>> from regrid2 import Regridder >>> # @@ -638,9 +638,9 @@ comparison. .. doctest:: - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" - >>> # wget http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc - >>> # wget "http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc" + >>> # wget https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc + >>> # wget "https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc" >>> import cdms2, regrid2, MV2 >>> # Open the SCRIP remapping file and data file >>> fremap = cdms2.open('rmp_T42_to_C02562_conserv.nc') diff --git a/docs/source/manual/cdms_5.rst b/docs/source/manual/cdms_5.rst index 09d0701d..b53c45ea 100644 --- a/docs/source/manual/cdms_5.rst +++ b/docs/source/manual/cdms_5.rst @@ -30,7 +30,7 @@ Plotting a Gridded Variable import requests fnames = [ 'clt.nc', 'geos-sample', 'xieArkin-T42.nc', 'remap_grid_POP43.nc', 'remap_grid_T42.nc', 'rmp_POP43_to_T42_conserv.n', 'rmp_T42_to_POP43_conserv.nc', 'ta_ncep_87-6-88-4.nc', 'rmp_T42_to_C02562_conserv.nc' ] for file in fnames: - url = 'http://cdat.llnl.gov/cdat/sample_data/'+file + url = 'https://cdat.llnl.gov/cdat/sample_data/'+file r = requests.get(url) open(file, 'wb').write(r.content) diff --git a/docs/source/manual/cdms_6.rst b/docs/source/manual/cdms_6.rst index c0c08364..ade53ebe 100644 --- a/docs/source/manual/cdms_6.rst +++ b/docs/source/manual/cdms_6.rst @@ -6,7 +6,7 @@ Introduction The Climate Data Markup Language (CDML) is the markup language used to represent metadata in CDMS. CDML is based on the W3C XML standard -(http://www.w3.org). This chapter defines the syntax of CDML. Read this +(https://www.w3.org). This chapter defines the syntax of CDML. Read this section if you will be building or maintaining a CDMS database. XML, the eXtensible Markup Language, makes it possible to define @@ -113,7 +113,7 @@ on the length of an identifier. CF Metadata Standard ~~~~~~~~~~~~~~~~~~~~ -`The CF metadata standard `__ defines a set +`The CF metadata standard `__ defines a set of conventions for usage of netCDF. This standard is supported by CDML. The document defines names and usage for metadata attributes. CF supersedes the GDT 1.3 standard. @@ -136,11 +136,11 @@ element. The prolog defines the XML version, and the Document Type Definition (DTD), a formal specification of the document syntax. -See http://www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML +See https://www.w3.org/TR/1998/REC-xml-19980210 for a formal definition of XML Version 1.0. -``prolog ::= `` +``prolog ::= `` Dataset Element ^^^^^^^^^^^^^^^ @@ -434,7 +434,7 @@ Dataset "sample" has two variables, and six axes. .. raw:: html - + [-90. -78. -66. -54. -42. -30. -18. -6. 6. 18. 30. 42. 54. 66. 78. 90.] diff --git a/docs/source/manual/sample_data.rst b/docs/source/manual/sample_data.rst index 7ab72453..c6685723 100644 --- a/docs/source/manual/sample_data.rst +++ b/docs/source/manual/sample_data.rst @@ -1,125 +1,125 @@ CDMS Sample Dataset ------------------- -* http://cdat.llnl.gov/cdat/sample_data/161122_RobertPincus_multiple_input4MIPs_radiation_RFMIP_UColorado-RFMIP-20161122_none.nc -* http://cdat.llnl.gov/cdat/sample_data/20160520.A_WCYCL1850.ne30_oEC.edison.alpha6_01_ANN_climo_Q.nc -* http://cdat.llnl.gov/cdat/sample_data/area_weights.nc -* http://cdat.llnl.gov/cdat/sample_data/BlueMarble.ppm -* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.001 -* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.002 -* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.003 -* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.004 -* http://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.005 -* http://cdat.llnl.gov/cdat/sample_data/CCTM_CONC.D1.001 -* http://cdat.llnl.gov/cdat/sample_data/cdtest10.xml -* http://cdat.llnl.gov/cdat/sample_data/cdtest13.xml -* http://cdat.llnl.gov/cdat/sample_data/cdtest14.xml -* http://cdat.llnl.gov/cdat/sample_data/clt2.nc -* http://cdat.llnl.gov/cdat/sample_data/clt.nc -* http://cdat.llnl.gov/cdat/sample_data/dar.meteo.mod.cam3.era.v31.h0.l3.nrstpt.cp.2000070100.2000080100.tau.12.36.nc -* http://cdat.llnl.gov/cdat/sample_data/dvtest1.dat -* http://cdat.llnl.gov/cdat/sample_data/dvtest1.dic -* http://cdat.llnl.gov/cdat/sample_data/era15_tas_sample.nc -* http://cdat.llnl.gov/cdat/sample_data/era40_sst_sample.nc -* http://cdat.llnl.gov/cdat/sample_data/era40_tas_sample.nc -* http://cdat.llnl.gov/cdat/sample_data/genutil_statistics.nc -* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.ctl -* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.gmp -* http://cdat.llnl.gov/cdat/sample_data/geo.1deg.grb -* http://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc -* http://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.ctl -* http://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.data -* http://cdat.llnl.gov/cdat/sample_data/GPCP_ANN_climo.nc -* http://cdat.llnl.gov/cdat/sample_data/gpcp_cdr_v23rB1_y2016_m08.nc -* http://cdat.llnl.gov/cdat/sample_data/GRIDCRO2D_D1.001 -* http://cdat.llnl.gov/cdat/sample_data/hadcrut2_sample.nc -* http://cdat.llnl.gov/cdat/sample_data/junk.nc -* http://cdat.llnl.gov/cdat/sample_data/MERRA_ANN_climo_SHUM.nc -* http://cdat.llnl.gov/cdat/sample_data/meshfill.nc -* http://cdat.llnl.gov/cdat/sample_data/model_ANN_climo.nc -* http://cdat.llnl.gov/cdat/sample_data/navy_land.nc -* http://cdat.llnl.gov/cdat/sample_data/netcdf4_compressed_example.nc -* http://cdat.llnl.gov/cdat/sample_data/obs_timeseries.nc -* http://cdat.llnl.gov/cdat/sample_data/prcp_1951.nc -* http://cdat.llnl.gov/cdat/sample_data/psl_6h.nc -* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.0E.nc -* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180E.nc -* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180W.nc -* http://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.60E.nc -* http://cdat.llnl.gov/cdat/sample_data/readonly.nc -* http://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc -* http://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc -* http://cdat.llnl.gov/cdat/sample_data/rlut_CERES_000001-000012_ac.nc -* http://cdat.llnl.gov/cdat/sample_data/rmp_C02562_to_T42_conserv.nc -* http://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc -* http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc -* http://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc -* http://cdat.llnl.gov/cdat/sample_data/sampleCurveGrid4.nc -* http://cdat.llnl.gov/cdat/sample_data/sampleGenGrid3.nc -* http://cdat.llnl.gov/cdat/sample_data/sample.nc -* http://cdat.llnl.gov/cdat/sample_data/sample_polar.nc -* http://cdat.llnl.gov/cdat/sample_data/sftbyrgn.nc -* http://cdat.llnl.gov/cdat/sample_data/sftlf_10x10.nc -* http://cdat.llnl.gov/cdat/sample_data/sftlf_ccsr.nc -* http://cdat.llnl.gov/cdat/sample_data/sftlf_dnm.nc -* http://cdat.llnl.gov/cdat/sample_data/sftlf_visus.nc -* http://cdat.llnl.gov/cdat/sample_data/so_Omon_ACCESS1-0_historical_r1i1p1_185001-185412_2timesteps.nc -* http://cdat.llnl.gov/cdat/sample_data/so_Omon_GISS-E2-R_historicalNat_r5i1p1_185001-187512_2timesteps.nc -* http://cdat.llnl.gov/cdat/sample_data/so_Omon_HadGEM2-CC_historical_r1i1p1_185912-186911_2timesteps.nc -* http://cdat.llnl.gov/cdat/sample_data/so_Omon_MPI-ESM-LR_1pctCO2_r1i1p1_185001-185912_2timesteps.nc -* http://cdat.llnl.gov/cdat/sample_data/stereographic.nc -* http://cdat.llnl.gov/cdat/sample_data/swan.four.nc -* http://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dat -* http://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dic -* http://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_6h.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1979.01-1979.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1980.01-1980.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1981.01-1981.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1982.01-1982.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1983.01-1983.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1984.01-1984.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a.xml -* http://cdat.llnl.gov/cdat/sample_data/tas_cru_1979.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1979.01-1979.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1980.01-1980.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1981.01-1981.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1982.01-1982.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1983.01-1983.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1984.01-1984.12.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a.xml -* http://cdat.llnl.gov/cdat/sample_data/tas_ecm_1979.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_gavg_rnl_ecm.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_GFDL-ESM2G_Amon_historical_r1i1p1_198501-200512-clim.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_mo_clim.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_mo.nc -* http://cdat.llnl.gov/cdat/sample_data/tas_ukmo_con.nc -* http://cdat.llnl.gov/cdat/sample_data/taylor.nc -* http://cdat.llnl.gov/cdat/sample_data/tdata.hdf -* http://cdat.llnl.gov/cdat/sample_data/test.2.bin -* http://cdat.llnl.gov/cdat/sample_data/test_anim.nc -* http://cdat.llnl.gov/cdat/sample_data/test.bin -* http://cdat.llnl.gov/cdat/sample_data/test.cdms -* http://cdat.llnl.gov/cdat/sample_data/test_col.asc -* http://cdat.llnl.gov/cdat/sample_data/testgrib2.ctl -* http://cdat.llnl.gov/cdat/sample_data/testgrib2.grib2 -* http://cdat.llnl.gov/cdat/sample_data/testgrib2.idx -* http://cdat.llnl.gov/cdat/sample_data/test_mesa_leak.nc -* http://cdat.llnl.gov/cdat/sample_data/testpp.pp -* http://cdat.llnl.gov/cdat/sample_data/test.xml -* http://cdat.llnl.gov/cdat/sample_data/thermo.nc -* http://cdat.llnl.gov/cdat/sample_data/th_yr.nc -* http://cdat.llnl.gov/cdat/sample_data/ts_da.nc -* http://cdat.llnl.gov/cdat/sample_data/u_2000.nc -* http://cdat.llnl.gov/cdat/sample_data/u_2001.nc -* http://cdat.llnl.gov/cdat/sample_data/u_2002.nc -* http://cdat.llnl.gov/cdat/sample_data/v_2000.nc -* http://cdat.llnl.gov/cdat/sample_data/v_2001.nc -* http://cdat.llnl.gov/cdat/sample_data/v_2002.nc -* http://cdat.llnl.gov/cdat/sample_data/vertical.nc -* http://cdat.llnl.gov/cdat/sample_data/vmro3_input4MIPs_ozone_DAMIP_CCMI-hist-stratO3-1-0_gr_185001_nco.nc -* http://cdat.llnl.gov/cdat/sample_data/wk_data.nc -* http://cdat.llnl.gov/cdat/sample_data/wk_results.nc -* http://cdat.llnl.gov/cdat/sample_data/wspd.coads.nc -* http://cdat.llnl.gov/cdat/sample_data/wspd.nc -* http://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc +* https://cdat.llnl.gov/cdat/sample_data/161122_RobertPincus_multiple_input4MIPs_radiation_RFMIP_UColorado-RFMIP-20161122_none.nc +* https://cdat.llnl.gov/cdat/sample_data/20160520.A_WCYCL1850.ne30_oEC.edison.alpha6_01_ANN_climo_Q.nc +* https://cdat.llnl.gov/cdat/sample_data/area_weights.nc +* https://cdat.llnl.gov/cdat/sample_data/BlueMarble.ppm +* https://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.001 +* https://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.002 +* https://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.003 +* https://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.004 +* https://cdat.llnl.gov/cdat/sample_data/CCTM_ACONC.D1.005 +* https://cdat.llnl.gov/cdat/sample_data/CCTM_CONC.D1.001 +* https://cdat.llnl.gov/cdat/sample_data/cdtest10.xml +* https://cdat.llnl.gov/cdat/sample_data/cdtest13.xml +* https://cdat.llnl.gov/cdat/sample_data/cdtest14.xml +* https://cdat.llnl.gov/cdat/sample_data/clt2.nc +* https://cdat.llnl.gov/cdat/sample_data/clt.nc +* https://cdat.llnl.gov/cdat/sample_data/dar.meteo.mod.cam3.era.v31.h0.l3.nrstpt.cp.2000070100.2000080100.tau.12.36.nc +* https://cdat.llnl.gov/cdat/sample_data/dvtest1.dat +* https://cdat.llnl.gov/cdat/sample_data/dvtest1.dic +* https://cdat.llnl.gov/cdat/sample_data/era15_tas_sample.nc +* https://cdat.llnl.gov/cdat/sample_data/era40_sst_sample.nc +* https://cdat.llnl.gov/cdat/sample_data/era40_tas_sample.nc +* https://cdat.llnl.gov/cdat/sample_data/genutil_statistics.nc +* https://cdat.llnl.gov/cdat/sample_data/geo.1deg.ctl +* https://cdat.llnl.gov/cdat/sample_data/geo.1deg.gmp +* https://cdat.llnl.gov/cdat/sample_data/geo.1deg.grb +* https://cdat.llnl.gov/cdat/sample_data/geos5-sample.nc +* https://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.ctl +* https://cdat.llnl.gov/cdat/sample_data/gfs.globl.b20121028_00z.e20121102_00z.data +* https://cdat.llnl.gov/cdat/sample_data/GPCP_ANN_climo.nc +* https://cdat.llnl.gov/cdat/sample_data/gpcp_cdr_v23rB1_y2016_m08.nc +* https://cdat.llnl.gov/cdat/sample_data/GRIDCRO2D_D1.001 +* https://cdat.llnl.gov/cdat/sample_data/hadcrut2_sample.nc +* https://cdat.llnl.gov/cdat/sample_data/junk.nc +* https://cdat.llnl.gov/cdat/sample_data/MERRA_ANN_climo_SHUM.nc +* https://cdat.llnl.gov/cdat/sample_data/meshfill.nc +* https://cdat.llnl.gov/cdat/sample_data/model_ANN_climo.nc +* https://cdat.llnl.gov/cdat/sample_data/navy_land.nc +* https://cdat.llnl.gov/cdat/sample_data/netcdf4_compressed_example.nc +* https://cdat.llnl.gov/cdat/sample_data/obs_timeseries.nc +* https://cdat.llnl.gov/cdat/sample_data/prcp_1951.nc +* https://cdat.llnl.gov/cdat/sample_data/psl_6h.nc +* https://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.0E.nc +* https://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180E.nc +* https://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.180W.nc +* https://cdat.llnl.gov/cdat/sample_data/ps.wrap.test.60E.nc +* https://cdat.llnl.gov/cdat/sample_data/readonly.nc +* https://cdat.llnl.gov/cdat/sample_data/remap_grid_POP43.nc +* https://cdat.llnl.gov/cdat/sample_data/remap_grid_T42.nc +* https://cdat.llnl.gov/cdat/sample_data/rlut_CERES_000001-000012_ac.nc +* https://cdat.llnl.gov/cdat/sample_data/rmp_C02562_to_T42_conserv.nc +* https://cdat.llnl.gov/cdat/sample_data/rmp_POP43_to_T42_conserv.nc +* https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_C02562_conserv.nc +* https://cdat.llnl.gov/cdat/sample_data/rmp_T42_to_POP43_conserv.nc +* https://cdat.llnl.gov/cdat/sample_data/sampleCurveGrid4.nc +* https://cdat.llnl.gov/cdat/sample_data/sampleGenGrid3.nc +* https://cdat.llnl.gov/cdat/sample_data/sample.nc +* https://cdat.llnl.gov/cdat/sample_data/sample_polar.nc +* https://cdat.llnl.gov/cdat/sample_data/sftbyrgn.nc +* https://cdat.llnl.gov/cdat/sample_data/sftlf_10x10.nc +* https://cdat.llnl.gov/cdat/sample_data/sftlf_ccsr.nc +* https://cdat.llnl.gov/cdat/sample_data/sftlf_dnm.nc +* https://cdat.llnl.gov/cdat/sample_data/sftlf_visus.nc +* https://cdat.llnl.gov/cdat/sample_data/so_Omon_ACCESS1-0_historical_r1i1p1_185001-185412_2timesteps.nc +* https://cdat.llnl.gov/cdat/sample_data/so_Omon_GISS-E2-R_historicalNat_r5i1p1_185001-187512_2timesteps.nc +* https://cdat.llnl.gov/cdat/sample_data/so_Omon_HadGEM2-CC_historical_r1i1p1_185912-186911_2timesteps.nc +* https://cdat.llnl.gov/cdat/sample_data/so_Omon_MPI-ESM-LR_1pctCO2_r1i1p1_185001-185912_2timesteps.nc +* https://cdat.llnl.gov/cdat/sample_data/stereographic.nc +* https://cdat.llnl.gov/cdat/sample_data/swan.four.nc +* https://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dat +* https://cdat.llnl.gov/cdat/sample_data/ta_300_850_PCM_O_mm_xy_wa_r0000_0000.dic +* https://cdat.llnl.gov/cdat/sample_data/ta_ncep_87-6-88-4.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_6h.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1979.01-1979.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1980.01-1980.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1981.01-1981.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1982.01-1982.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1983.01-1983.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a_1984.01-1984.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ccsr-95a.xml +* https://cdat.llnl.gov/cdat/sample_data/tas_cru_1979.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1979.01-1979.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1980.01-1980.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1981.01-1981.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1982.01-1982.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1983.01-1983.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a_1984.01-1984.12.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_dnm-95a.xml +* https://cdat.llnl.gov/cdat/sample_data/tas_ecm_1979.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_gavg_rnl_ecm.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_GFDL-ESM2G_Amon_historical_r1i1p1_198501-200512-clim.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_mo_clim.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_mo.nc +* https://cdat.llnl.gov/cdat/sample_data/tas_ukmo_con.nc +* https://cdat.llnl.gov/cdat/sample_data/taylor.nc +* https://cdat.llnl.gov/cdat/sample_data/tdata.hdf +* https://cdat.llnl.gov/cdat/sample_data/test.2.bin +* https://cdat.llnl.gov/cdat/sample_data/test_anim.nc +* https://cdat.llnl.gov/cdat/sample_data/test.bin +* https://cdat.llnl.gov/cdat/sample_data/test.cdms +* https://cdat.llnl.gov/cdat/sample_data/test_col.asc +* https://cdat.llnl.gov/cdat/sample_data/testgrib2.ctl +* https://cdat.llnl.gov/cdat/sample_data/testgrib2.grib2 +* https://cdat.llnl.gov/cdat/sample_data/testgrib2.idx +* https://cdat.llnl.gov/cdat/sample_data/test_mesa_leak.nc +* https://cdat.llnl.gov/cdat/sample_data/testpp.pp +* https://cdat.llnl.gov/cdat/sample_data/test.xml +* https://cdat.llnl.gov/cdat/sample_data/thermo.nc +* https://cdat.llnl.gov/cdat/sample_data/th_yr.nc +* https://cdat.llnl.gov/cdat/sample_data/ts_da.nc +* https://cdat.llnl.gov/cdat/sample_data/u_2000.nc +* https://cdat.llnl.gov/cdat/sample_data/u_2001.nc +* https://cdat.llnl.gov/cdat/sample_data/u_2002.nc +* https://cdat.llnl.gov/cdat/sample_data/v_2000.nc +* https://cdat.llnl.gov/cdat/sample_data/v_2001.nc +* https://cdat.llnl.gov/cdat/sample_data/v_2002.nc +* https://cdat.llnl.gov/cdat/sample_data/vertical.nc +* https://cdat.llnl.gov/cdat/sample_data/vmro3_input4MIPs_ozone_DAMIP_CCMI-hist-stratO3-1-0_gr_185001_nco.nc +* https://cdat.llnl.gov/cdat/sample_data/wk_data.nc +* https://cdat.llnl.gov/cdat/sample_data/wk_results.nc +* https://cdat.llnl.gov/cdat/sample_data/wspd.coads.nc +* https://cdat.llnl.gov/cdat/sample_data/wspd.nc +* https://cdat.llnl.gov/cdat/sample_data/xieArkin-T42.nc From 66d42895b8cd5f7f9f9abcc8ccd08d5426b24808 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 17:43:05 -0700 Subject: [PATCH 078/239] fix API documentation --- Lib/bindex.py | 2 +- Lib/cdscan.py | 0 Lib/dataset.py | 15 ++++++++------- Lib/fvariable.py | 2 +- Lib/hgrid.py | 3 ++- Script/myproxy_logon.py | 0 ci-support/checkout_merge_commit.sh | 0 ci-support/circle.sh | 0 ci-support/conda_upload.sh | 0 docs/createRST.sh | 0 docs/source/conf.py | 15 ++++++++++++--- docs/source/index.rst | 3 +-- docs/source/manual/images/generic_grid.jpg | Bin docs/source2/manual/images/generic_grid.jpg | Bin regrid2/Lib/crossSection.py | 3 ++- regrid2/Lib/horizontal.py | 3 ++- regrid2/Lib/pressure.py | 3 ++- regrid2/Lib/scrip.py | 3 ++- regrid2/Src/_regridmodule.c | 0 test_condaforge.sh | 0 tests/test_cdmsfile_io.py | 0 tests/test_cdmsfile_ma_rw.py | 0 tests/test_cdmsfile_rw.py | 0 tests/test_cdscan.py | 0 tests/test_curvilinear_grid.py | 0 tests/test_dataset_filemap.py | 0 tests/test_dataset_io.py | 0 tests/test_regrid2.py | 0 tests/test_tvariable.py | 0 tests/test_variable_subselection.py | 0 30 files changed, 33 insertions(+), 19 deletions(-) mode change 100755 => 100644 Lib/cdscan.py mode change 100755 => 100644 Script/myproxy_logon.py mode change 100755 => 100644 ci-support/checkout_merge_commit.sh mode change 100755 => 100644 ci-support/circle.sh mode change 100755 => 100644 ci-support/conda_upload.sh mode change 100755 => 100644 docs/createRST.sh mode change 100755 => 100644 docs/source/manual/images/generic_grid.jpg mode change 100755 => 100644 docs/source2/manual/images/generic_grid.jpg mode change 100755 => 100644 regrid2/Src/_regridmodule.c mode change 100755 => 100644 test_condaforge.sh mode change 100755 => 100644 tests/test_cdmsfile_io.py mode change 100755 => 100644 tests/test_cdmsfile_ma_rw.py mode change 100755 => 100644 tests/test_cdmsfile_rw.py mode change 100755 => 100644 tests/test_cdscan.py mode change 100755 => 100644 tests/test_curvilinear_grid.py mode change 100755 => 100644 tests/test_dataset_filemap.py mode change 100755 => 100644 tests/test_dataset_io.py mode change 100755 => 100644 tests/test_regrid2.py mode change 100755 => 100644 tests/test_tvariable.py mode change 100755 => 100644 tests/test_variable_subselection.py diff --git a/Lib/bindex.py b/Lib/bindex.py index 572bd4a2..a1687558 100644 --- a/Lib/bindex.py +++ b/Lib/bindex.py @@ -3,7 +3,7 @@ """Bin index for non-rectilinear grids""" -from . import _bindex +import _bindex import numpy diff --git a/Lib/cdscan.py b/Lib/cdscan.py old mode 100755 new mode 100644 diff --git a/Lib/dataset.py b/Lib/dataset.py index e5348ef2..7bbcb019 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -4,7 +4,8 @@ """ CDMS dataset and file objects""" from __future__ import print_function from .error import CDMSError -from . import Cdunif +#from . import Cdunif +import Cdunif import numpy from . import cdmsNode import os @@ -1179,11 +1180,11 @@ def getLogicalCollectionDN(self, base=None): return dn def getVariable(self, id): - "Get the variable object with the given id. + """Get the variable object with the given id. Returns ------- - None if not found." + None if not found.""" return self.variables.get(id) def getVariables(self, spatial=0): @@ -1200,19 +1201,19 @@ def getVariables(self, spatial=0): return retval def getAxis(self, id): - "Get the axis object with the given id. + """Get the axis object with the given id. Returns ------- - None if not found." + None if not found.""" return self.axes.get(id) def getGrid(self, id): - "Get the grid object with the given id. + """Get the grid object with the given id. Returns ------- - None if not found." + None if not found.""" return self.grids.get(id) def __repr__(self): diff --git a/Lib/fvariable.py b/Lib/fvariable.py index c9b7024b..9900db82 100644 --- a/Lib/fvariable.py +++ b/Lib/fvariable.py @@ -7,7 +7,7 @@ from .variable import DatasetVariable from .error import CDMSError from .sliceut import reverseSlice -from .Cdunif import CdunifError +from cdms2.Cdunif import CdunifError FileClosed = "Cannot read from closed file, variable: " FileClosedWrite = "Cannot write to a closed file, variable: " diff --git a/Lib/hgrid.py b/Lib/hgrid.py index e0a5a5d2..6a7c07e8 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -13,8 +13,9 @@ from .grid import AbstractGrid, LongitudeType, LatitudeType, CoordTypeToLoc from .axis import TransientVirtualAxis from .axis import getAutoBounds, allclose +import _bindex from . import bindex -from . import _bindex +#from . import _bindex from functools import reduce import copy diff --git a/Script/myproxy_logon.py b/Script/myproxy_logon.py old mode 100755 new mode 100644 diff --git a/ci-support/checkout_merge_commit.sh b/ci-support/checkout_merge_commit.sh old mode 100755 new mode 100644 diff --git a/ci-support/circle.sh b/ci-support/circle.sh old mode 100755 new mode 100644 diff --git a/ci-support/conda_upload.sh b/ci-support/conda_upload.sh old mode 100755 new mode 100644 diff --git a/docs/createRST.sh b/docs/createRST.sh old mode 100755 new mode 100644 diff --git a/docs/source/conf.py b/docs/source/conf.py index 5bf482bb..75f60bca 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,12 +15,12 @@ from future.standard_library import install_aliases install_aliases() import sys,os -sys.path.append(os.path.abspath('..')) +sys.path.append(os.path.abspath('../../regrid2')) sys.path.append(os.path.abspath('../..')) import mock os.environ['READTHEDOCS']="True" #MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] -MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif'] +MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip'] def side_effect(*args, **kwargs): return mock.DEFAULT @@ -32,6 +32,14 @@ def side_effect(*args, **kwargs): print mod_name sys.modules[mod_name] = m +print os.getcwd() + +if os.path.isdir('../../regrid2/Lib'): + os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') + +open("../../Lib/git.py", 'wb').close() +open("../../regrid2/Libregrid/git.py", 'wb').close() + import sys import os @@ -74,6 +82,7 @@ def side_effect(*args, **kwargs): 'easydev.copybutton', 'sphinx.ext.todo', 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', 'sphinx.ext.graphviz', 'sphinx.ext.doctest', 'sphinx.ext.napoleon' @@ -153,7 +162,7 @@ def side_effect(*args, **kwargs): # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. diff --git a/docs/source/index.rst b/docs/source/index.rst index 2c05c5d5..14bdf22e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,8 +23,7 @@ CDMS documentation manual/cdms_7 manual/cdms_appendix manual/sample_data - avariable - axis + API # AbstractAxis # AbstractVariable diff --git a/docs/source/manual/images/generic_grid.jpg b/docs/source/manual/images/generic_grid.jpg old mode 100755 new mode 100644 diff --git a/docs/source2/manual/images/generic_grid.jpg b/docs/source2/manual/images/generic_grid.jpg old mode 100755 new mode 100644 diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py index 8a859e80..cf23b45d 100644 --- a/regrid2/Lib/crossSection.py +++ b/regrid2/Lib/crossSection.py @@ -3,7 +3,8 @@ import cdms2 import numpy import copy -from . import _regrid +#from . import _regrid +import regrid2._regrid as _regrid from .error import RegridError diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index cd65d9e9..67d673f4 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -2,7 +2,8 @@ import numpy import copy -from . import _regrid +#from . import _regrid +import regrid2._regrid as _regrid from .error import RegridError import warnings import cdms2 diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py index 6de24914..fb79a9e2 100644 --- a/regrid2/Lib/pressure.py +++ b/regrid2/Lib/pressure.py @@ -1,7 +1,8 @@ # Automatically adapted for numpy.oldnumeric Aug 02, 2007 by import cdms2 import numpy -from . import _regrid +#from . import _regrid +import regrid2._regrid as _regrid from .error import RegridError import copy diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 13eec1ef..5a052700 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -1,7 +1,8 @@ # Automatically adapted for numpy.oldnumeric Aug 02, 2007 by import cdms2 -from . import _scrip +#from . import _scrip +import regrid2._scrip as _scrip from .error import RegridError import numpy from functools import reduce diff --git a/regrid2/Src/_regridmodule.c b/regrid2/Src/_regridmodule.c old mode 100755 new mode 100644 diff --git a/test_condaforge.sh b/test_condaforge.sh old mode 100755 new mode 100644 diff --git a/tests/test_cdmsfile_io.py b/tests/test_cdmsfile_io.py old mode 100755 new mode 100644 diff --git a/tests/test_cdmsfile_ma_rw.py b/tests/test_cdmsfile_ma_rw.py old mode 100755 new mode 100644 diff --git a/tests/test_cdmsfile_rw.py b/tests/test_cdmsfile_rw.py old mode 100755 new mode 100644 diff --git a/tests/test_cdscan.py b/tests/test_cdscan.py old mode 100755 new mode 100644 diff --git a/tests/test_curvilinear_grid.py b/tests/test_curvilinear_grid.py old mode 100755 new mode 100644 diff --git a/tests/test_dataset_filemap.py b/tests/test_dataset_filemap.py old mode 100755 new mode 100644 diff --git a/tests/test_dataset_io.py b/tests/test_dataset_io.py old mode 100755 new mode 100644 diff --git a/tests/test_regrid2.py b/tests/test_regrid2.py old mode 100755 new mode 100644 diff --git a/tests/test_tvariable.py b/tests/test_tvariable.py old mode 100755 new mode 100644 diff --git a/tests/test_variable_subselection.py b/tests/test_variable_subselection.py old mode 100755 new mode 100644 From 2e9414a6f9d0b179c31c938703ce2b6ee8066e45 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 17:47:08 -0700 Subject: [PATCH 079/239] rename regrid2 directory and delete print message --- docs/Makefile | 1 + docs/source/conf.py | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 61c88bb2..b4df31a1 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -55,6 +55,7 @@ html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + @mv ../regrid2/Libregrid/ ../regrid2/Lib dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml diff --git a/docs/source/conf.py b/docs/source/conf.py index 75f60bca..2e93a959 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,11 +29,8 @@ def side_effect(*args, **kwargs): m = mock.Mock() m.return_value=3 m.side_effect = side_effect - print mod_name sys.modules[mod_name] = m -print os.getcwd() - if os.path.isdir('../../regrid2/Lib'): os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') From 02b91951d5bd72a090c89c485a641f995b45cfd1 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 18:01:55 -0700 Subject: [PATCH 080/239] add module API files --- docs/source/API.rst | 19 +++++++++++++++++++ docs/source/avariable.rst | 7 +++++++ docs/source/axis.rst | 7 +++++++ docs/source/fvariable.rst | 7 +++++++ docs/source/horizontal.rst | 7 +++++++ 5 files changed, 47 insertions(+) create mode 100644 docs/source/API.rst create mode 100644 docs/source/avariable.rst create mode 100644 docs/source/axis.rst create mode 100644 docs/source/fvariable.rst create mode 100644 docs/source/horizontal.rst diff --git a/docs/source/API.rst b/docs/source/API.rst new file mode 100644 index 00000000..8b5dfd83 --- /dev/null +++ b/docs/source/API.rst @@ -0,0 +1,19 @@ +API +=== +.. currentmodule:: Lib + +Classes +------- +.. autosummary:: + + avariable + axis + fvariable + +.. currentmodule:: Libregrid + +Regridder +--------- +.. autosummary:: + horizontal + diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst new file mode 100644 index 00000000..5a4ae51e --- /dev/null +++ b/docs/source/avariable.rst @@ -0,0 +1,7 @@ +avariable +========= + +.. automodule:: Lib.avariable + :members: + + diff --git a/docs/source/axis.rst b/docs/source/axis.rst new file mode 100644 index 00000000..7cbe4f35 --- /dev/null +++ b/docs/source/axis.rst @@ -0,0 +1,7 @@ +axis +==== + +.. automodule:: Lib.axis + :members: + + diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst new file mode 100644 index 00000000..14e69707 --- /dev/null +++ b/docs/source/fvariable.rst @@ -0,0 +1,7 @@ +fvariable +========= + +.. automodule:: Lib.fvariable + :members: + + diff --git a/docs/source/horizontal.rst b/docs/source/horizontal.rst new file mode 100644 index 00000000..288f3c09 --- /dev/null +++ b/docs/source/horizontal.rst @@ -0,0 +1,7 @@ +regrid2-horizontal +================== + +.. automodule:: Libregrid.horizontal + :members: + + From d12d82f2f31b3dbc7eaa1f6260f80488dca38075 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 18:04:08 -0700 Subject: [PATCH 081/239] add future and mock requirements --- docs/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index e48f7c2c..f0ee57ae 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,3 @@ easydev +future +mock From adf2dcbcbab417cd0f8ed65a573e87e81751e682 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 16 Apr 2018 18:07:56 -0700 Subject: [PATCH 082/239] get cwd for readthedocs --- docs/source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2e93a959..fb72cd1e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -34,6 +34,7 @@ def side_effect(*args, **kwargs): if os.path.isdir('../../regrid2/Lib'): os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') +print os.getcwd() open("../../Lib/git.py", 'wb').close() open("../../regrid2/Libregrid/git.py", 'wb').close() From 3724fb7c5f0ec9381a01fb6a727d73c35548b3cc Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 18 Apr 2018 15:42:31 -0700 Subject: [PATCH 083/239] Changes made to API --- Lib/avariable.py | 77 ++++++++++++++++++++++--------- Lib/axis.py | 9 +++- Lib/dataset.py | 51 ++++++++++++++++++-- Lib/grid.py | 110 ++++++++++++++++++++++++++------------------ docs/source/API.rst | 21 ++++++++- 5 files changed, 195 insertions(+), 73 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 4927b80d..653ced15 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -43,6 +43,8 @@ def getMinHorizontalMask(var): var CDMS variable with a mask + -: None + Return ------ mask array or None if order 'x' and 'y' were not found @@ -421,14 +423,22 @@ def getConvention(self): # A child class may want to override this def getAxis(self, n): """Get the n-th axis. + Parameters ---------- - n: - Axis number + n: + Axis number + + _: None + + + Returns ------- + if n < 0: n = n + self.rank() - self.getDomain()[n][0]""" + self.getDomain()[n][0] + """ if n < 0: n = n + self.rank() return self.getDomain()[n][0] @@ -440,6 +450,8 @@ def getAxisIndex(self, axis_spec): ---------- axis_spec: + _: None + Returns ------- the axis index or -1 if no match is found. @@ -507,14 +519,18 @@ def getGrid(self): def getMissing(self, asarray=0): """ - Parameters - ---------- - asarray : - '0' : scalar - '1' : numpy array - Return - ------ - the missing value as a scalar, or as a numpy array if asarray==1""" + Parameters + ---------- + + asarray: + + '0': scalar + + '1': numpy array + + Return + ------ + the missing value as a scalar, or as a numpy array if asarray==1""" if hasattr(self, 'missing_value'): try: @@ -551,6 +567,8 @@ def setMissing(self, value): value scalar, a single-valued numpy array, or None. + _: None + Note ---- The value is cast to the same type as the variable.""" @@ -684,8 +702,12 @@ def getOrder(self, ids=0): """ Parameters ---------- - id: + + id: 0 or 1 + + _: None + Returns ------- the order string, such as t, z, y, x (time, level, lat, lon). @@ -816,7 +838,7 @@ def getSlice(self, *specs, **keys): """getSlice takes arguments of the following forms and produces a return array. - Parameter + Parameters --------- raw: if set to 1, return numpy.ma only @@ -872,23 +894,28 @@ def expertSlice(self, slicelist): raise CDMSError(NotImplemented + 'expertSlice') def getRegion(self, *specs, **keys): - """ Read a region of data. A region is an n-dimensional rectangular region specified in coordinate space. - + """ + Read a region of data. A region is an n-dimensional rectangular region specified in coordinate space. + Parameters ---------- - slice - is an argument list, each item of which has one of the following forms: - * x, where x is a scalar + + Slice: is an argument list, each item of which has one of the following forms + + * x, where x is a scalar * Map the scalar to the index of the closest coordinate value. - * (x, y) + * (x, y) * Map the half-open coordinate interval [x,y) to index interval. - * (x, y, 'cc') + * (x, y, 'cc') * Map the closed interval [x,y] to index interval. Other options are 'oo' (open), 'oc' (open on the left), and 'co' (open on the right, the default). - * (x, y, 'co', cycle) + * (x, y, 'co', cycle) * Map the coordinate interval with wraparound. If no cycle is specified, wraparound will occur iff axis.isCircular() is true. + _: None + + Ellipsis Represents the full range of all dimensions bracketed by non-Ellipsis items. None, colon @@ -1180,6 +1207,8 @@ def reorder(self, order): order: string can be "tzyx" with all possible axes permutation. + _: None + Returns ------- New reordered variable. @@ -1657,7 +1686,11 @@ def decode(self, ar): Parameter --------- - ar is a masked array, scalar, or numpy.ma.masked.""" + + ar is a masked array, scalar, or numpy.ma.masked. + _: None + + """ resulttype = self._decodedType() if hasattr(self, 'scale_factor'): diff --git a/Lib/axis.py b/Lib/axis.py index beb34059..a99486cc 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -701,7 +701,11 @@ def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): """ Parameters ---------- - ax1, ax2: array_like + ax1, ax2: + + array_like + + _: None Returns ------- @@ -2707,6 +2711,9 @@ def take(ax, indices): Returns ------- axis: TransientAxis + + _: None + The return array has the same type of ax. """ diff --git a/Lib/dataset.py b/Lib/dataset.py index 7bbcb019..beb82df9 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -117,6 +117,8 @@ def setCompressionWarnings(value=None): value: * 0/1 False/True 'no'/'yes' or None (which sets it to the opposite + _: None + Returns ------- Return set value. @@ -149,11 +151,16 @@ def setCompressionWarnings(value=None): def setNetcdfUseNCSwitchModeFlag(value): """Tells cdms2 to switch constantly between netcdf define/write modes. + Parameters ---------- + value: 0/1, False/True. + _: None + + Returns ------- No return value. @@ -176,6 +183,8 @@ def setNetcdfUseParallelFlag(value): value: 0/1, False/True. + _: None + Returns ------- No return value. @@ -229,6 +238,8 @@ def setNetcdf4Flag(value): value: 0/1, False/True. + _: None + Returns ------- No return value. @@ -249,6 +260,8 @@ def setNetcdfClassicFlag(value): value: 0/1, False/True. + _: None + Returns ------- No return value. @@ -268,6 +281,8 @@ def setNetcdfShuffleFlag(value): ---------- value: 0/1, False/True. + + _: None Returns ------- No return value. @@ -287,6 +302,9 @@ def setNetcdfDeflateFlag(value): ---------- value: 0/1, False/True. + + _: None + Returns ------- No return value. @@ -307,6 +325,8 @@ def setNetcdfDeflateLevelFlag(value): value: Deflation Level 1-9. + _: None + Returns ------- No return value. @@ -334,6 +354,9 @@ def getNetcdfUseParallelFlag(): ---------- value: 0/1, False/True. + + _: None + Returns ------- No return value. @@ -431,6 +454,7 @@ def createDataset(path, template=None): ---------- path: is the XML file name, or netCDF filename for simple file creation. + template: is a string template for the datafile(s), for dataset creation. @@ -575,6 +599,7 @@ def parselist(text, f): Input String. f: function which parses A and returns (A, nconsumed). + Returns ------- Parser results. @@ -614,6 +639,9 @@ def parseIndexList(text): text: i,j,k,l,... are indices or '-', and path is a filename. Coerce the indices to integers. + + _: None + Returns ------- Parser results. @@ -2301,6 +2329,9 @@ def write_it_yourself(self, obj): ---------- obj: object containing `writeg`, `writeToFile` or `write` method. + + _: None + Returns ------- Nothing is returned. """ @@ -2321,6 +2352,8 @@ def getVariable(self, id): ---------- id: str id of the variable to get + + _: None Returns ------- @@ -2331,12 +2364,15 @@ def getVariable(self, id): return self.variables.get(id) def getVariables(self, spatial=0): - """Get a list of variable objects. + """ + Get a list of variable objects. + Parameters ---------- - spatial: - If spatial=1 or True, only return those axes defined on latitude - or longitude, excluding weights and bounds + spatial: If spatial=1 or True, only return those axes defined on latitude + or longitude, excluding weights and bounds + + _: None Returns ------- @@ -2359,6 +2395,9 @@ def getAxis(self, id): ---------- id: id of the axis to get + + _: None + Returns -------- file axis @@ -2374,6 +2413,8 @@ def getGrid(self, id): id: id of the grid to get + _: None + Returns ------- file axis @@ -2388,6 +2429,8 @@ def getBoundsAxis(self, n, boundid=None): n: bound id (bound_%d) + _: None + Returns ------- bounds axis diff --git a/Lib/grid.py b/Lib/grid.py index 95a998c7..5da709e3 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -101,12 +101,15 @@ def createGaussianGrid(nlats, xorigin=0.0, order="yx"): Parameters ---------- - 'nlats' + nlats: is the number of latitudes. - 'xorigin' - is the origin of the longitude axis. - 'order' - is either "yx" or "xy" """ + + xorigin: + is the origin of the longitude axis + + order: + is either "yx" or "xy" + """ lat = createGaussianAxis(nlats) nlons = 2 * nlats lon = createUniformLongitudeAxis(xorigin, nlons, 360.0 / float(nlons)) @@ -140,31 +143,28 @@ def setRegionSpecs(grid, coordSpec, coordType, resultSpec): Parameters ---------- - 'grid' + grid: is the grid object to be associated with the region. - 'coordSpec' + coordSpec: is a coordinate specification, having one of the forms: - x - (x,y) - (x,y,'co') - (x,y,'co',cycle) - ':' - None - - 'coordType' - is one of CoordinateTypes - 'resultSpec' - is a list of 4-tuples of the form (x,y,'co',cycle), or None - if no spec for the corresponding dimension type. - The function sets the appropriate coordinate in resultSpec, - in the canonical form (x,y,'co',cycle). A CDMSError exception - is raised if the entry in resultSpec is not None. - - Note - ---- - - that time coordinate types are not permitted. + x + (x,y) + (x,y,'co') + (x,y,'co',cycle) + ':' + None + + coordType: + is one of CoordinateTypes + resultSpec: + is a list of 4-tuples of the form (x,y,'co',cycle), or None + if no spec for the corresponding dimension type. + The function sets the appropriate coordinate in resultSpec, + in the canonical form (x,y,'co',cycle). A CDMSError exception + is raised if the entry in resultSpec is not None. + + Note: that time coordinate types are not permitted. """ if (coordSpec is None) or (coordSpec == ':'): @@ -298,8 +298,12 @@ class AbstractRectGrid(AbstractGrid): Parameters ---------- - AbstractRectGrid defines the interface for rectilinear grids: - grids which can be decomposed into 1-D latitude and longitude axes + AbstractRectGrid: + defines the interface for rectilinear grids + + grids: + which can be decomposed into 1-D latitude and longitude axes + """ gridtypes = ['gaussian', 'uniform', 'equalarea', 'generic'] @@ -663,25 +667,32 @@ def size(self): return ny * nx def writeScrip(self, cufile, gridTitle=None): - """Write a grid to a SCRIP file. + """ + Write a grid to a SCRIP file. Parameters ---------- + cufile: + is a Cdunif file, NOT a CDMS file. - cufile is a Cdunif file, NOT a CDMS file. + gridtitle: + is a string identifying the grid. - gridtitle is a string identifying the grid. """ cgrid = self.toCurveGrid() cgrid.writeScrip(cufile, gridTitle) def toCurveGrid(self, gridid=None): - """Convert to a curvilinear grid. - + """ + Convert to a curvilinear grid. + Parameters - ---------- + ---------- + gridid: + is the string identifier of the resulting curvilinear grid object. + + _: None - 'gridid' is the string identifier of the resulting curvilinear grid object. """ from .coord import TransientVirtualAxis, TransientAxis2D @@ -924,25 +935,34 @@ def isGrid(grid): """ Is grid a grid? - Parameter - -------- + Parameters + ---------- + + grid cdms2: + contruct to be examined + + _: None - @param grid cdms2 contruct to be examined """ return isinstance(grid, AbstractGrid) def writeScripGrid(path, grid, gridTitle=None): - """Write a grid to a SCRIP grid file. + """ + Write a grid to a SCRIP grid file. + + Parameters + ---------- - Parameter - --------- + path: + is the path of the SCRIP file to be created. - path is the path of the SCRIP file to be created. + grid: + is a CDMS grid object. - grid is a CDMS grid object. + gridTitle: + is a string ID for the grid. - gridTitle is a string ID for the grid. """ import Cdunif diff --git a/docs/source/API.rst b/docs/source/API.rst index 8b5dfd83..266d3294 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -5,10 +5,29 @@ API Classes ------- .. autosummary:: - avariable axis fvariable + bindex + variable + cache + CDML + cdurllib + cdurlparse + cdxmllib + convention + coord + cudsinterface + database + dataset + forecast + gengrid + grid + hgrid + gsStaticVariable + gsTimeVariable + + .. currentmodule:: Libregrid From e252f48f7cfb06e9717fc98d7e41ec9b63b1af26 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 20 Apr 2018 10:34:56 -0700 Subject: [PATCH 084/239] Changes made to API --- Lib/axis.py | 17 ++++++----- Lib/coord.py | 6 ++-- Lib/cudsinterface.py | 5 ++++ Lib/dataset.py | 9 +++--- Lib/forecast.py | 5 +++- Lib/hgrid.py | 67 +++++++++++++++++++++++++++++--------------- docs/source/API.rst | 27 ++++++++++++++++-- regrid2/Lib/esmf.py | 32 ++++++++++++++++++--- 8 files changed, 125 insertions(+), 43 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index a99486cc..63d1c50e 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -193,16 +193,19 @@ def createUniformLongitudeAxis(startLon, nlon, deltaLon): def mapLinearIntersection(xind, yind, iind, aMinusEps, aPlusEps, bPlusEps, bMinusEps, boundLeft, nodeSubI, boundRight): - """ - Parameters - ---------- + """ Parameters + ---------- + xind: 'c' if (a,b) is closed on the left, 'o' if open, + yind: - same for right endpoint -j - Returns - ------- + same for right endpoint j + + + Returns + ------- + True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: diff --git a/Lib/coord.py b/Lib/coord.py index 7222a1f4..c4e3b3ce 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -379,9 +379,11 @@ def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_val Parameters ---------- - 'bounds' is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and + 'bounds' + is the bounds array, having shape (m,n,nvert) where data.shape is (m,n) and - nvert is the max number of vertices per cell. + nvert + is the max number of vertices per cell. """ AbstractAxis2D.__init__(self, None, None, bounds=bounds) TransientVariable.__init__(self, data, typecode=typecode, copy=copy, savespace=savespace, diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index 7c0d9ab7..cff27151 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -141,6 +141,8 @@ def listglobal(self): ------- a list of the global attributes in the file. + _None_ + ::: """ return list(self.attributes.keys()) @@ -152,6 +154,9 @@ def listvariable(self): ------- a list of the variables in the file. + + _None_ + ::: """ return list(self.variables.keys()) diff --git a/Lib/dataset.py b/Lib/dataset.py index beb82df9..e3545553 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -2008,17 +2008,16 @@ def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds The list of axis objects. Default is var.getAxisList() extbounds: Bounds of the (portion of) the extended dimension being written. - id or newname: + id: + newname: String identifier of the new variable. extend: * 1 define the first dimension as the unlimited dimension. - * 0 do not define an unlimited dimension. The default is the define - the first dimension as unlimited only if it is a time dimension. + * 0 do not define an unlimited dimension. The default is the define the first dimension as unlimited only if it is a time dimension. fill_value: The missing value flag. index: - The extended dimension index for writting. The default index is determined - by lookup relative to the existing extended dimension. + The extended dimension index for writting. The default index is determined by lookup relative to the existing extended dimension. grid: The variable grid. `none` the value of var.getGrid() will used. diff --git a/Lib/forecast.py b/Lib/forecast.py index 75dcae5e..fe8dae05 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -1,6 +1,10 @@ # Forecast support, experimental coding # probably all this will be rewritten, put in a different directory, etc. +"""CDMS Forecast""" + + + from __future__ import print_function import numpy import cdtime @@ -72,7 +76,6 @@ class forecast(): def __init__(self, tau0time, dataset_list, path="."): """ - Parameters ---------- diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 6a7c07e8..5ac1bdca 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -294,9 +294,11 @@ def writeScrip(self, cufile, gridTitle=None): Parameter --------- - cufile is a Cdunif file, NOT a CDMS file. + cufile + is a Cdunif file, NOT a CDMS file. - gridtitle is a string identifying the grid. + gridtitle + is a string identifying the grid. """ lat = numpy.ma.filled(self._lataxis_[:]) @@ -585,22 +587,29 @@ def getGridSlices(self, domainlist, newaxislist, slicelist): Parameters ---------- - domainlist is a list of axes of a variable. + domainlist + is a list of axes of a variable. - newaxislist is a list of result axes after the slicelist is applied to domainlist. + newaxislist + is a list of result axes after the slicelist is applied to domainlist. - slicelist is a list of slices. + slicelist + is a list of slices. All lists are of equal length. Returns ------- - value is (newslicelist, gridaxislist) where - newslicelist is the elements of slicelist that correspond to the grid, in the + value + is (newslicelist, gridaxislist) where + newslicelist + + is the elements of slicelist that correspond to the grid, in the preferred order of the grid. - gridaxislist is the elements of newaxislist that correspond to the grid, in the + gridaxislist + is the elements of newaxislist that correspond to the grid, in the preferred order of the grid. """ @@ -649,14 +658,19 @@ def intersect(self, spec): Parameters ---------- - 'spec' is a region specification of the form defined in the grid module. + 'spec' + is a region specification of the form defined in the grid module. Returns ------- (mask, indexspecs) where - 'mask' is the mask of the result grid AFTER self and region spec are interested. - 'indexspecs' is a list of index specifications suitable for slicing a + 'mask' + is the mask of the result grid AFTER self and region spec are interested. + + 'indexspecs' + is a list of index specifications suitable for slicing a + variable with the given grid. """ ni, nj = self.shape @@ -697,7 +711,8 @@ def isClose(self, g): Returns ------- - 1 if g is a grid of the same type and shape. A real element-by-element + 1 if g + is a grid of the same type and shape. A real element-by-element comparison would be too expensive here.""" if g is None: return 0 @@ -714,7 +729,8 @@ def checkAxes(self, axes): Returns ------- - 1 iff every element of self.getAxisList() is in the list 'axes'.""" + 1 iff every element of self.getAxisList() + is in the list 'axes'.""" for item in self.getAxisList(): # if all [False, False, ....] result=0 if not any([allclose(item[:], axis[:]) for axis in axes]): @@ -727,11 +743,12 @@ def checkAxes(self, axes): def reconcile(self, axes): """ - Returns ------- - a grid that is consistent with the axes, or None. + a grid that + is consistent with the axes, or None. + For curvilinear grids this means that the grid-related axes are contained in the 'axes' list. """ @@ -763,13 +780,15 @@ def reconcile(self, axes): def flatAxes(self): """ - Returns ------- - (flatlat, flatlon) where flatlat is a 1D NumPy array + (flatlat, flatlon) where flatlat + is a 1D NumPy array + having the same length as the number of cells in the grid, similarly - for flatlon.""" + for flatlon. + """ if self._flataxes_ is None: from . import MV2 as MV alat = MV.filled(self.getLatitude()) @@ -847,13 +866,17 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): Parameters ---------- - fileobj is an open CDMS dataset or file object. + fileobj + is an open CDMS dataset or file object. - dims is the grid shape. + dims + is the grid shape. - whichType is the type of file, either "grid" or "mapping" + whichType + is the type of file, either "grid" or "mapping" - if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" + if whichType + is "mapping", whichGrid is the choice of grid, either "source" or "destination" """ import string from .coord import TransientAxis2D diff --git a/docs/source/API.rst b/docs/source/API.rst index 266d3294..f63a931f 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -24,9 +24,27 @@ Classes gengrid grid hgrid - gsStaticVariable - gsTimeVariable + MV2 + mvCdmsRegrid + selectors + tvariable + mvBaseWriter + mvSphereMesh + mvVsWriter + mvVTKSGWriter + mvVTKUGWriter + + + + + + + + + + + .. currentmodule:: Libregrid @@ -35,4 +53,9 @@ Regridder --------- .. autosummary:: horizontal + esmf + + + + diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 884a7800..5644b601 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -91,7 +91,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- - `` + 3 4 ---------- 3 / \ | | / \ | | @@ -99,7 +99,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, / \ | | / \ | | 1 --------- 2 1 ---------- 2 - `` + 3 8---------------7 /|\ /| /| / | \ / | / | @@ -114,7 +114,7 @@ def setCells(self, cellIndices, cellTypes, connectivity, \|/ |/ |/ 1 1---------------2 - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX `` + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX """ n = len(cellIndices) @@ -155,7 +155,9 @@ def toVTK(self, filename): Parameters ---------- - filename VTK file name + filename VTK file name + _: None + """ self.grid.write(filename) @@ -252,6 +254,9 @@ def getLocalSlab(self, staggerloc): ---------- staggerloc (e.g. ESMF.StaggerLoc.CENTER) + + _: None + Returns ------- @@ -271,6 +276,8 @@ def getLoHiBounds(self, staggerloc): staggerloc e.g. ESMF.StaggerLoc.CENTER + _: None + Returns ------- @@ -289,6 +296,8 @@ def getCoordShape(self, staggerloc): staggerloc (e.g. ESMF.StaggerLoc.CENTER) + _: None + Returns ------- @@ -354,6 +363,9 @@ def setCellAreas(self, areas): --------- areas numpy array + + _: None + """ self.grid.add_item(item=ESMF.GridItem.Area) areaPtr = self.grid.get_item( @@ -403,6 +415,8 @@ def setMask(self, mask, staggerloc=CENTER): mask numpy array. 1 is invalid by default. This array exists on all procs + + _: None """ self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) maskPtr = self.grid.get_item( @@ -502,6 +516,8 @@ def getData(self, rootPe): gather the data on processor "rootPe" (all other procs will return None). + _: None + Returns ------- @@ -683,6 +699,8 @@ def getSrcAreas(self, rootPe): rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered + _: None + Returns ------- @@ -702,6 +720,8 @@ def getDstAreas(self, rootPe): rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered + _: None + Returns ------- @@ -721,6 +741,8 @@ def getSrcAreaFractions(self, rootPe): rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered + _: None + Returns ------- @@ -741,6 +763,8 @@ def getDstAreaFractions(self, rootPe): rootPe None is local areas are returned, otherwise provide rootPe and the data will be gathered + _: None + Returns ------- From ffce80dd4d346b2849f1bc4b2d99208c745a9243 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 20 Apr 2018 12:39:21 -0700 Subject: [PATCH 085/239] Changes made to API --- docs/source/API.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/API.rst b/docs/source/API.rst index f63a931f..2698ccf5 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -33,6 +33,12 @@ Classes mvVsWriter mvVTKSGWriter mvVTKUGWriter + restApi + slabinterface + + + + From 1760785471842c3e00ec5ad3f82a8c5fe1e4a9d5 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 23 Apr 2018 16:03:04 -0700 Subject: [PATCH 086/239] Changes to API --- docs/source/API.rst | 20 ++++++++++ regrid2/Lib/esmf.py | 96 ++++++++++++++++++++++++++++++--------------- 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index 2698ccf5..6a83760f 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -60,6 +60,26 @@ Regridder .. autosummary:: horizontal esmf + crossSection + gsRegrid + mvESMFRegrid + mvGenericRegrid + pressure + scrip + mvLibCFRegrid + gs_horizontal + + + + + + + + + + + + diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 5644b601..ccabad43 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -40,15 +40,16 @@ class EsmfUnstructGrid: """ def __init__(self, numTopoDims, numSpaceDims): - """ - Constructor + """Constructor Parameters ---------- - numTopoDims number of topological dimensions + numTopoDims + number of topological dimensions - numSpaceDims number of space dimensions + numSpaceDims + number of space dimensions """ # handle to the grid object self.grid = None @@ -91,15 +92,27 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- - - 3 4 ---------- 3 - / \ | | - / \ | | - / \ | | - / \ | | - / \ | | - 1 --------- 2 1 ---------- 2 + 3 + / \ + / \ + / \ + / \ + / \ + 1 --------- 2 + + + + + 4------------3 + | | + | | + | | + | | + | | + 1 ---------- 2 + + 3 8---------------7 /|\ /| /| / | \ / | / | @@ -253,7 +266,8 @@ def getLocalSlab(self, staggerloc): Parameters ---------- - staggerloc (e.g. ESMF.StaggerLoc.CENTER) + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) _: None @@ -274,7 +288,8 @@ def getLoHiBounds(self, staggerloc): Parameters ---------- - staggerloc e.g. ESMF.StaggerLoc.CENTER + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) _: None @@ -294,7 +309,8 @@ def getCoordShape(self, staggerloc): Parameters ---------- - staggerloc (e.g. ESMF.StaggerLoc.CENTER) + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) _: None @@ -314,14 +330,17 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): Parameters ---------- - coords The curvilinear coordinates of the grid. + coords + The curvilinear coordinates of the grid. List of numpy arrays. Must exist on all procs. - staggerloc The stagger location + staggerloc + The stagger location ESMF.StaggerLoc.CENTER (default) ESMF.StaggerLoc.CORNER - globalIndexing if True array was allocated over global index + globalIndexing + if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None @@ -443,15 +462,19 @@ def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): Parameters ---------- - esmfGrid instance of an ESMF + esmfGrid + instance of an ESMF - name field name (must be unique) + name field + name (must be unique) - datatype data type, one of 'float64', 'float32', 'int64', or 'int32' + datatype + data type, one of 'float64', 'float32', 'int64', or 'int32' (or equivalent numpy dtype) - staggerloc ESMF.StaggerLoc.CENTER - ESMF.StaggerLoc.CORNER + staggerloc + ESMF.StaggerLoc.CENTER + ESMF.StaggerLoc.CORNER """ # field object self.field = None @@ -608,23 +631,32 @@ def __init__(self, srcField, dstField, Parameters ---------- - srcField the source field object of type EsmfStructField + srcField + the source field object of type EsmfStructField - dstField the destination field object of type EsmfStructField + dstField + the destination field object of type EsmfStructField - srcMaskValues Value of masked cells in source + srcMaskValues + Value of masked cells in source - dstMaskValues Value of masked cells in destination + dstMaskValues + Value of masked cells in destination - srcFrac Cell fractions on source grid (type EsmfStructField) + srcFrac + Cell fractions on source grid (type EsmfStructField) - dstFrac Cell fractions on destination grid (type EsmfStructField) + dstFrac + Cell fractions on destination grid (type EsmfStructField) - regridMethod ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + regridMethod + ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - unMappedAction ESMF.UnmappedAction.{IGNORE,ERROR} + unMappedAction + ESMF.UnmappedAction.{IGNORE,ERROR} - ignoreDegenerate Ignore degenerate cells when checking inputs + ignoreDegenerate + Ignore degenerate cells when checking inputs """ self.srcField = srcField self.dstField = dstField From 1b4d412e081573d7402cb4eed2ae79479c3c40b8 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 11:28:20 -0700 Subject: [PATCH 087/239] test rtd with mock --- Lib/axis.py | 35 ++++++++++++++++++++++++----------- Lib/bindex.py | 3 ++- Lib/convention.py | 35 +++++++++++++++++++++++++---------- Lib/dataset.py | 10 +++++++--- Lib/fvariable.py | 3 ++- Lib/hgrid.py | 3 ++- Lib/tvariable.py | 1 - Src/Cdunifmodule.c | 1 + docs/createRST.sh | 4 ++-- docs/requirements.txt | 1 + docs/source/conf.py | 29 +++++++++++++++++++++++++++-- docs/source/index.rst | 9 +++++++-- tests/test_EsmfMask.py | 9 ++++++++- 13 files changed, 108 insertions(+), 35 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index b070ba54..3d8b8230 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -7,6 +7,7 @@ from future import standard_library import sys +import os import types import copy import numpy @@ -25,22 +26,34 @@ _debug = 0 std_axis_attributes = ['name', 'units', 'length', 'values', 'bounds'] +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' -class AliasList (UserList): - def __init__(self, alist): - UserList.__init__(self, alist) +if not ON_RTD: + class AliasList (UserList): + def __init__(self, alist): + UserList.__init__(self, alist) - def __setitem__(self, i, value): - self.data[i] = value.lower() + def __setitem__(self, i, value): + self.data[i] = value.lower() - def __setslice(self, i, j, values): - self.data[i:j] = [x.lower() for x in values] + def __setslice(self, i, j, values): + self.data[i:j] = [x.lower() for x in values] - def append(self, value): - self.data.append(value.lower()) + def append(self, value): + self.data.append(value.lower()) - def extend(self, values): - self.data.extend(list(map(str.lower, values))) + def extend(self, values): + self.data.extend(list(map(str.lower, values))) +else: + class MockObject(object): + def __init__(self, *args, **kwargs): + super(MockObject, self).__init__() + + def __call__(self, *args, **kwargs): + return None + + class AliasList(MockObject): + pass level_aliases = AliasList(['plev']) diff --git a/Lib/bindex.py b/Lib/bindex.py index df14ead0..1c0433df 100644 --- a/Lib/bindex.py +++ b/Lib/bindex.py @@ -3,7 +3,8 @@ """Bin index for non-rectilinear grids""" -from . import _bindex +#from . import _bindex +import _bindex import numpy diff --git a/Lib/convention.py b/Lib/convention.py index ba32cbad..86fb5b9a 100644 --- a/Lib/convention.py +++ b/Lib/convention.py @@ -1,6 +1,6 @@ """ metadata conventions """ - from __future__ import print_function +import os from .error import CDMSError from collections import UserList @@ -9,19 +9,34 @@ MethodNotImplemented = "Method not yet implemented" +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if not ON_RTD: + class AliasList (UserList): + def __init__(self, alist): + UserList.__init__(self, alist) + + def __setitem__(self, i, value): + self.data[i] = value.lower() + + def __setslice(self, i, j, values): + self.data[i:j] = [x.lower() for x in values] -class AliasList (UserList): - def __init__(self, alist): - UserList.__init__(self, alist) + def append(self, value): + self.data.append(value.lower()) - def __setitem__(self, i, value): - self.data[i] = value.lower() + def extend(self, values): + self.data.extend(list(map(str.lower, values))) +else: + class MockObject(object): + def __init__(self, *args, **kwargs): + super(MockObject, self).__init__() - def __setslice(self, i, j, values): - self.data[i:j] = [x.lower() for x in values] + def __call__(self, *args, **kwargs): + return None - def append(self, value): - self.data.append(value.lower()) + class AliasList(MockObject): + pass level_aliases = AliasList(['plev']) diff --git a/Lib/dataset.py b/Lib/dataset.py index c55bc6c8..efb70c9b 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -4,15 +4,19 @@ """ CDMS dataset and file objects""" from __future__ import print_function from .error import CDMSError -from . import Cdunif +import sys +#from . import Cdunif +import Cdunif import numpy -from . import cdmsNode +#from . import cdmsNode +import cdmsNode import os import sys import string import urllib from urllib.parse import urlparse, urlunparse -from . import cdmsobj +#from . import cdmsobj +import cdmsobj import re from .CDMLParser import CDMLParser from .cdmsobj import CdmsObj diff --git a/Lib/fvariable.py b/Lib/fvariable.py index c9b7024b..6dfb69d7 100644 --- a/Lib/fvariable.py +++ b/Lib/fvariable.py @@ -7,7 +7,8 @@ from .variable import DatasetVariable from .error import CDMSError from .sliceut import reverseSlice -from .Cdunif import CdunifError +from cdms2.Cdunif import CdunifError +#import cdms2.Cdunif.CdunifError as CdunifError FileClosed = "Cannot read from closed file, variable: " FileClosedWrite = "Cannot write to a closed file, variable: " diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 18d7e0a2..68cf3da8 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -14,7 +14,8 @@ from .axis import TransientVirtualAxis from .axis import getAutoBounds, allclose from . import bindex -from . import _bindex +#from . import _bindex +import _bindex from functools import reduce import copy diff --git a/Lib/tvariable.py b/Lib/tvariable.py index 69c1cdd4..8cb4f082 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -58,7 +58,6 @@ def fromJSON(jsn): V.set_fill_value(D["_fill_value"]) return V - class TransientVariable(AbstractVariable, numpy.ma.MaskedArray): "An in-memory variable." variable_count = 0 diff --git a/Src/Cdunifmodule.c b/Src/Cdunifmodule.c index ddfb81df..3911836e 100644 --- a/Src/Cdunifmodule.c +++ b/Src/Cdunifmodule.c @@ -524,6 +524,7 @@ static int cdopen(const char* controlpath, int ncmode, CuFileType *filetype) { /* Check the filetype */ int saveopts; + saveopts = cuErrOpts; cuseterropts(0); cuseterropts(saveopts); diff --git a/docs/createRST.sh b/docs/createRST.sh index f77af08c..15bc19f2 100755 --- a/docs/createRST.sh +++ b/docs/createRST.sh @@ -3,10 +3,10 @@ a=('cdmsobj' 'axis' 'coord' 'grid' 'hgrid' 'avariable' 'sliceut' 'error' for i in "${a[@]}"; do echo "creating "$i".rst" -echo "cdms $i +echo "$i ======== -.. automodule:: cdms2.$i +.. automodule:: Lib.$i :members: " >$i.rst diff --git a/docs/requirements.txt b/docs/requirements.txt index e48f7c2c..8348af0a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,2 @@ easydev +mock diff --git a/docs/source/conf.py b/docs/source/conf.py index 8b2d4881..294d7ac6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,6 +11,30 @@ # # All configuration values have a default; values that are commented out # serve to show the default. +from future.standard_library import install_aliases +install_aliases() +import sys,os +sys.path.append(os.path.abspath('..')) +sys.path.append(os.path.abspath('../..')) +print sys.path +import mock +os.environ['READTHEDOCS']="True" +#MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] +MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif'] + +def side_effect(*args, **kwargs): + return mock.DEFAULT + +for mod_name in MOCK_MODULES: + m = mock.Mock() + m.return_value=3 + m.side_effect = side_effect + print mod_name + sys.modules[mod_name] = m + + +open('../Lib/git.py','a').close() + import sys import os @@ -25,7 +49,7 @@ #sys.path.insert(0, os.path.abspath('.')) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) #sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) -sys.path.insert(0,"/software/anaconda2/envs/dev/lib/python2.7/site-packages") +sys.path.insert(0,"..") print os.path.join(sys.prefix,"lib","python2.7","site-packages") @@ -51,6 +75,7 @@ #] extensions = [ 'easydev.copybutton', + 'sphinx.ext.autosummary', 'sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinx.ext.graphviz', @@ -132,7 +157,7 @@ # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. diff --git a/docs/source/index.rst b/docs/source/index.rst index f96d857b..bce7d25d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -19,10 +19,15 @@ manual/cdms_appendix manual/sample_data +.. autosummary:: + :toctree: + + avariable + axis.FileVirtuaAxis + axis.TransientVirtualAxis + # AbstractAxis # AbstractVariable -# avariable -# axis # bindex # cache # cdmsfile diff --git a/tests/test_EsmfMask.py b/tests/test_EsmfMask.py index e401b6cb..60da15ac 100644 --- a/tests/test_EsmfMask.py +++ b/tests/test_EsmfMask.py @@ -1,5 +1,6 @@ import unittest import cdms2 +import vcs import ESMF import cdat_info import os @@ -60,10 +61,16 @@ def testMask2(self): data2 = cdms2.MV2.masked_where(cdms2.MV2.less(sft,50.),data) tGrid = cdms2.createUniformGrid(-88.875, 72, 2.5, 0, 144, 2.5) - + x=vcs.init() for mthd in ["conservative", "linear"]: print("USING REGRID METHOD:",mthd) data3 = data2.regrid(tGrid, regridTool="esmf", regridMethod=mthd, mask=data2.mask) + print("pltting") + x.plot(data3) + print("pnging") + x.png("masked_{}".format(mthd)) + print("clearing") + x.clear() From 34973dd5ef1f67de1b554b33757462eb1bdb5324 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 11:30:56 -0700 Subject: [PATCH 088/239] add future for readthedocs --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 8348af0a..cae732c6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ easydev mock +future From 79f5c123e4cdb9de56576bb014c72cbae5bbe504 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 11:36:51 -0700 Subject: [PATCH 089/239] create git.py in ../.. --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 294d7ac6..f916a016 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,7 @@ def side_effect(*args, **kwargs): sys.modules[mod_name] = m -open('../Lib/git.py','a').close() +open('../../Lib/git.py','a').close() import sys From bdb5db6fa72a7db99c0a9243fedd7f889c0bf6e3 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 11:55:02 -0700 Subject: [PATCH 090/239] add esmf --- docs/source/index.rst | 6 - regrid2/Lib/__init__.py | 36 - regrid2/Lib/crossSection.py | 1092 ----------------------------- regrid2/Lib/error.py | 3 - regrid2/Lib/esmf.py | 842 ----------------------- regrid2/Lib/gsRegrid.py | 1179 -------------------------------- regrid2/Lib/gs_horizontal.py | 214 ------ regrid2/Lib/horizontal.py | 422 ------------ regrid2/Lib/mvESMFRegrid.py | 483 ------------- regrid2/Lib/mvGenericRegrid.py | 313 --------- regrid2/Lib/mvLibCFRegrid.py | 101 --- regrid2/Lib/pressure.py | 490 ------------- regrid2/Lib/scrip.py | 447 ------------ 13 files changed, 5628 deletions(-) delete mode 100644 regrid2/Lib/__init__.py delete mode 100644 regrid2/Lib/crossSection.py delete mode 100644 regrid2/Lib/error.py delete mode 100644 regrid2/Lib/esmf.py delete mode 100644 regrid2/Lib/gsRegrid.py delete mode 100644 regrid2/Lib/gs_horizontal.py delete mode 100644 regrid2/Lib/horizontal.py delete mode 100644 regrid2/Lib/mvESMFRegrid.py delete mode 100644 regrid2/Lib/mvGenericRegrid.py delete mode 100644 regrid2/Lib/mvLibCFRegrid.py delete mode 100644 regrid2/Lib/pressure.py delete mode 100644 regrid2/Lib/scrip.py diff --git a/docs/source/index.rst b/docs/source/index.rst index 567bd75f..b5fe5bca 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -20,12 +20,6 @@ manual/sample_data API -.. autosummary:: - :toctree: - - avariable - axis.FileVirtuaAxis - axis.TransientVirtualAxis # AbstractAxis # AbstractVariable diff --git a/regrid2/Lib/__init__.py b/regrid2/Lib/__init__.py deleted file mode 100644 index 36b7f9e2..00000000 --- a/regrid2/Lib/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Interface to regridding facilities -""" - -__all__ = ["horizontal", "pressure", "crossSection", "scrip", - "error", "mvGenericRegrid", ] - -from .error import RegridError # noqa -from .horizontal import Horizontal, Regridder # noqa -from .pressure import PressureRegridder # noqa -from .crossSection import CrossSectionRegridder # noqa -from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa -from .scrip import DistwgtRegridder, readRegridder # noqa -from regrid2 import gsRegrid # noqa -from .mvGenericRegrid import GenericRegrid # noqa -from .mvLibCFRegrid import LibCFRegrid # noqa -try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - from .mvESMFRegrid import ESMFRegrid # noqa -except BaseException: - pass - -from . import git # noqa - -ESMF_HAS_BEEN_INITIALIZED = False -if not ESMF_HAS_BEEN_INITIALIZED: - try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - ESMF.Manager(debug=False) - # this turns off the PET file logs - ESMF_HAS_BEEN_INITIALIZED = True - except BaseException: - pass diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py deleted file mode 100644 index cf23b45d..00000000 --- a/regrid2/Lib/crossSection.py +++ /dev/null @@ -1,1092 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError - - -class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, - latTypeOut=None, latSizeOut=None): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, - # latTypeOut = None, latSizeOut = None): - # - # PROCEDURE: - # - # The user must assemble at least the following four pieces of information: - # - # latIn - the axis specifying the latitude grid for the input data - # - # latOut - the axis specifying the latitude grid for the output data - # - # levIn - the axis specifying the pressure grid for the input data - # - # levOut - the axis specifying the pressure grid for the output data - # - # - # Additional information is required if a latitude grid is not global. It may be generic. - # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice - # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the - # computation requires the size of the global grid from which the subset was choosen. Consequently, - # the user must assemble: - # - # latTypeIn -- for input latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region - # - # latTypeOut -- for output latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region - # - # USAGE: - # - # To make an instance preparing for a global to global regrid, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) - # - # To make an instance preparing for a global to a regional grid which, for example, is a subset of - # a global gaussian grid of size 64, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) - # - # where the latOut axis must have been selected from the global 64 length gaussian grid - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.latOut = latOut - self.levIn = levIn - self.levOut = levOut - self.nlevi = len(levIn) - self.nlevo = len(levOut) - - latIn, self.nlati = checkdimension(latIn, 'input latitude') - latOut, self.nlato = checkdimension(latOut, 'output latitude') - - # --- check for a single grid point in the latitude-level plane - - if self.nlevo == 1 and self.nlato != 1: - sendmsg( - 'Error in output grid - a single level value requires a single latitude value') - raise ValueError - if self.nlevo != 1 and self.nlato == 1: - sendmsg( - 'Error in output grid - a single latitude value requires a single longitude value') - raise ValueError - if self.nlevo == 1 and self.nlato == 1: - calculateMean = 1 - msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' - sendmsg(msg) - else: - calculateMean = 0 - - # --- get the latitude coordinate grid boundaries for the input grid - - if latTypeIn is None: # global latIn - lat_wts_bndsIn = get_latitude_wts_bnds(latIn) - else: - lat_wts_bndsIn = get_region_latitude_wts_bnds( - latIn, latTypeIn, latSizeIn) - - lat_bndsIn = lat_wts_bndsIn[1] - bnin, bsin = latitude_bounds(lat_bndsIn) - - if calculateMean == 0: # meaningful grid - - # --- get the latitude coordinate grid boundaries for the output grid - - if latTypeOut is None: # global latOut - lat_wts_bndsOut = get_latitude_wts_bnds(latOut) - else: - lat_wts_bndsOut = get_region_latitude_wts_bnds( - latOut, latTypeOut, latSizeOut) - - lat_bndsOut = lat_wts_bndsOut[1] - bnout, bsout = latitude_bounds(lat_bndsOut) - - else: - bnout = numpy.array([90.0], numpy.float32) - bsout = numpy.array([-90.0], numpy.float32) - - # --- call maplength to get the rest of the self data needed by rgrdlength - - t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) - - self.latdx, self.latpt, self.wtlat = t - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the regridder function. - ar is the input array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = "zy" - else: - order = "tzy" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = str.lower(order) - - # Map order to positionIn - positionIn = [None] * 3 - for i in range(len(order)): - if order[i] == 'y': - positionIn[0] = i - if inputIsVariable: - axislist[i] = self.latOut - elif order[i] == 'z': - positionIn[1] = i - if inputIsVariable: - axislist[i] = self.levOut - else: - positionIn[2] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - # Mask fill_value and return results - if inputIsVariable == 1: - result = numpy.ma.masked_values(outar, missing) - result = cdms2.createVariable(result, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - result = numpy.ma.masked_values(result, missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', - positionIn=None, maskIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in - # the latitude-level plane. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, - # missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed - # in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence latitude, - # level and time. Latitude and level are required. If time is missing submit None in its - # slot in the tuple. Notice that the length of the tuple is - # always three. - # - # Explicitly, in terms of the shape of dataIn as returned by python's shape function - # - # positionIn[0] contains the position of latitude in dataIn - # positionIn[1] contains the position of level in dataIn or None - # positionIn[2] contains the position of time in dataIn or None - # - # As examples: - # If the c order shape of 3D data is - # (number of times, number of levels, number of latitudes) - # submit - # (2, 1, 0). - # - # If the c order shape of 2D data is - # (number of times, number of latitudes) - # submit - # (1, None, 0). - # - # Send in None if the shape is a subset of (time, level, latitude) which is evaluated - # as follows: - # 2D -- code assumes (1,0,None) - # 3D -- code assumes (2,1,0) - # - # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This - # mask only works on the latitude grid. It is not possible to mask out a region in the level - # plane. The 0.0 value removes the data from correponding grid point. The user can supply the - # following choices: - # - # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing - # data in the input data array, dataIn - # - # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, - # dataIn. This user supplied mask might be used to mask a latitude region. It is not - # required to account for missing data in the input data. The code uses missingValueIn - # and missingMatch to supply the 0.0s for grid points with missing data in the input - # data array, dataIn. - # - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # WARNING: This code does not regrid cross sections which have a single dummy longitude value! - # - # - #-----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # try to identify a single dummy longitude - - dataShape = dataIn.shape - - if len(dataShape) > 3: - msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is not None: - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # set missing value to be used in dataOut - - if missingValueOut is None: - if missingValueIn is not None: - # default - omit = missingValueIn - else: - # default - omit = 1.0e20 - else: - # user choice - omit = missingValueOut - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - # produce the input for rgdlength not generated by maplength - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is None: # construct the default positionIn tuple - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - if numberDim == 2: # fill end of list with a None - positionList.append(None) - - positionIn = tuple(positionList) - - if len(positionIn) != 3: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' - sendmsg(msg) - raise TypeError - - # set ilon, ilat in Fortran order except that the first index is 0 - - # not 1 - ilat = numberDim - 1 - positionIn[0] - - itim1 = itim2 = -1 - ntim1 = ntim2 = 0 - - if numberDim == 2: # lat and level field - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - - if numberDim == 3: # lon_lat field + level + time - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - itim2 = numberDim - 1 - positionIn[2] - ntim2 = dataShape[positionIn[2]] - - # check for consistency between the grid axiss and the dataIn shape - - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # allocate memory for aout -- the array with original number of levels - # but the new number of latitudes - - aoutList = list(dataIn.shape) - aoutList[positionIn[0]] = self.nlato - # memory for aout - aout = numpy.zeros(tuple(aoutList), numpy.float32) - - # generate the mask - - amskin = sectionmask( - dataIn, - positionIn, - maskIn, - missingValueIn, - missingMatch) - - # ------------- call rgdlength to regrid latitude --------------- - - _regrid.rgdlength( - ilat, - itim1, - itim2, - ntim1, - ntim2, - self.nlati, - self.nlato, - omit, - self.latdx, - self.latpt, - self.wtlat, - amskin, - dataIn, - aout) - - # ------------- call rgdpressure to regrid pressure ------------- - - # allocate memory for ap -- the array with new number of levels and the - # new number of latitudes - - apList = list(dataIn.shape) - apList[positionIn[0]] = self.nlato - apList[positionIn[1]] = self.nlevo - # memory for ap - ap = numpy.zeros(tuple(apList), numpy.float32) - - nlon = 0 - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.levIn[:].astype(numpy.float64) - levOut = self.levOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlato, - nlon, - ntim2, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - aout, - ap) - - if missingMatch == 'none': # if no missing do not pass None - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - return ap - - -def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" - - data = x[:] - try: - xsize = len(x) - except TypeError: - sendmsg('Hgrid instance error -- instance requires a ' + name) - raise TypeError - - if data.dtype.char != 'f': - x[:] = x[:].astype(numpy.float32) - - # ----- check for consistency ----- - - if x[0] > x[xsize - 1]: - for n in range(1, xsize): - if x[n] > x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - else: - for n in range(1, xsize): - if x[n] < x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - - return x, xsize - - -def generic_wts_bnds(lat): - try: - bnds = lat.getBounds() - if bnds is None: # No bounds defined - newLat = lat.clone() - newLat.setBounds(None) - bnds = lat.getBounds() - except BaseException: # just an array.... - newLat = cdms2.createAxis(lat) - newLat.setBounds(None) - bnds = newLat.getBounds() - outBnds = bnds[:, 0].tolist() - outBnds.append(bnds[-1][-1]) - outBnds = numpy.array(outBnds) - wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] - wts = numpy.array(wts) / numpy.sum(wts) - return wts, outBnds - - -def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - small = 0.001 # use as tolerance in checking values - - nlat = len(checklatpass) - - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if checklatpass[0] < checklatpass[nlat - - 1]: # need a copy? - checklat = numpy.array(checklatpass, numpy.float64) - checklat = checklat[::-1] - reverse_latitude = 'yes' - else: - checklat = checklatpass - - # ------ check the pass for evenly spaced latitudes ------- - - firstdelta = abs(checklat[0] - checklat[1]) - maxdiff = 0.0 - for i in range(1, nlat - 1): - diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) - if diff > maxdiff: - maxdiff = diff - - if maxdiff < small: - # if abs(90. - checklat[0]) > small or abs(-90. - - # checklat[nlat - 1]) > small: - # grid_type = 'even' # evenly spaced without poles - # wts, bnds = generic_wts_bnds(checklat) - # if reverse_latitude == 'yes': - # wts = wts[::-1] - # bnds = bnds[::-1] - # return (wts, bnds) - # else: - grid_type = 'uniform' # evenly spaced with poles - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for gaussian latitudes ------- - - grid_type = 'gaussian' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for equalarea latitudes ------- - - grid_type = 'equalarea' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ must be generic latitude ------- - wts, bnds = generic_wts_bnds(checklatpass) - return (wts, bnds) - - -def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" - - latbnds = lat_bnds.astype(numpy.float32) - - if latbnds[0] > latbnds[len(latbnds) - 1]: - bn = latbnds[:-1] - bs = latbnds[1:] - else: - bn = latbnds[1:] - bs = latbnds[:-1] - - return (bn, bs) - - -def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - - latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] - - if latType not in latTypeList: - sendmsg( - "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", - latType) - raise ValueError - return - - if latSize is None: - sendmsg('Error in latSize -- it must be a number') - raise ValueError - return - - nlat = len(latRegionpass) - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if latRegionpass[0] < latRegionpass[nlat - - 1]: # need a copy? - latRegion = numpy.array(latRegionpass, numpy.float64) - latRegion = latRegion[::-1] - reverse_latitude = 'yes' - else: - latRegion = latRegionpass - - small = 0.001 # use as tolerance in checking values - - # ------ check the pass for gaussian latitudes ------- - - if latType != 'generic': - # n to s global pts, wts and bnds - pts_wts_bnds = _regrid.gridattr(latSize, latType) - latvals = pts_wts_bnds[0] - - imatch = -1 - i = 0 - while(imatch == -1): - if abs(latvals[i] - latRegion[0]) < small: # first index found - startIndex = i - imatch = 0 - i = i + 1 - imatch = -1 - while(imatch == -1): - if abs(latvals[i] - latRegion[nlat - 1] - ) < small: # last index found - lastIndex = i - imatch = 0 - i = i + 1 - - wts = pts_wts_bnds[1][startIndex:lastIndex + 1] - bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] - - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - - return (wts, bnds) - -# else: # must be generic latitude ------- -# -# wts, bnds = generic_wts_bnds(latIn) -# if reverse_latitude == 'yes': -# wts = wts[::-1] -# bnds = bnds[::-1] -# return (wts, bnds) - - -def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" - # Logic outline - # START NO USER MASK SECTION ? - # - # START USER MASK SECTION ? - # USER SUPPLIED MASK IS 2D ? - # USER SUPPLIED MASK IS FULL SIZE ? - - # ---- check the missingMatch pass -------- - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' - sendmsg(msg) - raise ValueError - - # ----- Check for missing data in dataIn, set missingFlag and miss, the va - - # missingFlag = 0 if there is no missing data - # missingFlag = 1 if there is missing data found using greater than missingValueIn - # missingFlag = 1 if there is missing data found using the default 1.0e20 - # missingFlag = 2 if there is missing data found using equal to missingValueIn - # missingFlag = 3 if there is missing data found using less than - # missingValueIn - - missingFlag = 0 - - # use value from the file - if missingValueIn is not None: - - if missingMatch == 'greater': - if missingValueIn > 0: - miss = 0.99 * missingValueIn - else: - miss = 1.01 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.greater( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 1 - - elif missingMatch == 'equal': - miss = missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.equal( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 2 - - elif missingMatch == 'less': - if missingValueIn > 0: - miss = 1.01 * missingValueIn - else: - miss = 0.99 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.less( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 3 - - # ----- get the shape of dataIn and set the number of dimensions in the da - - dataShape = dataIn.shape - # set size and check against positionIn - numberDataDim = len(dataShape) - - # remove the None fillers - reducedPositionIn = [] - for i in range(len(positionIn)): - if positionIn[i] is not None: - reducedPositionIn.append(positionIn[i]) - - if numberDataDim != len(reducedPositionIn): - msg = 'positionIn does not describe the number of dimensions in the data' - sendmsg(msg) - raise ValueError - - # ----- Determine the order of latitude and level in the data ------- - - # sequence is standard (lat,lon) - if positionIn[0] > positionIn[1]: - levlatFlag = 1 - else: - levlatFlag = 0 - - # ------------------------------------------------------------------------------------------------------ - # ----------------------------------------- Generate the mask ----------- - # ------------------------------------------------------------------------------------------------------ - - # ------------------------------------------------------------------------------------------------------ - # ---------- START NO USER MASK SECTION - - if maskIn is None: # ---- need to generate the mask from scratch ---- - - # allocate memory - amskin = numpy.ones(dataShape, numpy.float32) - - # ---------- START USER MASK SECTION - - else: # ---- use the users supplied mask ---- - - numberMaskDim = len(maskIn.shape) - - if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D - - # mask shape is (lat,lon) - if levlatFlag == 1: - checkmaskShape = ( - dataShape[positionIn[1]], dataShape[positionIn[0]]) - # mask shape is (lon,lat) - else: - checkmaskShape = ( - dataShape[positionIn[0]], dataShape[positionIn[1]]) - - if maskIn.shape != checkmaskShape: # check the mask shape - msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' - sendmsg(msg) - raise IndexError - - # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED - - if numberDataDim > 2: - # replicate the mask to size of dataIn - amskin = numpy.resize(maskIn, dataShape) - - else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE - - amskin = maskIn - - if numberMaskDim != numberDataDim: - msg = 'Error -- user supplied mask must be 2D or the size of the data' - sendmsg(msg) - raise IndexError - - if amskin.shape != dataIn.shape: - msg = 'Error -- full size mask supplied must have the same shape as the input data' - sendmsg(msg) - raise IndexError - - # there is missing data in dataIn to add to amskin - if missingFlag != 0: - if missingFlag == 1: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - elif missingFlag == 2: - amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) - elif missingFlag == 3: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - - amskin = amskin.astype(numpy.float32) - - return amskin - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None - - -def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" - - nlev = len(levvals) - - nlat = len(latvals) - theta = (math.pi / 180.) * latvals - - xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory - - t0 = 60. - p0 = 1000. - - for j in range(nlat): - for i in range(nlev): - x = math.cos(theta[j])**2 - y = t0 * ((levvals[i] / p0)**.3) - xsection[i, j] = x * y - 30. - - return xsection - - -def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" - - if data1.shape != data2.shape: - print('Error in shape in rmserror') - print(('data1 shape = ', data1.shape)) - print(('data2 shape = ', data2.shape)) - raise ValueError - - d1 = numpy.ravel(data1) - d2 = numpy.ravel(data2) - - sq = (d1 - d2) * (d1 - d2) - error = numpy.sum(sq) / len(d1) - rmserror = numpy.sqrt(error) - - return rmserror - - -if __name__ == '__main__': - import math - - latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) - levList = [10., 40., 75., 100., 150., 250., 350., 500., - 650., 850., 1000.] # pick some levels - levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - latOut = cdms2.createGaussianAxis(64) - levList = [10., 30., 50., 70., 100., 200., 300., 400., - 500., 700., 850., 1000.] # pick some levels - levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - - xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) - - # make some artificial data - dataIn = section(latIn[:], levIn[:]) - var = cdms2.createVariable( - dataIn, axes=( - levIn, latIn), attributes={ - 'units': 'N/A'}, id='test') - - dataOut = xregridf(dataIn) - - # make the exact answer - dataCheck = section(latOut[:], levOut[:]) - # find the rms error - error = rmserror(dataOut, dataCheck) - - print('expected cross section test case rms error = 0.18581882') - # print 'expected cross section test case rms error = 0.23062' - print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/error.py b/regrid2/Lib/error.py deleted file mode 100644 index 327dff22..00000000 --- a/regrid2/Lib/error.py +++ /dev/null @@ -1,3 +0,0 @@ -class RegridError (Exception): - def __init__(self, args="Unspecified error from regrid package"): - self.args = (args,) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py deleted file mode 100644 index 830910a1..00000000 --- a/regrid2/Lib/esmf.py +++ /dev/null @@ -1,842 +0,0 @@ -#!/usr/bin/env python - -""" -Copyright (c) 2008-2012, Tech-X Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the conditions -specified in the license file 'license.txt' are met. - -Authors: David Kindig and Alex Pletzer -""" -import re -import time -import numpy -from regrid2 import RegridError -import ESMF -from functools import reduce - -# constants -R8 = ESMF.TypeKind.R8 -R4 = ESMF.TypeKind.R4 -I8 = ESMF.TypeKind.I8 -I4 = ESMF.TypeKind.I4 -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER -CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class EsmfUnstructGrid: - """ - Unstructured grid - """ - - def __init__(self, numTopoDims, numSpaceDims): - """Constructor - - Parameters - ---------- - - numTopoDims - number of topological dimensions - - numSpaceDims - number of space dimensions - """ - # handle to the grid object - self.grid = None - # whether or not nodes were added - self.nodesAdded = False - # whether or not cells were added - self.cellsAdded = False - # the local processor rank - self.pe = 0 - # number of processors - self.nprocs = 1 - # communicator - self.comm = None - - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - self.grid = ESMF.Mesh( - parametric_dim=numTopoDims, - spatial_dim=numSpaceDims) - - def setCells(self, cellIndices, cellTypes, connectivity, - cellMask=None, cellAreas=None): - """ - Set Cell connectivity - - Parameters - ---------- - - cell indices (0-based) - - cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - - connectivity node connectivity array, see below for node ordering - - cellMask - - cellAreas area (volume) of each cell - - Note - ---- - - 3 - / \ - / \ - / \ - / \ - / \ - 1 --------- 2 - - - - - 4------------3 - | | - | | - | | - | | - | | - 1 ---------- 2 - - - - 3 8---------------7 - /|\ /| /| - / | \ / | / | - / | \ / | / | - / | \ / | / | - / | \ 5---------------6 | - 4-----|-----2 | | | | - \ | / | 4----------|----3 - \ | / | / | / - \ | / | / | / - \ | / | / | / - \|/ |/ |/ - 1 1---------------2 - - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX - - """ - n = len(cellIndices) - if not self.cellsAdded: - # node/cell indices are 1-based in ESMF - cellIndices += 1 - self.grid.add_elements(n, cellIndices, cellTypes, - connectivity, elementMask=cellMask, - elementArea=cellAreas) - self.cellsAdded = True - - def setNodes(self, indices, coords, peOwners=None): - """ - Set the nodal coordinates - - Parameters - ---------- - - indices Ids of the nodes (0-based) - - coords nodal coordinates - - peOwners processor ranks where the coordinates reside (0-based) - """ - n = len(indices) - if not self.nodesAdded: - if peOwners is None: - peOwners = numpy.ones((n,), numpy.int32) * self.pe - # node indices are 1-based - indices += 1 - self.grid.add_nodes(n, indices, coords, peOwners) - self.nodesAdded = True - - def toVTK(self, filename): - """ - Write grid to VTK file format - - Parameters - ---------- - - filename VTK file name - _: None - - """ - self.grid.write(filename) - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructGrid: - """ - Structured grid - """ - - def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, - periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, - hasBounds=False): - """ - Constructor - - Parameters - ---------- - - shape Tuple of cell sizes along each axis - - coordSys coordinate system - ESMF.CoordSys.CART Cartesian - ESMF.CoordSys.SPH_DEG (default) Degrees - ESMF.CoordSys.SPH_RAD Radians - - periodicity Does the grid have a periodic coordinate - 0 No periodicity - 1 Periodic in x (1st) axis - 2 Periodic in x, y axes - - staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX - The stagger constants are listed at the top - - hasBounds If the grid has bounds, Run AddCoords for the bounds - """ - # ESMF grid object - self.grid = None - # number of cells in [z,] y, x on all processors - self.shape = shape[::-1] - # number of dimensions - self.ndims = len(self.shape) - # whether or not cell areas were set - self.cellAreasSet = False - # whether or not nodal coords were set - self.nodesSet = False - # whether or not cell centered coordinates were set - self.centersSet = False - - # assume last 2 dimensions are Y,X - # For esmf reverse to X, Y - maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) - - self.centersSet = False - periodic_dim = 0 - pole_dim = 1 - if periodicity == 0: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], - coord_sys=coordSys) - elif periodicity == 1: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, - periodic_dim=periodic_dim, pole_dim=pole_dim, - staggerloc=[staggerloc], coord_sys=coordSys) - else: - msg = """ -esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. - """ % periodicity - raise RegridError(msg) - - # Grid add coordinates call must go here for parallel runs - # This occur before the fields are created, making the fields - # parallel aware. - if ((staggerloc == CENTER) and (not self.centersSet)): - self.centersSet = True - elif (staggerloc == CORNER) and (not self.nodesSet): - self.nodesSet = True - - if hasBounds is not None: - if self.ndims == 2: - self.grid.add_coords([CORNER], coord_dim=None, from_file=False) - if self.ndims == 3: - self.grid.add_coords( - [VCORNER], coord_dim=None, from_file=False) - - def getLocalSlab(self, staggerloc): - """ - Get the local slab (ellipsis). You can use this to grab - the data local to this processor - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple of slices - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([slice(lo[i], hi[i], None) - for i in range(self.ndims)])[::-1] - - def getLoHiBounds(self, staggerloc): - """ - Get the local lo/hi index values for the coordinates (per processor) - (hi is not inclusive, lo <= index < hi) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - lo, hi lists - """ - lo = self.grid.lower_bounds[staggerloc] - hi = self.grid.upper_bounds[staggerloc] - return lo, hi - - def getCoordShape(self, staggerloc): - """ - Get the local coordinate shape (may be different on each processor) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] - - def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): - """ - Populate the grid with staggered coordinates (e.g. corner or center). - - - Parameters - ---------- - - coords - The curvilinear coordinates of the grid. - List of numpy arrays. Must exist on all procs. - - staggerloc - The stagger location - ESMF.StaggerLoc.CENTER (default) - ESMF.StaggerLoc.CORNER - - globalIndexing - if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - - Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, - hence the dimensions are reversed here. - """ - # allocate space for coordinates, can only add coordinates once - for i in range(self.ndims): - ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) - if globalIndexing: - slab = self.getLocalSlab(staggerloc)[::-1] - # Populate self.grid with coordinates or the bounds as needed - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] - else: - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] - - def getCoords(self, dim, staggerloc): - """ - Return the coordinates for a dimension - - Parameters - --------- - - dim desired dimension (zero based indexing) - - staggerloc Stagger location - """ - gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) - shp = self.getCoordShape(staggerloc)[::-1] - return numpy.reshape(gridPtr, shp).T - - def setCellAreas(self, areas): - """ - Set the cell areas - - Parameters - --------- - - areas numpy array - - _: None - - """ - self.grid.add_item(item=ESMF.GridItem.Area) - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - areaPtr[:] = areas.T.flat - self.cellAreasSet = True - - def getCellAreas(self): - """ - - Returns - ------- - - cell areas or None if setCellAreas was not called - """ - if self.cellAreasSet: - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - return numpy.reshape(areaPtr, self.shape).T - else: - return None - - def getMask(self, staggerloc=CENTER): - """ - Get mask array. In ESMF, the mask is applied to cells. - - Returns - ------- - - mask numpy array. 1 is invalid by default. This array exists on all procs - """ - try: - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, staggerloc=staggerloc) - except BaseException: - maskPtr = None - return maskPtr.T - - def setMask(self, mask, staggerloc=CENTER): - """ - Set mask array. In ESMF, the mask is applied to cells. - - Parameters - ---------- - - mask numpy array. 1 is invalid by default. This array exists - on all procs - - _: None - """ - self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, - staggerloc=staggerloc) - slab = self.getLocalSlab(CENTER)[::-1] - maskPtr[:] = mask.T[slab] - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructField: - """ - Structured field. - """ - - def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): - """ - Creator for structured ESMF Field - - Parameters - ---------- - - esmfGrid - instance of an ESMF - - name field - name (must be unique) - - datatype - data type, one of 'float64', 'float32', 'int64', or 'int32' - (or equivalent numpy dtype) - - staggerloc - ESMF.StaggerLoc.CENTER - ESMF.StaggerLoc.CORNER - """ - # field object - self.field = None - # the local processor rank - self.pe = 0 - # the number of processors - self.nprocs = 1 - # associated grid - self.grid = esmfGrid - # staggering - self.staggerloc = staggerloc - # communicator - self.comm = None - - try: - from mpi4py import MPI - self.comm = MPI.COMM_WORLD - except BaseException: - pass - - etype = None - sdatatype = str(datatype) # in case user passes a numpy dtype - if re.search('float64', sdatatype): - etype = R8 - elif re.search('float32', sdatatype): - etype = R4 - elif re.search('int64', sdatatype): - etype = I8 - elif re.search('int32', sdatatype): - etype = I4 - else: - msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype - raise RegridError(msg) - - self.field = ESMF.Field( - grid=esmfGrid.grid, - name=name, - typekind=etype, - staggerloc=staggerloc) - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - def getPointer(self): - """ - Get field data as a flat array - - Returns - ------- - - pointer - """ - return numpy.ravel(self.field.data) - - def getData(self, rootPe): - """ - Get field data as a numpy array - - Parameters - ---------- - - rootPe if None then local data will be fetched, otherwise - gather the data on processor "rootPe" (all other - procs will return None). - - _: None - - Returns - ------- - - numpy array or None - """ - ptr = self.getPointer() - if rootPe is None: - shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] - # local data, copy - return numpy.reshape(ptr, shp).T - else: - # gather the data on rootPe - lo, hi = self.grid.getLoHiBounds(self.staggerloc) - los = [lo] - his = [hi] - ptrs = [ptr] - ptr = numpy.reshape(ptr, hi) - if self.comm is not None: - los = self.comm.gather(lo) # Local - his = self.comm.gather(hi) # Local - ptrs = self.comm.gather(ptr, root=rootPe) - - if self.pe == rootPe: # Local - # reassemble, find the largest hi indices to set - # the shape of the data container - bigHi = [0 for i in range(self.grid.ndims)] - for i in range(self.grid.ndims): - bigHi[i] = reduce(lambda x, y: max(x, y), - [his[p][i] for p in range(self.nprocs)]) - # allocate space to retrieve the data - bigData = numpy.empty(bigHi, ptr.dtype) - bigData[:] = 0.0 - - # populate the data - for p in range(self.nprocs): - slab = tuple([slice(los[p][i], his[p][i], None) for - i in range(self.grid.ndims)]) - # copy - bigData[slab].flat = ptrs[p] - return bigData.T # Local - - # rootPe is not None and self.pe != rootPe - return None - - def setLocalData(self, data, staggerloc, globalIndexing=False): - """ - Set local field data - - Parameters - ---------- - - data full numpy array, this method will take care of setting a - the subset of the data that reside on the local processor - - staggerloc stagger location of the data - - - globalIndexing if True array was allocated over global index - space, array was allocated over local index - space (on this processor) - """ - ptr = self.field.data - if globalIndexing: - slab = self.grid.getLocalSlab(staggerloc)[::-1] - ptr[:] = data.T[slab] - else: - ptr[:] = data.T - - -########################################################################## - -class EsmfRegrid: - """ - Regrid source grid data to destination grid data - """ - - def __init__(self, srcField, dstField, - srcFrac=None, - dstFrac=None, - srcMaskValues=None, - dstMaskValues=None, - regridMethod=BILINEAR, - ignoreDegenerate=False, - unMappedAction=IGNORE): - """ - Constuct regrid object - - Parameters - ---------- - - srcField - the source field object of type EsmfStructField - - dstField - the destination field object of type EsmfStructField - - srcMaskValues - Value of masked cells in source - - dstMaskValues - Value of masked cells in destination - - srcFrac - Cell fractions on source grid (type EsmfStructField) - - dstFrac - Cell fractions on destination grid (type EsmfStructField) - - regridMethod - ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - - unMappedAction - ESMF.UnmappedAction.{IGNORE,ERROR} - - ignoreDegenerate - Ignore degenerate cells when checking inputs - """ - self.srcField = srcField - self.dstField = dstField - self.regridMethod = regridMethod - self.srcAreaField = None - self.dstAreaField = None - self.srcFracField = srcFrac - self.dstFracField = dstFrac - self.regridHandle = None - self.ignoreDegenerate = ignoreDegenerate - - timeStamp = re.sub('\.', '', str(time.time())) - - # create and initialize the cell areas to zero - if regridMethod == CONSERVE: - self.srcAreaField = EsmfStructField(self.srcField.grid, - name='src_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcAreaField.getPointer() - dataPtr[:] = 0.0 - self.dstAreaField = EsmfStructField(self.dstField.grid, - name='dst_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstAreaField.getPointer() - dataPtr[:] = 0.0 - - # initialize fractional areas to 1 (unless supplied) - if srcFrac is None: - self.srcFracField = EsmfStructField(self.srcField.grid, - name='src_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcFracField.getPointer() - dataPtr[:] = 1.0 - - if dstFrac is None: - self.dstFracField = EsmfStructField(self.dstField.grid, - name='dst_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstFracField.getPointer() - dataPtr[:] = 1.0 - - srcMaskValueArr = None - if srcMaskValues is not None: - srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) - - dstMaskValueArr = None - if dstMaskValues is not None: - dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) - - self.regridHandle = ESMF.Regrid( - srcField.field, - dstField.field, - src_frac_field=self.srcFracField.field, - dst_frac_field=self.dstFracField.field, - src_mask_values=srcMaskValueArr, - dst_mask_values=dstMaskValueArr, - regrid_method=regridMethod, - unmapped_action=unMappedAction, - ignore_degenerate=self.ignoreDegenerate) - - def getSrcAreas(self, rootPe): - """ - Get the src grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.srcAreaField.data.T - return None - - def getDstAreas(self, rootPe): - """ - Get the dst grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.dstAreaField.data.T - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.srcFracField is not None: - # self.srcFracField.get_area() - return self.srcFracField.data.T - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.dstFracField is not None: - # self.dstFracField.get_area() - return self.dstFracField.data.T - return None - - def __call__(self, srcField=None, dstField=None, zero_region=None): - """ - Apply interpolation weights - - Parameters - ---------- - - srcField source field (or None if src field passed to - constructor is to be used) - - dstField destination field (or None if dst field passed - to constructor is to be used) - - zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) - """ - if srcField is None: - srcField = self.srcField - if dstField is None: - dstField = self.dstField - - # default is keep the masked values intact - zeroregion = ESMF.Region.SELECT - if self.regridMethod == CONSERVE: - zeroregion = None # will initalize to zero - - self.regridHandle( - srcfield=srcField.field, - dstfield=dstField.field, - zero_region=zeroregion) - - def __del__(self): - if self.regridHandle is not None: - self.regridHandle.destroy() diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py deleted file mode 100644 index de150dba..00000000 --- a/regrid2/Lib/gsRegrid.py +++ /dev/null @@ -1,1179 +0,0 @@ -#!/usr/bin/env python - -""" -Regridding of curvilinear structured grids -Alex Pletzer and Dave Kindig, Tech-X (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. -""" -# standard python includes -# from re import search, sub -from ctypes import c_double, c_float, c_int, \ - c_wchar_p, CDLL, byref, POINTER -# import ctypes -import operator -import sys -import os -import copy -import numpy -import warnings -from regrid2 import RegridError -from functools import reduce -import fnmatch - -C_DOUBLE_P = POINTER(c_double) - -# libcf -try: - from pycf import libCFConfig, __path__ -except BaseException: - raise ImportError('Error: could not import pycf') - -LIBCFDIR = __path__[0] + "/pylibcf" - -__FILE__ = sys._getframe().f_code.co_filename - - -def catchError(status, lineno): - if status != 0: - raise RegridError("ERROR in %s: status = %d at line %d" - % (__FILE__, status, lineno)) - - -def getTensorProduct(axis, dim, dims): - """ - Convert an axis into a curvilinear coordinate by applying - a tensor product - - Parameters - ---------- - - axis 1D array of coordinates - - dim dimensional index of the above coordinate - - dims sizes of all coordinates - - Returns - ------- - - coordinate values obtained by tensor product - """ - return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), - numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) - - -def makeCurvilinear(coords): - """ - Turn a mixture of axes and curvilinear coordinates into - full curvilinear coordinates - - Parameters - ---------- - - coords list of coordinates - - Returns - ------- - - new list of coordinates and associated dimensions - """ - rank = len(coords) - - count1DAxes = 0 - dims = [] - for i in range(rank): - coord = coords[i] - if len(coord.shape) == 1: - # axis - dims.append(len(coord)) - count1DAxes += 1 - elif len(coord.shape) == rank: - # fully curvilinear - dims.append(coord.shape[i]) - else: - # assumption: all 1D axes preceed curvilinear - # coordinates!!! - dims.append(coord.shape[i - count1DAxes]) - - for i in range(rank): - nd = len(coords[i].shape) - if nd == rank: - # already in curvilinear form, keep as is - pass - elif nd == 1: - # it's an axis - coords[i] = getTensorProduct(coords[i][:], i, dims) - elif rank == 3 and nd == 2 and i > 0: - # assume leading coordinate is an axis - o1 = numpy.ones((len(coords[0]),), coords[i].dtype) - coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) - else: - raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" - % (__FILE__, str([x.shape for x in coords]))) - return coords, dims - - -def makeCoordsCyclic(coords, dims): - """ - Make coordinates cyclic - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - new, extended coordinates such that the longitudes cover the sphere - and new dimensions - """ - # assume lon is the last coordinate!! - - # check if already extended - eps = 1.e-3 - - # some models already overlap - diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # some models are already periodic - diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # make cyclic by appending a column to the coordinates - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-1] += 1 # append to the right - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:-1] = coords[i][...] - newCoords[i][..., -1] = coords[i][..., 0] - - # add modulo term, want deltas ~ order of dlon otherwise add - # or subtract a periodicity length - nlon = dims[-1] - dlon = 360.0 / float(nlon) # average resolution - tol = 360.0 - min(5, nlon) * dlon - mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) - mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) - newCoords[-1][..., -1] += 360.0 * mask1 - newCoords[-1][..., -1] -= 360.0 * mask2 - - return newCoords, newDims - - -def checkForCoordCut(coords, dims): - """ - Look for a cut in a coordinate system (e.g. tri-polar grid) - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - True for cut found - False for no cut - """ - - # Assume latitude is next to last coordinate and longitude is last - # coordinate!!! - - rank = len(dims) - if rank < 2: - # print 'no cut: dims < 2' - return False - if len(coords[-2].shape) < 2: - # Is the 'lat' coordinate an axis? - return False - - nlat, nlon = dims[-2], dims[-1] - lat = coords[-2] - eps = 1.e-7 - - # Check to see if the top row has already be dealt with by the modeling - # agency. Last row is repeated in reverse. - - topRow = coords[-2][..., nlat - 1, :] - revTop = coords[-2][..., nlat - 1, ::-1] - nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow - diffs = abs(revTop - nextRow) - - # If already accounted for all diffs are 0. - if numpy.all(diffs < eps): - # print "no cut: reversed" - return False - - # Lon of max latitude -- Looking for a rotated pole - maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) - inTopRow = False - if len(maxLats[0] > 0): - inTopRow = numpy.all(maxLats[-2] == nlat - 1) - if not inTopRow: - # The max lats are not in the top row. The cut may already be handled - # print 'no cut: max lat not in top row.' + \ - # 'Either: it is a funky grid or rotated pole' - return False - - # Only in top row. - maxLatInd = lat[..., nlat - 1, :].argmax() - maxLonInd = lat[..., maxLatInd].argmax() - rowOfMaxLat = lat[..., maxLonInd, :] - diffs = rowOfMaxLat - topRow - - if diffs.max() != 0: - # Rotated Pole - # print "no cut: rotated pole" - return False - - # Find locale minima. - # A rotated pole grid has only one minimum. A tripolar grid should - # have two, though they may not be at the same latitude - - minInds = numpy.where(abs(topRow - topRow.min()) < eps) - if len(minInds[0]) > 2: - # Account for the end points matching - # Multiple minima in the top row - return True - - # Now if we have an offset tri-pole. The extra poles are not at the same - # latitude - minCount = 0 - firstInd = topRow.argmin() - diffs = numpy.diff(topRow) - if firstInd == 0: - if revTop.argmin() == 0: - if topRow[firstInd] == revTop[0]: - minCount += 1 - else: - minCount += 1 - # Look for next Minima - index = firstInd + 1 - while diffs[index] > 0: - index += 1 - if index == nlon: - break - nextIndex = topRow[index + 1:].argmin() + index + 1 - if nextIndex != index + 1 and nextIndex != nlon - 1: - minCount += 1 - if minCount == 1: - # print "no cut: one pole" - return False - - return True - - -def handleCoordsCut(coords, dims, bounds): - """ - Generate connectivity across a cut. e.g. from a tri-polar grid. - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates list of rank - - dims input dimensions - - bounds boundaries for each coordinate - - Returns - ------- - - extended coordinates such that there is an extra row containing - connectivity information across the cut - """ - - # Assume latitude is next to last coordinate and longitude is - # last coordinate!!! - - dims = coords[-2].shape - - # Add row to top with connectivity information. This means rearranging - # the top row - def getIndices(array, nlon, newI): - """ - Find indices where a cell edge matches for two cells - - Parameters - ---------- - - array Array of booleans - - nlon number of longitudes - - newI index row with connectivity to be updated - - Returns - ------- - - new coordinates, new dimensions, index row - """ - for i in range(len(array)): - # An edge - if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa - if newI[i] < 0: - newI[i] = (nlon - 1) - i - if newI[(nlon - 1) - i] < 0: - newI[(nlon - 1) - i] = i - - # Assume mkCyclic == True - newI = numpy.arange(nlon - 1, -1, -1) - 1 - newI[nlon - 1] = 0 # Complete the rotation - - # Build new coordinate array and adjust dims - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-2] += 1 - - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:dims[-2], :] = coords[i][...] - newCoords[i][..., dims[-2], - :] = coords[i][..., dims[-2] - 1, newI] - - return newCoords, newDims, newI - - -class Regrid: - - def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, - handleCut=False, verbose=False): - """ - Constructor - - Parameters - ---------- - - src_grid source grid, a list of [x, y, ...] coordinates - or a cdms2.grid.Transient - - dst_grid destination grid, a list of [x, y, ...] coordinates - - src_bounds list of cell bounding coordinates (to be used when - handling a cut in coordinates) - - mkCyclic Add a column to the right side of the grid to complete - a cyclic grid - - handleCut Add a row to the top of grid to handle a cut for - grids such as the tri-polar grid - - verbose print diagnostic messages - - - Note: the grid coordinates can either be axes (rectilinear grid) or - n-dimensional for curvilinear grids. Rectilinear grids will - be converted to curvilinear grids. - """ - self.regridid = c_int(-1) - self.src_gridid = c_int(-1) - self.dst_gridid = c_int(-1) - self.rank = 0 - self.src_dims = [] - self.dst_dims = [] - self.src_coords = [] - self.dst_coords = [] - self.lib = None - self.extendedGrid = False - self.handleCut = False - self.dst_Index = [] - self.verbose = verbose - self.weightsComputed = False - self.maskSet = False - - # Open the shaped library - dynLibFound = False - for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': - if os.path.exists(LIBCFDIR + sosuffix): - dynLibFound = True - CFfile = self.find('pylibcf.*', __path__[0]) - if os.path.exists(CFfile): - try: - self.lib = CDLL(CFfile) - except BaseException: - pass -# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': -# if os.path.exists(LIBCFDIR + sosuffix): -# dynLibFound = True -# try: -# self.lib = CDLL(LIBCFDIR + sosuffix) -# break -# except: -# pass - if self.lib is None: - if not dynLibFound: - raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - - # Number of space dimensions - self.rank = len(src_grid) - - if len(dst_grid) != self.rank: - raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" - % (__FILE__, len(dst_grid), self.rank)) - - if self.rank <= 0: - raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" - % (__FILE__, self.rank)) - - # Convert src_grid/dst_grid to curvilinear grid, if need be - if self.rank > 1: - src_grid, src_dims = makeCurvilinear(src_grid) - dst_grid, dst_dims = makeCurvilinear(dst_grid) - - # Make sure coordinates wrap around if mkCyclic is True - if mkCyclic: - src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - for i in range(self.rank): - print(('...... src_gridNew[%d].shape = %s' - % (i, str(src_gridNew[i].shape)))) - # flag indicating that the grid was extended - if reduce(lambda x, y: x + y, - [src_dimsNew[i] - src_dims[i] - for i in range(self.rank)]) > 0: - self.extendedGrid = True - # reset - src_grid = src_gridNew - src_dims = src_dimsNew - - # Handle a cut in the coordinate system. Run after mkCyclic. - # e.g. a tri-polar grid - if handleCut and src_bounds is not None: - # Test for the presence of a cut. - isCut = checkForCoordCut(src_grid, src_dims) - if isCut: - # No cut - src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, - src_dims, src_bounds) - if dst_Index is not None: - self.handleCut = True - self.extendedGrid = self.extendedGrid - else: - self.handleCut = False - self.extendedGrid = self.extendedGrid - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - src_grid = src_gridNew - src_dims = src_dimsNew - self.dst_Index = dst_Index - - self.src_dims = (c_int * self.rank)() - self.dst_dims = (c_int * self.rank)() - - # Build coordinate objects - src_dimnames = (c_wchar_p * self.rank)() - dst_dimnames = (c_wchar_p * self.rank)() - for i in range(self.rank): - src_dimnames[i] = 'src_n%d' % i - dst_dimnames[i] = 'dst_n%d' % i - self.src_dims[i] = src_dims[i] - self.dst_dims[i] = dst_dims[i] - self.src_coordids = (c_int * self.rank)() - self.dst_coordids = (c_int * self.rank)() - save = 0 - standard_name = "" - units = "" - coordid = c_int(-1) - for i in range(self.rank): - data = numpy.array(src_grid[i], numpy.float64) - self.src_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "src_coord%d" % i - # assume [lev,] lat, lon ordering - if i == self.rank - 2: - standard_name = 'latitude' - units = 'degrees_north' - elif i == self.rank - 1: - standard_name = 'longitude' - units = 'degrees_east' - status = self.lib.nccf_def_coord(self.rank, self.src_dims, - src_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.src_coordids[i] = coordid - - data = numpy.array(dst_grid[i], numpy.float64) - self.dst_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "dst_coord%d" % i - status = self.lib.nccf_def_coord(self.rank, self.dst_dims, - dst_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.dst_coordids[i] = coordid - - # Build grid objects - status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", - byref(self.src_gridid)) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", - byref(self.dst_gridid)) - catchError(status, sys._getframe().f_lineno) - - # Create regrid object - status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, - byref(self.regridid)) - catchError(status, sys._getframe().f_lineno) - - def getPeriodicities(self): - """ - Get the periodicity lengths of the coordinates - - Returns - ------- - - numpy array, values inf indicate no periodicity - """ - coord_periodicity = numpy.zeros((self.rank,), numpy.float64) - status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, - coord_periodicity.ctypes.data_as(C_DOUBLE_P)) - catchError(status, sys._getframe().f_lineno) - return coord_periodicity - - def __del__(self): - """ - Destructor, will be called automatically - """ - status = self.lib.nccf_free_regrid(self.regridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.src_gridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.dst_gridid) - catchError(status, sys._getframe().f_lineno) - - for i in range(self.rank): - - status = self.lib.nccf_free_coord(self.src_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_coord(self.dst_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - def find(self, pattern, path): - result = "" - for root, dirs, files in os.walk(path): - for name in files: - if fnmatch.fnmatch(name, pattern): - result = os.path.join(root, name) - return result - - def setValidMask(self, inMask): - """ - Set valid mask array for the grid - - Parameters - ---------- - - inMask flat numpy array of type numpy.int32 or a valid cdms2 variable - with its mask set. - 0 - invalid, 1 - valid data - - Note: This must be invoked before computing the weights, the - mask is a property of the grid (not the data). - """ - if self.weightsComputed: - raise RegridError('Must set mask before computing weights') - - mask = numpy.array(inMask, dtype=numpy.int32) - - # extend src data if grid was made cyclic and or had a cut accounted - # for - newMask = self._extend(mask) - c_intmask = newMask.ctypes.data_as(POINTER(c_int)) - status = self.lib.nccf_set_grid_validmask(self.src_gridid, - c_intmask) - catchError(status, sys._getframe().f_lineno) - self.maskSet = True - - def setMask(self, inDataOrMask): - """ - Set mask array. The mask is defined for nodes - - Parameters - ---------- - - inDataOrMask cdms2 array or flat mask array, - 0 - valid data - 1 - invalid data - - Note: this definition is compatible with the numpy masked arrays - - Note: note see setValidMask for the opposite definition - - Note: should be called before computing the weights - """ - mask = None - if hasattr(inDataOrMask, 'getmask'): - # cdms2 variable - mask = inDataOrMask.getmask() - else: - # flat mask array - mask = inDataOrMask - # reversing the meaning 1 == valid, 0 == invalid - mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) - # now calling our own mask setter - self.setValidMask(mask) - - def computeWeights(self, nitermax=100, tolpos=1.e-2): - """ - Compute the the interpolation weights - - Parameters - ---------- - - nitermax max number of iterations - - tolpos max tolerance when locating destination positions in - index space - """ - status = self.lib.nccf_compute_regrid_weights(self.regridid, - nitermax, - c_double(tolpos)) - catchError(status, sys._getframe().f_lineno) - self.weightsComputed = True - - def apply(self, src_data_in, dst_data, missingValue=None): - """ - Apply interpolation - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - if not self.weightsComputed: - raise RegridError('Weights must be set before applying the regrid') - # extend src data if grid was made cyclic and or had a cut accounted - # for - src_data = self._extend(src_data_in) - - # Check - if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + - "%s != %s") % (__FILE__, str(src_data.shape), - str(tuple([d for d in self.src_dims])))) - if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + - "%s != %s") % (__FILE__, str(dst_data.shape), - str(tuple([d for d in self.dst_dims])))) - - # Create temporary data objects - src_dataid = c_int(-1) - dst_dataid = c_int(-1) - save = 0 - standard_name = "" - units = "" - time_dimname = "" - - status = self.lib.nccf_def_data(self.src_gridid, "src_data", - standard_name, units, time_dimname, - byref(src_dataid)) - catchError(status, sys._getframe().f_lineno) - - if src_data.dtype != dst_data.dtype: - try: # try recasting - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" - % (src_data.dtype, dst_data.dtype)) - src_data = src_data.astype(dst_data.dtype) - except BaseException: - try: - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" - % (src_data.dtype, dst_data.dtype)) - dst_data = dst_data.astype(src_data.dtype) - except BaseException: - raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" - % (__FILE__, src_data.dtype, dst_data.dtype)) - - # only float64 and float32 data types are supported for interpolation - if src_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif src_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" - % (__FILE__, src_data.dtype)) - - status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", - standard_name, units, time_dimname, - byref(dst_dataid)) - catchError(status, sys._getframe().f_lineno) - if dst_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif dst_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid dst_data type = %s" - % (__FILE__, dst_data.dtype)) - - # Now apply weights - status = self.lib.nccf_apply_regrid( - self.regridid, src_dataid, dst_dataid) - catchError(status, sys._getframe().f_lineno) - - # Clean up - status = self.lib.nccf_free_data(src_dataid) - catchError(status, sys._getframe().f_lineno) - status = self.lib.nccf_free_data(dst_dataid) - catchError(status, sys._getframe().f_lineno) - - return dst_data - - def __call__(self, src_data, dst_data, missingValue=None): - """ - Apply interpolation (synonymous to apply method) - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - self.apply(src_data, dst_data, missingValue) - - def getNumValid(self): - """ - Return the number of valid destination points. Destination points - falling outside the source domain, more gnerally, points which - could not be located on the source grid, reduce the number of - valid points. - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_nvalid(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getNumDstPoints(self): - """ - Return the number of points on the destination grid - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_ntargets(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getSrcGrid(self): - """ - Return the source grid - - Returns - ------- - - grid - """ - return self.src_coords - - def getDstGrid(self): - """ - Return the destination grid - - Returns - ------- - - grid - """ - return self.dst_coords - - def getIndicesAndWeights(self, dst_indices): - """ - Get the indices and weights for a single target location - - Parameters - ---------- - - dst_indices index set on the target grid - - Returns - ------- - - [index sets on original grid, weights] - """ - dinds = numpy.array(dst_indices) - sinds = (c_int * 2**self.rank)() - weights = numpy.zeros((2**self.rank,), numpy.float64) - status = self.lib.nccf_inq_regrid_weights(self.regridid, - dinds.ctypes.data_as( - POINTER(c_double)), - sinds, - weights.ctypes.data_as(POINTER(c_double))) - catchError(status, sys._getframe().f_lineno) - # convert the flat indices to index sets - ori_inds = [] - for i in range(2**self.rank): - inx = numpy.zeros((self.rank,), numpy.int32) - self.lib.nccf_get_multi_index(self.rank, self.src_dims, - sinds[i], - inx.ctypes.data_as(POINTER(c_int))) - ori_inds.append(inx) - - return ori_inds, weights - - def _extend(self, src_data): - """ - Extend the data by padding a column and a row, depending on whether the - grid was made cyclic and a fold was added or not - - Parameters - ---------- - - src_data input source data - - Returns - ------- - - extended source data (or source input data of no padding was applied) - """ - - # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] - # original dimensions, before extension - # assuming ..., lat, lon ordering - nlat, nlon = src_data.shape[-2:] - - # no cut and no cyclic extension - src_dataNew = src_data - - if self.handleCut or self.extendedGrid: - # copy data into new, extended container - src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) - # start filling in... - src_dataNew[..., :nlat, :nlon] = src_data[...] - - if self.handleCut: - # fill in polar cut (e.g. tripolar cut), top row - # self.dst_Index[i] knows how to fold - for i in range(nlon): - src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] - - if self.extendedGrid: - # make data periodic in longitudes - src_dataNew[..., -1] = src_dataNew[..., 0] - - return src_dataNew - - def _findIndices(self, targetPos, nitermax, tolpos, - dindicesGuess): - """ - Find the floating point indices - - Parameters - ---------- - - targetPos numpy array of target positions - - nitermax max number of iterations - - tolpos max toelrance in positions - - dindicesGuess guess for the floating point indices - - Returns - ------- - - indices, number of iterations, achieved tolerance - """ - posPtr = targetPos.ctypes.data_as(POINTER(c_double)) - adjustFunc = None - hit_bounds = numpy.zeros((self.rank), - dtype=int).ctypes.data_as(POINTER(c_int)) - # no periodicity - coord_periodicity = float( - 'inf') * numpy.ones((self.rank), targetPos.dtype) - coord_periodicity_ptr = coord_periodicity.ctypes.data_as( - POINTER(c_double)) - res = copy.copy(dindicesGuess) - resPtr = res.ctypes.data_as(POINTER(c_double)) - src_coords = (POINTER(c_double) * self.rank)() - niter = c_int(nitermax) - tol = c_double(tolpos) - for i in range(self.rank): - ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) - src_coords[i] = ptr - status = self.lib.nccf_find_indices_double(self.rank, - self.src_dims, - src_coords, - coord_periodicity_ptr, - posPtr, - byref(niter), - byref(tol), - adjustFunc, - resPtr, - hit_bounds) - catchError(status, sys._getframe().f_lineno) - return resPtr.contents.value, niter.value, tol.value - -###################################################################### - - -def testMakeCyclic(): - - y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) - x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) - yy = getTensorProduct(y, 0, [len(y), len(x)]) - xx = getTensorProduct(x, 1, [len(y), len(x)]) - coords = [yy, xx] - dims = [len(y), len(x)] - newCoords, newDims = makeCoordsCyclic(coords, dims) -# print 'cyclic lats' -# print newCoords[0] -# print 'cyclic lons' -# print newCoords[1] - - -def testHandleCut(): - - import cdms2 - # Need tripolar grid - filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" - f = cdms2.open(filename) - if not f: - return - - # so = f.variables['so'][0, 0, :, :] - if 'lon' in list(f.variables.keys()): - alllat = f.variables['lat'] - alllon = f.variables['lon'] - else: - alllat = f.getAxis("lat").getData() - alllon = f.getAxis("lon").getData() - - bounds = [f.variables['bounds_lon'][:].data, - f.variables['bounds_lat'][:].data] - coords = [alllat[:].data, alllon[:].data] - dims = alllat.shape - newCoords, newDims = makeCoordsCyclic(coords, dims) - newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) - - -# def testOuterProduct(): - - # 2d - # x = numpy.array([1, 2, 3, 4]) - # y = numpy.array([10, 20, 30]) - # xx = getTensorProduct(x, 0, [len(x), len(y)]) - # yy = getTensorProduct(y, 1, [len(x), len(y)]) - - # z = numpy.array([100, 200]) - # Mixed coordinates and axes - # aa = makeCurvilinear([z, yy, xx]) - # for g in aa: - # print g - -def test(): - def func1(coords): - return coords[0] * coords[1] + coords[2] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = numpy.array([1, 2, 3, 4, 5, 6]) - src_y = numpy.array([10, 20, 30, 40, 50]) - src_z = numpy.array([100, 200]) - - # destination grid, product of axes - dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) - dst_y = numpy.array([15., 20., 25., 30., 40.]) - dst_z = numpy.array([120.0, 180.0, 240.]) - - # regridding constructor - rg = Regrid([src_x, src_y, src_z], - [dst_x, dst_y, dst_z]) -# rg = Regrid([src_x, src_y], -# [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - maxNumIters = 20 - posTol = 1.e-3 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data = ', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -def testMasking(): - import numpy.ma as ma - - def func1(coords): - return coords[0] * coords[1] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) - src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) - - # destination grid, product of axes - dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, - 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) - dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) - - # regridding constructor - rg = Regrid([src_x, src_y], - [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - # Mask needs to be set before weights are computed - mask = rg.getSrcGrid()[0] == 3 - mask[:, 3] = True - rg.setValidMask(mask) - rg.setMask(mask) - maxNumIters = 20 - posTol = 1.e-2 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data =\n', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -if __name__ == '__main__': - # testOuterProduct() - test() - testMasking() - # testMakeCyclic() - # testHandleCut() diff --git a/regrid2/Lib/gs_horizontal.py b/regrid2/Lib/gs_horizontal.py deleted file mode 100644 index 20cfa4a6..00000000 --- a/regrid2/Lib/gs_horizontal.py +++ /dev/null @@ -1,214 +0,0 @@ -import sys -import os -import os.path -# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer -from ctypes import CDLL, c_double, c_uint -import cdms2 -import time -import config -sys.path.append("/home/painter1/libcf/") -libcf = CDLL(config.prefix + '/lib/libcf.so') - - -class GS_Regridder: - - def __init__(self, ingrid, outgrid, - infile=None, outfile=None, remapfile=None): - # Save the grids, make and save a Gridspec remap file. - # For now, we are using the libCF/Gridspec API which operates only on files; - # thus temporary files are written out and read back in. That requires the - # input grids to support a "write_gridspec" method. - # If a path is provided, it prefixes whatever filenames were input. - # If there is no path provided, each filename must include its path. - # Note: it's a bit messy to keep filenames and paths separate internally, - # but the presnet Gridspec function expects lots of directories. - - self.ingrid = ingrid - self.outgrid = outgrid - if (not hasattr(ingrid, "gsfile")): - ingrid.gsfile = None - ingrid.gspath = None - if (infile is None): - self.infile = ingrid.gsfile - self.inpath = ingrid.gspath - else: - self.infile = os.path.basename(infile) - self.inpath = os.path.dirname(infile) - if (not os.path.isfile(self.inpath + "/" + self.infile)): - raise OSError( - "cannot open infile " + - self.inpath + - "/" + - self.infile) - - if (not hasattr(outgrid, "gsfile")): - outgrid.gsfile = None - outgrid.gspath = None - if (outfile is None): - self.outfile = outgrid.gsfile - self.outpath = outgrid.gspath - else: - self.outfile = os.path.basename(outfile) - self.outpath = os.path.dirname(outfile) - if (not os.path.isfile(self.outpath + "/" + self.outfile)): - raise OSError( - "cannot open outfile " + - self.outpath + - "/" + - self.outfile) - - if (remapfile is None): - timestr = str(int(time.time())) - self.remapfile = "remap" + timestr - self.remappath = "/tmp" - else: - self.remapfile = os.path.basename(remapfile) - self.remappath = os.path.dirname(remapfile) - if (not os.path.isdir(self.remappath + "/")): - raise OSError( - "cannot open remapfile directory " + - self.remappath + - "/") - - ingrid.write_gridspec(self.inpath + "/" + self.infile) - outgrid.write_gridspec(self.outpath + "/" + self.outfile) - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - # No variables to interpolate; the gs_fregrid call will be just to - # make a remap file... - dir_in = 256 * "\x00" - dir_out = 256 * "\x00" - input_file = 256 * "\x00" - nfiles = 0 - output_file = 256 * "\x00" - nfiles_out = 0 - scalar_name = 256 * "\x00" - nscalar = 0 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - # For a call which only writes the remap files, gs_fregrid - # expects remapfile to be a full path. For a call in which - # remapping takes place, gs_fregrid expects remapfile to be - # a pure filename, in a path it gets from elsewhere, maybe dir_in. - # (ARRGH - but with the API slated to be replaced, I'll live with it) - remapf = os.path.abspath( - self.remappath + "/" + self.remapfile) + "\0" * 256 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - remapf, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - def __call__(self, ar): - # Interpolate the input variable to the new grid using the Gridspec - # remap file generated when this GS_Remapper object was initialized. - # >>>for now, ar is required to be a variable (MV) <<< - - # Here, convert ar into a file for gs_fregrid - # There's no special Gridspec way to write a variable; you write to any - # *.nc file. The tough part is making sure you have there exactly what's - # needed for the gs_fregrid call, especially because the grids are - # supposedly supergrids and you just have some keywords to use to figure - # out what goes where. And note that we'll need to check whether ar - # really lives on self.ingrid . Supposedly a future API will work - # better in this respect - - # Write the variable to a temporary file, as required by gs_fregrid. - # The remap path should be suitable. - # >>> this should be done more carefully, e.g. deal with failures; - # >>> more worth doing when we have mosaic variables. - timestr = str(int(time.time())) - varfile = cdms2.open( - self.inpath + - "/" + - "invvar" + - timestr + - ".nc", - 'w') - varfile.write(ar) - varfile.close() - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - dir_in = 256 * "\x00" # path is already encoded in input_file - dir_out = 256 * "\x00" # path is already encoded in output_file - input_file = varfile.id + 256 * "\x00" - nfiles = 1 - output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" - nfiles_out = 1 - scalar_name = ar.id + 256 * "\x00" - nscalar = 1 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - print(("__call__ remapfile=", self.remapfile)) - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - self.remapfile, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - # Read the output_file into a variable, and return the variable - f = cdms2.open(self.outpath + "/" + output_file) - vout = f(scalar_name) - f.close() - return vout diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py deleted file mode 100644 index 67d673f4..00000000 --- a/regrid2/Lib/horizontal.py +++ /dev/null @@ -1,422 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import warnings -import cdms2 - -_debug = 0 # Set to 1 for debug - -# Map (n,2) boundary arrays to individual boundary arrays. Returns -# (lowerBounds, upperBounds) - - -def extractBounds(bounds): - if bounds[0, 0] < bounds[0, 1]: - lower = bounds[:, 0] - upper = bounds[:, 1] - else: - lower = bounds[:, 1] - upper = bounds[:, 0] - - return (lower.astype(numpy.float32), upper.astype(numpy.float32)) - -# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid -# objects. - - -class Horizontal: - - def __init__(self, ingrid, outgrid): - """ - Constructor for regridding class - - Parameters - ---------- - - ingrid cdms2, ndarray variable - - outgrid cdms2, ndarray variable - """ - - inlat = ingrid.getLatitude() - outlat = outgrid.getLatitude() - inlon = ingrid.getLongitude() - outlon = outgrid.getLongitude() - inlatBounds, inlonBounds = ingrid.getBounds() - outlatBounds, outlonBounds = outgrid.getBounds() - - self.nlati = len(inlat) - self.nlato = len(outlat) - self.nloni = len(inlon) - self.nlono = len(outlon) - self.inmask = ingrid.getMask() - self.outmask = outgrid.getMask() - # Make grid masks consistent with 'internal' convention: - # 0 == invalid - if self.inmask is not None: - self.inmask = 1. - self.inmask - if self.outmask is not None: - self.outmask = 1. - self.outmask - self.inshape = ingrid.shape - self.inorder = ingrid.getOrder() - self.outlat = outgrid.getLatitude().clone() - self.outlon = outgrid.getLongitude().clone() - - bsin, bnin = extractBounds(inlatBounds) - bwin, bein = extractBounds(inlonBounds) - bsout, bnout = extractBounds(outlatBounds) - bwout, beout = extractBounds(outlonBounds) - - if _debug == 1: - import sys - sys.stdout = open('debug_regrid.txt', 'w') - print(("bsin = ", numpy.array2string(bsin, precision=3))) - print(("bnin = ", numpy.array2string(bnin, precision=3))) - print(("bwin = ", numpy.array2string(bwin, precision=3))) - print(("bein = ", numpy.array2string(bein, precision=3))) - print(("bsout = ", numpy.array2string(bsout, precision=3))) - print(("bnout = ", numpy.array2string(bnout, precision=3))) - print(("bwout = ", numpy.array2string(bwout, precision=3))) - print(("beout = ", numpy.array2string(beout, precision=3))) - - self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( - self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) - - def __call__(self, ar, missing=None, order=None, - mask=None, returnTuple=0, **args): - """ - Call the regridder function. - @param ar is the input array. - @param order is of the form "tzyx", "tyx", etc. - @param missing is the missing data value, if any. - @param mask is either 2-D or the same shape as ar. - @param returnTuple If true, return the tuple (outArray, outWeights) where - outWeights is the fraction of each zone of the output grid - which overlaps non-missing zones of the input grid; it has - the same shape as the output array. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Compatibility - if mask is numpy.ma.nomask: - mask = None - - if ar.dtype.type is numpy.bool_: - ar = numpy.asarray(ar, numpy.float32) - - # Make sense of mask consistent with 'internal' convention (0 == - # invalid) - if mask is not None: - mask = 1. - mask - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - armask = ar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - armask = tempar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armask = armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if mask is None and missing is None: - missing = armiss - mask = armask - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = self.inorder - elif rank == 3: - order = "t" + self.inorder - else: - order = "tz" + self.inorder - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to ilon, ilat ... - itim1 = itim2 = 0 - ilon = ilat = -1 - idim = 0 - for i in range(rank - 1, -1, -1): - c = order[i] - if c == 'x': - ilon = idim - elif c == 'y': - ilat = idim - elif c == 'z': - itim1 = idim - elif c == 't': - if rank == 3: - itim1 = idim - else: - itim2 = idim - idim = idim + 1 - - # Map array shape to nloni, nlati, ... - ntim1 = ntim2 = 0 - shape = ar.shape - if ilon == -1: - raise RegridError("Input grid does not have a longitude axis") - if ilat == -1: - raise RegridError("Input grid does not have a latitude axis") - nlati = shape[rank - ilat - 1] - nloni = shape[rank - ilon - 1] - if nlati != self.nlati or nloni != self.nloni: - raise ( - 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % - (nlati, nloni, self.nlati, self.nloni)) - - if itim1 != 0: - ntim1 = shape[rank - itim1 - 1] - if itim2 != 0: - ntim2 = shape[rank - itim2 - 1] - - # Construct the input mask: - # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask - # if no user mask is specified) - # with the 'implicit mask' generated from the missing data, if any - if (mask is None) or len(mask.shape) == 2: - flag2D = 1 - if mask is not None: - assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' - inmask = mask - elif self.inmask is None: - inmask = numpy.ones(self.inshape) - else: - inmask = self.inmask - - if missing is not None: - if rank == 2: - firstslice = ar - elif rank == 3: - firstslice = ar[0] - else: - firstslice = ar[0, 0] - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - firstslice - - missing), - numpy.absolute( - 0.001 * - missing)), - inmask, - 0) - - # If the user mask was specified and is > 2-D, it overrides the grid - # mask - else: - assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' - inmask = mask - flag2D = 0 # 2-D user masks are handled above - # If armask is derived from the input array, it is probably consistent - # with the missing value - don't bother recalculating it - if missing is not None and armask is None: - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - ar - missing), - numpy.absolute( - 0.001 * missing)), - inmask, - 0) - # Cast the mask to float - inmask = inmask.astype(numpy.float32) - if missing is None: - missing = 1.0e20 - - # Cast the input array to 32-bit floats, if necessary - if ar.dtype.char != numpy.float32: - ar = ar.astype(numpy.float32) - - # Malloc return array - outshape = list(shape) - outshape[rank - ilat - 1] = self.nlato - outshape[rank - ilon - 1] = self.nlono - outar = numpy.zeros(tuple(outshape), numpy.float32) - - # Perform the regridding. The return array has the same shape - # as the output array, and is the fraction of the zone which overlaps - # a non-masked zone of the input grid. - amskout = _regrid.rgdarea( - ilon, - ilat, - itim1, - itim2, - ntim1, - ntim2, - nloni, - self.nlono, - nlati, - self.nlato, - flag2D, - missing, - self.londx, - self.lonpt, - self.wtlon, - self.latdx, - self.latpt, - self.wtlat, - inmask, - ar, - outar) - - # Correct the shape of output weights - amskout.shape = outar.shape - - # Set the missing data mask of the output array, if any. - hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) - if hasMissing: - slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) - else: - slabMask = None - - # Combine missing data mask and output grid mask - # Note: slabMask and outmask are Boolean here - if self.outmask is not None: - outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) - if hasMissing: - outmask = numpy.ma.logical_or(outmask, slabMask) - else: - outmask = slabMask - - # Create the result TransientVariable (if input ar is an AbstractVariable) - # or masked array - if inputIsVariable == 1: - for i in range(len(order)): - if order[i] == 'x': - axislist[i] = self.outlon - elif order[i] == 'y': - axislist[i] = self.outlat - result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array( - outar, mask=outmask, fill_value=missing) - - if returnTuple == 0: - return result - else: - return result, amskout - - -class Regridder(Horizontal): - def __init__(self, ingrid, outgrid): - warnings.warn( - "While this will work for now, please note that the Regridder class has been " + - "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + - "Please edit your code accordingly", - Warning) - Horizontal.__init__(self, ingrid, outgrid) - - -def input_mask(ain, type, mask, missing=None): - """ #------------------------------------------------------------------- - # - # purpose: set up the input mask including missing from ain - # - # usage: - # - # passed : - # - # returned: - # - # - #------------------------------------------------------------------------""" - if type != 'h' and type != 'v': - raise ValueError('Mask type must be h or v') - return - - if missing is None: - try: - omit = ain.missing_value - except AttributeError: - omit = 1.0e20 - else: - omit = missing - - # ----- insert 0.0 in mask where array has missing data ------- - - mask_size = len(mask.shape) - data_size = len(ain.shape) - - if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a - - if data_size == 3: # caution: assuming standard order lat-lon varying the fastest - if type == 'h': - reduced = ain[0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[:, :, 0] - elif data_size == 4: - if type == 'h': - reduced = ain[0, 0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[0, :, :, 0] - else: - raise IndexError('Data size is out of range') - return - - amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - else: # 0.0 -> missing in passed mask - - amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - return omit, amskin diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py deleted file mode 100644 index 235e1fd5..00000000 --- a/regrid2/Lib/mvESMFRegrid.py +++ /dev/null @@ -1,483 +0,0 @@ -""" -ESMF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import re -import numpy - -import ESMF -from . import esmf -from . import RegridError -from .mvGenericRegrid import GenericRegrid - -ESMF.Manager(debug=False) -HAVE_MPI = False -try: - from mpi4py import MPI - HAVE_MPI = True -except BaseException: - pass - -# constants -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class ESMFRegrid(GenericRegrid): - """ - Regrid class for ESMF - """ - - def __init__(self, srcGridshape, dstGridshape, dtype, - regridMethod, staggerLoc, periodicity, coordSys, - srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, - dstGridMask=None, hasDstBounds=False, dstGridAreas=None, - ignoreDegenerate=False, - **args): - """ - Constructor - @param srcGridShape tuple source grid shape - @param dstGridShape tuple destination grid shape - @param dtype a valid numpy data type for the src/dst data - @param regridMethod 'linear', 'conserve', or 'patch' - @param staggerLoc the staggering of the field, 'center' or 'corner' - @param periodicity 0 (no periodicity), - 1 (last coordinate is periodic, - 2 (both coordinates are periodic) - @param coordSys 'deg', 'cart', or 'rad' - @param hasSrcBounds tuple source bounds shape - @param hasDstBounds tuple destination bounds shape - @param ignoreDegenerate Ignore degenerate celss when checking inputs - """ - - # esmf grid objects (tobe constructed) - self.srcGrid = None - self.dstGrid = None - self.dtype = dtype - - self.srcGridShape = srcGridshape - self.dstGridShape = dstGridshape - self.ignoreDegenerate = ignoreDegenerate - self.ndims = len(self.srcGridShape) - - self.hasSrcBounds = hasSrcBounds - self.hasDstBounds = hasDstBounds - - self.regridMethod = BILINEAR - self.regridMethodStr = 'linear' - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.regridMethod = CONSERVE - self.regridMethodStr = 'conserve' - elif re.search('patch', regridMethod.lower()): - self.regridMethod = PATCH - self.regridMethodStr = 'patch' - - # data stagger - self.staggerloc = CENTER - self.staggerlocStr = 'center' - if isinstance(staggerLoc, str): - if re.search('vface', staggerLoc.lower(), re.I): - self.staggerloc = VFACE - self.staggerlocStr = 'vcorner' - # there are other staggers we could test here - elif re.search('corner', staggerLoc.lower(), re.I) or \ - re.search('node', staggerLoc.lower(), re.I): - self.staggerloc = CORNER - self.staggerlocStr = 'corner' - # there are other staggers we could test here - - # good for now - unMappedAction = args.get('unmappedaction', 'ignore') - self.unMappedAction = ESMF.UnmappedAction.IGNORE - if re.search('error', unMappedAction.lower()): - self.unMappedAction = ESMF.UnmappedAction.ERROR - - self.coordSys = ESMF.CoordSys.SPH_DEG - self.coordSysStr = 'deg' - if re.search('cart', coordSys.lower()): - self.coordSys = ESMF.CoordSys.CART - self.coordSysStr = 'cart' - elif re.search('rad', coordSys.lower()): - self.coordSys = ESMF.CoordSys.SPH_RAD - self.coordSysStr = 'rad' - - self.periodicity = periodicity - - # masks can take several values in ESMF, we'll have just one - # value (1) which means invalid -# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) -# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) - - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.srcMaskValues = numpy.array([1], dtype=numpy.int32) - self.dstMaskValues = numpy.array([1], dtype=numpy.int32) - else: - self.srcMaskValues = srcGridMask - self.dstMaskValues = dstGridMask - - # provided by user or None - self.srcGridAreas = srcGridAreas - self.dstGridAreas = dstGridAreas - self.maskPtr = None - - # MPI stuff - self.pe = 0 - self.nprocs = 1 - self.comm = None - if HAVE_MPI: - self.comm = MPI.COMM_WORLD - self.pe = self.comm.Get_rank() - self.nprocs = self.comm.Get_size() - - # checks - if self.ndims != len(self.dstGridShape): - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological -dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ - (self.ndims, len(self.dstGridShape)) - raise RegridError(msg) - - # Initialize the grids without data. - self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasSrcBounds) - self.dstGrid = esmf.EsmfStructGrid(dstGridshape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasDstBounds) - - # Initialize the fields with data. - self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.srcFld.field.data[:] = -1 - self.dstFld.field.data[:] = -1 - self.srcAreaField.field.data[:] = 0.0 - self.dstAreaField.field.data[:] = 0.0 - self.srcFracField.field.data[:] = 1.0 - self.dstFracField.field.data[:] = 1.0 - - def setCoords(self, srcGrid, dstGrid, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - globalIndexing=False, **args): - """ - Populator of grids, bounds and masks - @param srcGrid list [[z], y, x] of source grid arrays - @param dstGrid list [[z], y, x] of dstination grid arrays - @param srcGridMask list [[z], y, x] of arrays - @param srcBounds list [[z], y, x] of arrays - @param srcGridAreas list [[z], y, x] of arrays - @param dstGridMask list [[z], y, x] of arrays - @param dstBounds list [[z], y, x] of arrays - @param dstGridAreas list [[z], y, x] of arrays - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - """ - - # create esmf source Grid - self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - - if srcGridMask is not None: - self.srcGrid.setMask(srcGridMask, self.staggerloc) - - if srcBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - # VCORNER for 3D - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - # create destination Grid - self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - if dstGridMask is not None: - self.dstGrid.setMask(dstGridMask) - - if dstBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args (not used) - """ - self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, - dstfield=self.dstFld.field, - src_mask_values=self.srcMaskValues, - dst_mask_values=self.dstMaskValues, - regrid_method=self.regridMethod, - unmapped_action=self.unMappedAction, - ignore_degenerate=True) - - def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): - """ - Regrid source to destination. - When used in parallel, if the processor is not the root processor, - the dstData returns None. - - Source data mask: - - . If you provide srcDataMask in args the source grid will - be masked and weights will be recomputed. - - . Subsequently, if you do not provide a srcDataMask the last - weights will be used to regrid the source data array. - - . By default, only the data are masked, but not the grid. - - @param srcData array source data, shape should - cover entire global index space - @param dstData array destination data, shape should - cover entire global index space - @param rootPe if other than None, then data will be MPI gathered - on the specified rootPe processor - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - @param **args - """ - -# if args.has_key('srcDataMask'): -# srcDataMask=args.get('srcDataMask') - # Make sure with have a mask intialized for this grid. - -# if(self.maskPtr is None): -# if(self.srcFld.field.grid.mask[self.staggerloc] is None): -# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) -# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, -# staggerloc=self.staggerloc) - # Recompute weights only if masks are different. -# if(not numpy.array_equal(self.maskPtr, srcDataMask)): -# self.maskPtr[:] = srcDataMask[:] -# self.computeWeights(**args) - - zero_region = ESMF.Region.SELECT - if 'zero_region' in args.keys(): - zero_region=args.get('zero_region') - - self.srcFld.field.data[:] = srcData.T - self.dstFld.field.data[:] = dstData.T - # regrid - - self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) - - # fill in dstData - if rootPe is None and globalIndexing: - # only fill in the relevant portion of the data - slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) - dstData[slab] = self.dstFld.getData(rootPe=rootPe) - else: - tmp = self.dstFld.field.data.T - if tmp is None: - dstData = None - else: - dstData[:] = tmp - - def getDstGrid(self): - """ - Get the destination grid on this processor - @return grid - """ - return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) - for i in range(self.ndims)] - - def getSrcAreas(self, rootPe): - """ - Get the source grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.srcAreaField.field.get_area() - return self.srcAreaField.field.data - else: - return None - - def getDstAreas(self, rootPe): - """ - Get the destination grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.dstAreaField.field.get_area() - return self.dstAreaField.field.data - else: - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.srcFracField.field.data - else: - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.dstFracField.field.data - else: - return - - def getSrcLocalShape(self, staggerLoc): - """ - Get the local source coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getCoordShape(stgloc) - - def getDstLocalShape(self, staggerLoc): - """ - Get the local destination coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getCoordShape(stgloc) - - def getSrcLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center'): - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getLocalSlab(stgloc) - - def getDstLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center') - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getLocalSlab(stgloc) - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'srcAreaFractions', 'dstAreaFractions', - 'srcAreas', 'dstAreas' - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - oldMethods = {} - oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' - oldMethods['dstAreaFractions'] = 'getDstAreaFractions' - oldMethods['srcAreas'] = 'getSrcAreas' - oldMethods['dstAreas'] = 'getDstAreas' - for entry in 'srcAreaFractions', 'dstAreaFractions', \ - 'srcAreas', 'dstAreas': - if entry in diag: - diag[entry] = eval( - 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T - diag['regridTool'] = 'esmf' - diag['regridMethod'] = self.regridMethodStr - diag['periodicity'] = self.periodicity - diag['coordSys'] = self.coordSysStr - diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py deleted file mode 100644 index 2452e9c4..00000000 --- a/regrid2/Lib/mvGenericRegrid.py +++ /dev/null @@ -1,313 +0,0 @@ -""" -Generic interface to multiple regrid classes. No dependence on cdms2 variables. - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import operator -import numpy - -import regrid2 -import re -from distarray import MultiArrayIter -from functools import reduce - -# used to locate fully masked cells -EPS = 10 * 1.19209e-07 - - -def guessPeriodicity(srcBounds): - """ - Guess if a src grid is periodic - @param srcBounds the nodal src set of coordinates - @return 1 if periodic, warp around, 0 otherwise - """ - res = 0 - if srcBounds is not None: - res = 1 - # assume longitude to be the last coordinate - lonsb = srcBounds[-1] - nlon = lonsb.shape[-1] - dlon = (lonsb.max() - lonsb.min()) / float(nlon) - tol = 1.e-2 * dlon - if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] - ).sum() / float(lonsb.size)) > tol: - # looks like a regional model - res = 0 - return res - - -class GenericRegrid: - """ - Generic Regrid class. - """ - - def __init__(self, srcGrid, dstGrid, - dtype, - regridMethod, - regridTool, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - **args): - """ - Constructor. - @param srcGrid list of numpy arrays, source horizontal coordinates - @param dstGrid list of numpy arrays, destination horizontal coordinate - @param dtype numpy data type for src/dst data - @param regridMethod linear (bi, tri,...) default or conservative - @param regridTool currently either 'libcf' or 'esmf' - @param srcGridMask array of same shape as srcGrid - @param srcBounds list of numpy arrays of same shape as srcGrid - @param srcGridAreas array of same shape as srcGrid - @param dstGridMask array of same shape as dstGrid - @param dstBounds list of numpy arrays of same shape as dstGrid - @param dstGridAreas array of same shape as dstGrid - @param **args additional arguments to be passed to the - specific tool - 'libcf': mkCyclic={True, False}, handleCut={True,False} - 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... - """ - - self.nGridDims = len(srcGrid) - self.regridMethod = regridMethod - - if len(srcGrid) != len(dstGrid): - msg = 'mvGenericRegrid.__init__: mismatch in number of dims' - msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ - (self.nGridDims, len(dstGrid)) - raise regrid2.RegridError(msg) - - # parse the options - if re.search('libcf', regridTool.lower()) or \ - re.search('gsreg', regridTool.lower()): - # LibCF - self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - **args) - elif re.search('esm', regridTool.lower()): - # ESMF - staggerLoc = args.get('staggerLoc', 'center') - if 'staggerLoc' in args: - del args['staggerLoc'] - periodicity = args.get('periodicity', - guessPeriodicity(srcBounds)) - if 'periodicity' in args: - del args['periodicity'] - coordSys = args.get('coordSys', 'deg') - if 'coordSys' in args: - del args['coordSys'] - - # Get the shapes - self.srcGridShape = srcGrid[0].shape - self.dstGridShape = dstGrid[0].shape - self.hasSrcBounds = False - self.hasDstBounds = False - - if srcBounds is not None: - self.hasSrcBounds = True - - if dstBounds is not None: - self.hasDstBounds = True - - self.srcGridAreasShape = None - self.dstGridAreasShape = None - - if srcGridAreas is not None: - self.srcGridAreasShape = srcGridAreas[0].shape - - if dstGridAreas is not None: - self.dstGridAreasShape = dstGridAreas[0].shape - - # Initialize - self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, - dtype=dtype, - regridMethod=regridMethod, - staggerLoc=staggerLoc, - periodicity=periodicity, - coordSys=coordSys, - hasSrcBounds=self.hasSrcBounds, - hasDstBounds=self.hasDstBounds, - srcGridAreasShape=self.srcGridAreasShape, - dstGridAreasShape=self.dstGridAreasShape, - **args) - - self.tool.setCoords(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - srcGridAreas=srcGridAreas, - dstGridMask=dstGridMask, - dstBounds=dstBounds, - dstGridAreas=dstGridAreas, - globalIndexing=True, - **args) - else: - msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, -valid choices are: 'libcf', 'esmf'""" % regridTool - raise regrid2.RegridError(msg) - - def computeWeights(self, **args): - """ - Compute Weights - """ - self.tool.computeWeights(**args) - - def apply(self, srcData, dstData, - rootPe=None, - missingValue=None, - **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param rootPe if other than None, then results will be MPI - gathered - @param missingValue if not None, then data mask will be interpolated - and data value set to missingValue when masked - """ - - # assuming the axes are the slowly varying indices - srcHorizShape = srcData.shape[-self.nGridDims:] - dstHorizShape = dstData.shape[-self.nGridDims:] - - srcDataMaskFloat = None - dstDataMaskFloat = None - dstMask = None - if missingValue is not None: - srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) - dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) - - nonHorizShape = srcData.shape[: -self.nGridDims] - - if len(nonHorizShape) == 0: - - # - # no axis... just call apply - # - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (srcData == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later - indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), - dtype=srcData.dtype) - - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, **args) - if re.search('conserv', self.regridMethod.lower(), re.I): - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) - - # Initialize output to missin_value - dstData[:] = missingValue - # interpolate the data - self.tool.apply(indata, dstData, rootPe=rootPe, - globalIndexing=True, **args) - - # add missing values - dstData *= (1 - dstMask) - dstData += dstMask * missingValue - - else: - # no masking, just interpolate the data - self.tool.apply(srcData, dstData, rootPe=rootPe, - globalIndexing=True, **args) - else: - - nonHorizShape2 = dstData.shape[: -self.nGridDims] - if not numpy.all(nonHorizShape2 == nonHorizShape): - msg = 'mvGenericRegrid.apply: axes detected ' - msg += 'but %s != %s ' % (str(nonHorizShape2), - str(nonHorizShape)) - raise regrid2.RegridError(msg) - - # - # iterate over all axes - # - - # create containers to hold input/output values - # (a copy is essential here) - zros = '[' + ('0,' * len(nonHorizShape)) + '...]' - indata = numpy.array(eval('srcData' + zros)) - outdata = numpy.array(eval('dstData' + zros)) - - # now iterate over all non lat/lon coordinates - for it in MultiArrayIter(nonHorizShape): - - indices = it.getIndices() - slce = '[' - slce += reduce(operator.add, ['%d,' % i for i in indices]) - slce += '...]' - indata = eval('srcData' + slce) - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (indata == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later -# indata *= (1 - (srcDataMaskFloat == 1)) - -# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, - srcDataMask=(1 - srcDataMaskFloat), **args) - - if re.search('conserv', self.regridMethod.lower(), re.I): - # cell interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - # nodal interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 0), numpy.int32) - - # interpolate the data, using the appropriate tool - self.tool.apply(indata, outdata, rootPe=rootPe, - globalIndexing=True, - srcDataMask=srcDataMaskFloat, **args) - -# import vcs -# pp = vcs.init() -# pp.plot(indata) -# pp.interact() -# pp.clear() -# pp.plot(outdata) -# pp.interact() -# pp.clear() - # apply missing value contribution - if missingValue is not None: - # add mask contribution - outdata *= (1 - dstMask) - outdata += dstMask * missingValue - - # fill in dstData - exec('dstData' + slce + ' = outdata') - - def getDstGrid(self): - """ - Return the destination grid, may be different from the dst grid provided - to the constructor due to domain decomposition - @return local grid on this processor - """ - return self.tool.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe=None): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - entries are tool dependent - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py deleted file mode 100644 index 30c5f4bf..00000000 --- a/regrid2/Lib/mvLibCFRegrid.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -LibCF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" - -from regrid2 import gsRegrid -from regrid2 import GenericRegrid - - -class LibCFRegrid(GenericRegrid): - """ - """ - - def __init__(self, srcGrid, dstGrid, srcGridMask=None, - srcBounds=None, **args): - """ - Constructor - @param srcGrid array - @param dstGrid array - @param srcBounds cell boundaries - @param **args keyword arguments, eg mkCyclic, handleCut, ... - to be passed to gsRegrid - """ - self.regridMethodStr = 'linear' - self.mkCyclic = args.get('mkCyclic', False) - self.handleCut = args.get('handleCut', False) - self.verbose = args.get('verbose', False) - self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, - src_bounds=srcBounds, - mkCyclic=self.mkCyclic, - handleCut=self.handleCut) - if srcGridMask is not None: - self.regridObj.setMask(srcGridMask) - - # min resolution, required in order to set the tolerance (tolpos) - self.delta = float('inf') - for i in range(len(dstGrid)): - coordMin = dstGrid[i].min() - coordMax = dstGrid[i].max() - n = max(dstGrid[i].shape) - self.delta = min(self.delta, (coordMax - coordMin) / float(n)) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args arguments to be passed to gsRegrid, e.g. - nitermax, tolpos, ... - """ - nitermax = args.get('nitermax', 20) - # make tolpos relative to the min cell size - tolpos = args.get('tolpos', 0.01) * self.delta - self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) - - def apply(self, srcData, dstData, missingValue=None, **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param missingValue value that should be set for points falling outside - the src domain, pass None if these should not be - touched. - """ - - self.regridObj.apply(srcData, dstData, missingValue) - - def getSrcGrid(self): - """ - Get the grid of the src data (maybe larger than the - dst grid passed to the constructor due to column/row - padding) - @return grid - """ - return self.regridObj.getSrcGrid() - - def getDstGrid(self): - """ - Get the grid of the dst data - @return grid - """ - return self.regridObj.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'numDstPoints' and 'numValid' - @param rootPe not used - """ - for entry in 'numDstPoints', 'numValid': - if entry in diag: - meth = 'get' + entry[0].upper() + entry[1:] - diag[entry] = eval('self.regridObj.' + meth + '()') - diag['regridTool'] = 'libcf' - diag['regridMethod'] = self.regridMethodStr - diag['handleCut'] = self.handleCut - diag['mkCyclic'] = self.mkCyclic - diag['verbose'] = self.verbose diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py deleted file mode 100644 index fb79a9e2..00000000 --- a/regrid2/Lib/pressure.py +++ /dev/null @@ -1,490 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by -import cdms2 -import numpy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import copy - - -class PressureRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along - # the pressure dimension only. - # - # PROCEDURE: Step One: - # Make an instance of class PressureRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, axisIn, axisOut): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, levIn, levOut): - # - # PROCEDURE: - # - # The user must assemble two pieces of information: - # - # axisIn - the input level axis - # - # axisOut - the output level axis - # - # USAGE: - # - # To make an instance preparing for a regrid along the level dimension pnly, type - # - # r = PressureRegridder(levIn, levOut) - # - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.axisIn = axisIn - self.axisOut = axisOut - self.nlevi = len(axisIn) - self.nlevo = len(axisOut) - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the pressure regridder function. - ar is the input array, a variable, masked array, or numpy array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = ar.getAxisList() - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # Set missing value - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 3: - order = "zyx" - elif rank == 4: - order = "tzyx" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to positionIn - positionIn = [None] * 4 - for i in range(len(order)): - if order[i] == 'x': - positionIn[0] = i - elif order[i] == 'y': - positionIn[1] = i - elif order[i] == 'z': - positionIn[2] = i - if inputIsVariable: - axislist[i] = self.axisOut - else: - positionIn[3] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - if inputIsVariable == 1: - result = cdms2.createVariable(outar, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, - logYes='yes', positionIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, - # dataout along the level dimension only. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using - # the value passed in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence longitude, - # latitude, level and time. Longitude, latitude and level are - # required. If time is missing submit None in its slot in the - # tuple. Notice that the length of the tuple is always four. - # - # Explicitly, in terms of the shape of dataIn as returned by Python's shape function - # - # positionIn[0] contains the position of longitude in dataIn - # positionIn[1] contains the position of latitude in dataIn - # positionIn[2] contains the position of level in dataIn or None - # positionIn[3] contains the position of time in dataIn or None - # - # As examples: - # If the C order shape of 4D data is - # (number of longitudes, number of times, number of levels, - # number of latitudes) - # submit - # (0, 3, 2, 1) - # - # If the C order shape of 3D data is - # (number of longitudes, number of times, number oflatitudes) - # submit - # (0, 2, 1, None) - # - # Send in None if the shape is a subset of (time, level, - # latitude, longitude) which is evaluated as follows: - # 3D -- code assumes (2,1,0,None) - # 4D -- code assumes (3,2,1,0) - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last - # resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # ----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - # --- evaluate positionIn ---- - - # --- make standard positionIn as a check---- - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - for n in range(numberDim, 4): # fill end of list with Nones - positionList.append(None) - - positionCheck = tuple(positionList) - - standardPosition = 0 # transpose required - - if positionIn is None: # construct the default positionIn tuple - positionIn = positionCheck - standardPosition = 1 # no need for a transpose with this data - else: - if positionIn == positionCheck: # compare to the standard - standardPosition = 1 # no need for a transpose with this data - - if len(positionIn) != 4: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' - sendmsg(msg) - raise TypeError - - # transpose data to the standard order (t,z,y,x) - if standardPosition == 0: - - newOrder, inverseOrder = checkorder(positionIn) - - # transpose data to standard order (t,z,y,x) - dataIn = numpy.transpose(dataIn, newOrder) - dataIn = numpy.array( - dataIn.astype( - numpy.float32), - numpy.float32) # make contiguous - - # set dimension sizes and check for consistency - - if positionIn[0] is not None: - self.nlon = (dataShape[positionIn[0]]) - else: - self.nlon = 0 - if positionIn[1] is not None: - self.nlat = (dataShape[positionIn[1]]) - else: - self.nlat = 0 - if positionIn[2] is not None: - if self.nlevi != (dataShape[positionIn[2]]): - msg = 'Level size is inconsistent with input data' - sendmsg(msg) - raise ValueError - if positionIn[3] is not None: - self.ntime = (dataShape[positionIn[3]]) - else: - self.ntime = 0 - - # allocate memory for dataOut -- the array with new number of levels - - outList = list(dataIn.shape) - - for i in range(len(outList)): - if outList[i] == self.nlevi: - outList[i] = self.nlevo - break - - dataOut = numpy.zeros( - tuple(outList), - numpy.float32) # memory for aout - - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.axisIn[:].astype(numpy.float64) - levOut = self.axisOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlat, - self.nlon, - self.ntime, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - dataIn, - dataOut) - - # if no missing do not pass None - if missingMatch == 'none': - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - if standardPosition == 0: - # transpose data to original order - dataOut = numpy.transpose(dataOut, inverseOrder) - dataOut = numpy.array( - dataOut.astype( - numpy.float32), - numpy.float32) # make contiguous - - if missingValueOut is not None: # set the missing value in data to missingValueOut - - if missingMatch == 'greater': - if missingValueIn > 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.greater( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'equal': - missing = missingValueIn - dataOut = numpy.where( - numpy.equal( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'less': - if missingValueIn < 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.less( - dataOut, - missing), - missingValueOut, - dataOut) - - return dataOut - - -def checkorder(positionIn): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the tuples for transposing the data to standard dimension order and the - # inverse for transposing it back to the original dimension order - # - # usage: newOrder, inverseOrder = checkorder(positionIn) - # - # passed: positionIn -- array with location of longitude, latitude. level and time respectively - # in the sense of the python shape of the data - # - # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) - # inverseOrder -- tuple to transpose data to back to the original order - # - #----------------------------------------------------------------------------------------------""" - - # remove the None values from positionIn and reverse the order - - reducedPosition = [] - for item in positionIn: - if item is not None: - reducedPosition.append(item) - reducedPosition.reverse() - - # make the newOrder tuple - - newOrder = tuple(reducedPosition) - - # ----- Determine the inverse to this new order for use in mathtogeo ----- - - xform = [] - for i in range(len(newOrder)): - xform.append([newOrder[i], i]) - xform.sort() - - inverse_shapelist = [] - for item in xform: - inverse_shapelist.append(item[1]) - inverseOrder = tuple(inverse_shapelist) - - return newOrder, inverseOrder - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py deleted file mode 100644 index 5a052700..00000000 --- a/regrid2/Lib/scrip.py +++ /dev/null @@ -1,447 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -#from . import _scrip -import regrid2._scrip as _scrip -from .error import RegridError -import numpy -from functools import reduce - -"""Regrid support for nonrectangular grids, based on the SCRIP package.""" - - -class ScripRegridder: - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - self.outputGrid = outputGrid - self.remapMatrix = remapMatrix - self.sourceAddress = sourceAddress - self.destAddress = destAddress - self.inputGrid = inputGrid - self.sourceFrac = sourceFrac - self.destFrac = destFrac - - def __call__(self, input): - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - # this expects contiguous arrays - if input.iscontiguous() is False: - input = input.ascontiguous() - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - - # Regrid - output = self.regrid(input) - - # Reshape output and restore input shape - input.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - def getOutputGrid(self): - return self.outputGrid - - def getInputGrid(self): - return self.inputGrid - - def getSourceFraction(self): - return self.sourceFrac - - def getDestinationFraction(self): - return self.destFrac - - -class ConservativeRegridder(ScripRegridder): - """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' - is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length - as the output grid size, with values: - 1.0 for normalize="fracarea", - grid_frac for normalize="destarea", or - grid_frac*grid_area for normalize="none". - sourceArea is the area of the source grid cells - destArea is the area of the destination grid cells - """ - - def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, - sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): - if normalize not in ["fracarea", "destarea", "none"]: - raise RegridError("Invalid normalization option: %s" % normalize) - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - self.normalize = normalize - self.normal = None - self.sourceArea = sourceArea - self.destArea = destArea - - def getSourceArea(self): - return self.sourceArea - - def getDestinationArea(self): - return self.destArea - - def regrid(self, input): - if self.normal is None: - # print "On input, num_links = %d"%(len(self.sourceAddress)) - # print "On input, nextra = %d"%(input.shape[0]) - # print "On input, ninput = %d"%(input.shape[1]) - # print "On input, noutput = %d"%(self.outputGrid.size()) - # print "On input, shape(input) = %s"%`input.shape` - # print "On input, shape(output) = %s"%`self.outputGrid.shape` - # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` - # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` - # print "On input, shape(dst_address) = - # %s"%`self.destAddress.shape` - result = _scrip.conserv_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - else: - result = _scrip.conserv_regrid_normal( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - self.normal) - return result - - -class BilinearRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.bilinear_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -class BicubicRegridder(ScripRegridder): - """Bicubic regrid.""" - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def __call__(self, input, gradLat, gradLon, gradLatlon): - """gradLat = df/di - gradLon = df/dj - gradLatlon = d(df)/(di)(dj) - """ - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - if (gradLat.shape != input.shape or - gradLon.shape != input.shape or - gradLatlon.shape != input.shape): - raise RegridError( - "All input arrays must have shape %s" % - repr( - input.shape)) - - if (not isinstance(gradLat, type(input)) or - not isinstance(gradLon, type(input)) or - not isinstance(gradLatlon, type(input))): - raise RegridError( - "All input arrays must have type %s" % - repr( - type(input))) - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - gradLat = gradLat.subSlice() - gradLon = gradLon.subSlice() - gradLatlon = gradLatlon.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - gradLat = gradLat.filled() - gradLon = gradLon.filled() - gradLatlon = gradLatlon.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - gradLat.shape = newshape - gradLon.shape = newshape - gradLatlon.shape = newshape - - # Regrid - output = _scrip.bicubic_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - gradLat, - gradLon, - gradLatlon) - - # Reshape output and restore input shape - input.shape = oldshape - gradLat.shape = oldshape - gradLon.shape = oldshape - gradLatlon.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - -class DistwgtRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.distwgt_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -def readRegridder(fileobj, mapMethod=None, checkGrid=1): - """Read a regridder from an open fileobj. - mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method - defined in the file. - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. - """ - - if isinstance(fileobj, str): - fileobj = cdms2.open(fileobj) - elif not isinstance(fileobj, cdms2.dataset.CdmsFile): - raise RegridError( - "fileobj arguments must be a cdms2 file or a string pointing to a file") - - if mapMethod is None: - mapString = fileobj.map_method.strip().lower() - if mapString[0:12] == "conservative": - mapMethod = "conservative" - elif mapString[0:8] == "bilinear": - mapMethod = "bilinear" - elif mapString[0:7] == "bicubic": - mapMethod = "bicubic" - elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": - mapMethod = "distwgt" - else: - raise RegridError("Unrecognized map method: %s" % mapString) - - convention = 'SCRIP' - if list(fileobj.variables.keys()).count('S'): - convention = 'NCAR' - if convention == 'SCRIP': - remapMatrix = fileobj('remap_matrix').filled() - srcAddress = fileobj('src_address').filled() - dstAddress = fileobj('dst_address').filled() - srcfrac = fileobj('src_grid_frac') - dstfrac = fileobj('dst_grid_frac') - else: - remapMatrix = fileobj('S').filled() - srcAddress = fileobj('col').filled() - dstAddress = fileobj('row').filled() - srcfrac = fileobj('frac_a') - dstfrac = fileobj('frac_b') - ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) - outgrid = fileobj.readScripGrid( - whichGrid="destination", - checkGrid=checkGrid) - - if mapMethod == "conservative": - if convention == 'SCRIP': - srcarea = fileobj('src_grid_area') - dstarea = fileobj('dst_grid_area') - else: # NCAR stuff - if "S2" in list(fileobj.variables.keys()): - remapMatrix = fileobj("S2") - sh = list(remapMatrix.shape) - if len(sh) == 2 and sh[-1] == 2: - sh[-1] = 1 - S = fileobj("S").filled() - S.shape = sh - remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) - srcarea = fileobj('area_a') - dstarea = fileobj('area_b') - regridder = ConservativeRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac, - sourceArea=srcarea, - destArea=dstarea) - elif mapMethod == "bilinear": - regridder = BilinearRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "bicubic": - regridder = BicubicRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "distwgt": - regridder = DistwgtRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - else: - raise RegridError("Unrecognized map method: %s" % mapMethod) - - return regridder From 62c24f78b6a003b6a925b395e63d6d49f0a4639d Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 11:59:33 -0700 Subject: [PATCH 091/239] add print statements for regrid2 --- docs/source/conf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6c397076..53314b07 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,8 +55,13 @@ def side_effect(*args, **kwargs): m.side_effect = side_effect sys.modules[mod_name] = m +import glob +print "***" +print glob.glob("../../regrid2") if os.path.isdir('../../regrid2/Lib'): os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') +print "***" +print glob.glob("../../regrid2") print os.getcwd() open("../../Lib/git.py", 'wb').close() From 2846cfcb8552884cfcb4ea0137c3b10c7b0ba2cb Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 12:02:59 -0700 Subject: [PATCH 092/239] add print for libregrid2 --- docs/source/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 53314b07..20534c0a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -57,11 +57,11 @@ def side_effect(*args, **kwargs): import glob print "***" -print glob.glob("../../regrid2") +print glob.glob("../../regrid2/*") if os.path.isdir('../../regrid2/Lib'): os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') print "***" -print glob.glob("../../regrid2") +print glob.glob("../../regrid2/*") print os.getcwd() open("../../Lib/git.py", 'wb').close() From 43e42ebc364ddcf8f5535d22e6dc88b5e01f371a Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 12:11:18 -0700 Subject: [PATCH 093/239] restore regrid2.Lib for readthedocs --- regrid2/Lib/PET0.ESMF_LogFile | 1 + regrid2/Lib/__init__.py | 36 + regrid2/Lib/crossSection.py | 1092 +++++++++++++++++++++++++++ regrid2/Lib/crossSection.py.orig | 1095 +++++++++++++++++++++++++++ regrid2/Lib/error.py | 3 + regrid2/Lib/esmf.py | 842 +++++++++++++++++++++ regrid2/Lib/gsRegrid.py | 1179 ++++++++++++++++++++++++++++++ regrid2/Lib/gs_horizontal.py | 214 ++++++ regrid2/Lib/horizontal.py | 422 +++++++++++ regrid2/Lib/mvESMFRegrid.py | 483 ++++++++++++ regrid2/Lib/mvGenericRegrid.py | 313 ++++++++ regrid2/Lib/mvLibCFRegrid.py | 101 +++ regrid2/Lib/mytest.py | 2 + regrid2/Lib/pressure.py | 490 +++++++++++++ regrid2/Lib/scrip.py | 447 +++++++++++ 15 files changed, 6720 insertions(+) create mode 100644 regrid2/Lib/PET0.ESMF_LogFile create mode 100644 regrid2/Lib/__init__.py create mode 100644 regrid2/Lib/crossSection.py create mode 100644 regrid2/Lib/crossSection.py.orig create mode 100644 regrid2/Lib/error.py create mode 100644 regrid2/Lib/esmf.py create mode 100644 regrid2/Lib/gsRegrid.py create mode 100644 regrid2/Lib/gs_horizontal.py create mode 100644 regrid2/Lib/horizontal.py create mode 100644 regrid2/Lib/mvESMFRegrid.py create mode 100644 regrid2/Lib/mvGenericRegrid.py create mode 100644 regrid2/Lib/mvLibCFRegrid.py create mode 100644 regrid2/Lib/mytest.py create mode 100644 regrid2/Lib/pressure.py create mode 100644 regrid2/Lib/scrip.py diff --git a/regrid2/Lib/PET0.ESMF_LogFile b/regrid2/Lib/PET0.ESMF_LogFile new file mode 100644 index 00000000..3494c8e2 --- /dev/null +++ b/regrid2/Lib/PET0.ESMF_LogFile @@ -0,0 +1 @@ +20170308 152041.534 INFO PET0 Running with ESMF Version 7.0.0 diff --git a/regrid2/Lib/__init__.py b/regrid2/Lib/__init__.py new file mode 100644 index 00000000..36b7f9e2 --- /dev/null +++ b/regrid2/Lib/__init__.py @@ -0,0 +1,36 @@ +"""Interface to regridding facilities +""" + +__all__ = ["horizontal", "pressure", "crossSection", "scrip", + "error", "mvGenericRegrid", ] + +from .error import RegridError # noqa +from .horizontal import Horizontal, Regridder # noqa +from .pressure import PressureRegridder # noqa +from .crossSection import CrossSectionRegridder # noqa +from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa +from .scrip import DistwgtRegridder, readRegridder # noqa +from regrid2 import gsRegrid # noqa +from .mvGenericRegrid import GenericRegrid # noqa +from .mvLibCFRegrid import LibCFRegrid # noqa +try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + from .mvESMFRegrid import ESMFRegrid # noqa +except BaseException: + pass + +from . import git # noqa + +ESMF_HAS_BEEN_INITIALIZED = False +if not ESMF_HAS_BEEN_INITIALIZED: + try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + ESMF.Manager(debug=False) + # this turns off the PET file logs + ESMF_HAS_BEEN_INITIALIZED = True + except BaseException: + pass diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py new file mode 100644 index 00000000..cf23b45d --- /dev/null +++ b/regrid2/Lib/crossSection.py @@ -0,0 +1,1092 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklatpass) + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig new file mode 100644 index 00000000..c06eae4a --- /dev/null +++ b/regrid2/Lib/crossSection.py.orig @@ -0,0 +1,1095 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +from . import _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + print("INPUT IS VAR:", inputIsVariable) + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklat) + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print('calculated cross section test case rms error = ', error) diff --git a/regrid2/Lib/error.py b/regrid2/Lib/error.py new file mode 100644 index 00000000..327dff22 --- /dev/null +++ b/regrid2/Lib/error.py @@ -0,0 +1,3 @@ +class RegridError (Exception): + def __init__(self, args="Unspecified error from regrid package"): + self.args = (args,) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py new file mode 100644 index 00000000..830910a1 --- /dev/null +++ b/regrid2/Lib/esmf.py @@ -0,0 +1,842 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2008-2012, Tech-X Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the conditions +specified in the license file 'license.txt' are met. + +Authors: David Kindig and Alex Pletzer +""" +import re +import time +import numpy +from regrid2 import RegridError +import ESMF +from functools import reduce + +# constants +R8 = ESMF.TypeKind.R8 +R4 = ESMF.TypeKind.R4 +I8 = ESMF.TypeKind.I8 +I4 = ESMF.TypeKind.I4 +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER +CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class EsmfUnstructGrid: + """ + Unstructured grid + """ + + def __init__(self, numTopoDims, numSpaceDims): + """Constructor + + Parameters + ---------- + + numTopoDims + number of topological dimensions + + numSpaceDims + number of space dimensions + """ + # handle to the grid object + self.grid = None + # whether or not nodes were added + self.nodesAdded = False + # whether or not cells were added + self.cellsAdded = False + # the local processor rank + self.pe = 0 + # number of processors + self.nprocs = 1 + # communicator + self.comm = None + + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + self.grid = ESMF.Mesh( + parametric_dim=numTopoDims, + spatial_dim=numSpaceDims) + + def setCells(self, cellIndices, cellTypes, connectivity, + cellMask=None, cellAreas=None): + """ + Set Cell connectivity + + Parameters + ---------- + + cell indices (0-based) + + cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + + connectivity node connectivity array, see below for node ordering + + cellMask + + cellAreas area (volume) of each cell + + Note + ---- + + 3 + / \ + / \ + / \ + / \ + / \ + 1 --------- 2 + + + + + 4------------3 + | | + | | + | | + | | + | | + 1 ---------- 2 + + + + 3 8---------------7 + /|\ /| /| + / | \ / | / | + / | \ / | / | + / | \ / | / | + / | \ 5---------------6 | + 4-----|-----2 | | | | + \ | / | 4----------|----3 + \ | / | / | / + \ | / | / | / + \ | / | / | / + \|/ |/ |/ + 1 1---------------2 + + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX + + """ + n = len(cellIndices) + if not self.cellsAdded: + # node/cell indices are 1-based in ESMF + cellIndices += 1 + self.grid.add_elements(n, cellIndices, cellTypes, + connectivity, elementMask=cellMask, + elementArea=cellAreas) + self.cellsAdded = True + + def setNodes(self, indices, coords, peOwners=None): + """ + Set the nodal coordinates + + Parameters + ---------- + + indices Ids of the nodes (0-based) + + coords nodal coordinates + + peOwners processor ranks where the coordinates reside (0-based) + """ + n = len(indices) + if not self.nodesAdded: + if peOwners is None: + peOwners = numpy.ones((n,), numpy.int32) * self.pe + # node indices are 1-based + indices += 1 + self.grid.add_nodes(n, indices, coords, peOwners) + self.nodesAdded = True + + def toVTK(self, filename): + """ + Write grid to VTK file format + + Parameters + ---------- + + filename VTK file name + _: None + + """ + self.grid.write(filename) + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructGrid: + """ + Structured grid + """ + + def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, + periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, + hasBounds=False): + """ + Constructor + + Parameters + ---------- + + shape Tuple of cell sizes along each axis + + coordSys coordinate system + ESMF.CoordSys.CART Cartesian + ESMF.CoordSys.SPH_DEG (default) Degrees + ESMF.CoordSys.SPH_RAD Radians + + periodicity Does the grid have a periodic coordinate + 0 No periodicity + 1 Periodic in x (1st) axis + 2 Periodic in x, y axes + + staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX + The stagger constants are listed at the top + + hasBounds If the grid has bounds, Run AddCoords for the bounds + """ + # ESMF grid object + self.grid = None + # number of cells in [z,] y, x on all processors + self.shape = shape[::-1] + # number of dimensions + self.ndims = len(self.shape) + # whether or not cell areas were set + self.cellAreasSet = False + # whether or not nodal coords were set + self.nodesSet = False + # whether or not cell centered coordinates were set + self.centersSet = False + + # assume last 2 dimensions are Y,X + # For esmf reverse to X, Y + maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) + + self.centersSet = False + periodic_dim = 0 + pole_dim = 1 + if periodicity == 0: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], + coord_sys=coordSys) + elif periodicity == 1: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, + periodic_dim=periodic_dim, pole_dim=pole_dim, + staggerloc=[staggerloc], coord_sys=coordSys) + else: + msg = """ +esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. + """ % periodicity + raise RegridError(msg) + + # Grid add coordinates call must go here for parallel runs + # This occur before the fields are created, making the fields + # parallel aware. + if ((staggerloc == CENTER) and (not self.centersSet)): + self.centersSet = True + elif (staggerloc == CORNER) and (not self.nodesSet): + self.nodesSet = True + + if hasBounds is not None: + if self.ndims == 2: + self.grid.add_coords([CORNER], coord_dim=None, from_file=False) + if self.ndims == 3: + self.grid.add_coords( + [VCORNER], coord_dim=None, from_file=False) + + def getLocalSlab(self, staggerloc): + """ + Get the local slab (ellipsis). You can use this to grab + the data local to this processor + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple of slices + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([slice(lo[i], hi[i], None) + for i in range(self.ndims)])[::-1] + + def getLoHiBounds(self, staggerloc): + """ + Get the local lo/hi index values for the coordinates (per processor) + (hi is not inclusive, lo <= index < hi) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + lo, hi lists + """ + lo = self.grid.lower_bounds[staggerloc] + hi = self.grid.upper_bounds[staggerloc] + return lo, hi + + def getCoordShape(self, staggerloc): + """ + Get the local coordinate shape (may be different on each processor) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] + + def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): + """ + Populate the grid with staggered coordinates (e.g. corner or center). + + + Parameters + ---------- + + coords + The curvilinear coordinates of the grid. + List of numpy arrays. Must exist on all procs. + + staggerloc + The stagger location + ESMF.StaggerLoc.CENTER (default) + ESMF.StaggerLoc.CORNER + + globalIndexing + if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + + Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, + hence the dimensions are reversed here. + """ + # allocate space for coordinates, can only add coordinates once + for i in range(self.ndims): + ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) + if globalIndexing: + slab = self.getLocalSlab(staggerloc)[::-1] + # Populate self.grid with coordinates or the bounds as needed + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] + else: + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] + + def getCoords(self, dim, staggerloc): + """ + Return the coordinates for a dimension + + Parameters + --------- + + dim desired dimension (zero based indexing) + + staggerloc Stagger location + """ + gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) + shp = self.getCoordShape(staggerloc)[::-1] + return numpy.reshape(gridPtr, shp).T + + def setCellAreas(self, areas): + """ + Set the cell areas + + Parameters + --------- + + areas numpy array + + _: None + + """ + self.grid.add_item(item=ESMF.GridItem.Area) + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + areaPtr[:] = areas.T.flat + self.cellAreasSet = True + + def getCellAreas(self): + """ + + Returns + ------- + + cell areas or None if setCellAreas was not called + """ + if self.cellAreasSet: + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + return numpy.reshape(areaPtr, self.shape).T + else: + return None + + def getMask(self, staggerloc=CENTER): + """ + Get mask array. In ESMF, the mask is applied to cells. + + Returns + ------- + + mask numpy array. 1 is invalid by default. This array exists on all procs + """ + try: + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, staggerloc=staggerloc) + except BaseException: + maskPtr = None + return maskPtr.T + + def setMask(self, mask, staggerloc=CENTER): + """ + Set mask array. In ESMF, the mask is applied to cells. + + Parameters + ---------- + + mask numpy array. 1 is invalid by default. This array exists + on all procs + + _: None + """ + self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, + staggerloc=staggerloc) + slab = self.getLocalSlab(CENTER)[::-1] + maskPtr[:] = mask.T[slab] + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructField: + """ + Structured field. + """ + + def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): + """ + Creator for structured ESMF Field + + Parameters + ---------- + + esmfGrid + instance of an ESMF + + name field + name (must be unique) + + datatype + data type, one of 'float64', 'float32', 'int64', or 'int32' + (or equivalent numpy dtype) + + staggerloc + ESMF.StaggerLoc.CENTER + ESMF.StaggerLoc.CORNER + """ + # field object + self.field = None + # the local processor rank + self.pe = 0 + # the number of processors + self.nprocs = 1 + # associated grid + self.grid = esmfGrid + # staggering + self.staggerloc = staggerloc + # communicator + self.comm = None + + try: + from mpi4py import MPI + self.comm = MPI.COMM_WORLD + except BaseException: + pass + + etype = None + sdatatype = str(datatype) # in case user passes a numpy dtype + if re.search('float64', sdatatype): + etype = R8 + elif re.search('float32', sdatatype): + etype = R4 + elif re.search('int64', sdatatype): + etype = I8 + elif re.search('int32', sdatatype): + etype = I4 + else: + msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype + raise RegridError(msg) + + self.field = ESMF.Field( + grid=esmfGrid.grid, + name=name, + typekind=etype, + staggerloc=staggerloc) + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + def getPointer(self): + """ + Get field data as a flat array + + Returns + ------- + + pointer + """ + return numpy.ravel(self.field.data) + + def getData(self, rootPe): + """ + Get field data as a numpy array + + Parameters + ---------- + + rootPe if None then local data will be fetched, otherwise + gather the data on processor "rootPe" (all other + procs will return None). + + _: None + + Returns + ------- + + numpy array or None + """ + ptr = self.getPointer() + if rootPe is None: + shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] + # local data, copy + return numpy.reshape(ptr, shp).T + else: + # gather the data on rootPe + lo, hi = self.grid.getLoHiBounds(self.staggerloc) + los = [lo] + his = [hi] + ptrs = [ptr] + ptr = numpy.reshape(ptr, hi) + if self.comm is not None: + los = self.comm.gather(lo) # Local + his = self.comm.gather(hi) # Local + ptrs = self.comm.gather(ptr, root=rootPe) + + if self.pe == rootPe: # Local + # reassemble, find the largest hi indices to set + # the shape of the data container + bigHi = [0 for i in range(self.grid.ndims)] + for i in range(self.grid.ndims): + bigHi[i] = reduce(lambda x, y: max(x, y), + [his[p][i] for p in range(self.nprocs)]) + # allocate space to retrieve the data + bigData = numpy.empty(bigHi, ptr.dtype) + bigData[:] = 0.0 + + # populate the data + for p in range(self.nprocs): + slab = tuple([slice(los[p][i], his[p][i], None) for + i in range(self.grid.ndims)]) + # copy + bigData[slab].flat = ptrs[p] + return bigData.T # Local + + # rootPe is not None and self.pe != rootPe + return None + + def setLocalData(self, data, staggerloc, globalIndexing=False): + """ + Set local field data + + Parameters + ---------- + + data full numpy array, this method will take care of setting a + the subset of the data that reside on the local processor + + staggerloc stagger location of the data + + + globalIndexing if True array was allocated over global index + space, array was allocated over local index + space (on this processor) + """ + ptr = self.field.data + if globalIndexing: + slab = self.grid.getLocalSlab(staggerloc)[::-1] + ptr[:] = data.T[slab] + else: + ptr[:] = data.T + + +########################################################################## + +class EsmfRegrid: + """ + Regrid source grid data to destination grid data + """ + + def __init__(self, srcField, dstField, + srcFrac=None, + dstFrac=None, + srcMaskValues=None, + dstMaskValues=None, + regridMethod=BILINEAR, + ignoreDegenerate=False, + unMappedAction=IGNORE): + """ + Constuct regrid object + + Parameters + ---------- + + srcField + the source field object of type EsmfStructField + + dstField + the destination field object of type EsmfStructField + + srcMaskValues + Value of masked cells in source + + dstMaskValues + Value of masked cells in destination + + srcFrac + Cell fractions on source grid (type EsmfStructField) + + dstFrac + Cell fractions on destination grid (type EsmfStructField) + + regridMethod + ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + + unMappedAction + ESMF.UnmappedAction.{IGNORE,ERROR} + + ignoreDegenerate + Ignore degenerate cells when checking inputs + """ + self.srcField = srcField + self.dstField = dstField + self.regridMethod = regridMethod + self.srcAreaField = None + self.dstAreaField = None + self.srcFracField = srcFrac + self.dstFracField = dstFrac + self.regridHandle = None + self.ignoreDegenerate = ignoreDegenerate + + timeStamp = re.sub('\.', '', str(time.time())) + + # create and initialize the cell areas to zero + if regridMethod == CONSERVE: + self.srcAreaField = EsmfStructField(self.srcField.grid, + name='src_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcAreaField.getPointer() + dataPtr[:] = 0.0 + self.dstAreaField = EsmfStructField(self.dstField.grid, + name='dst_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstAreaField.getPointer() + dataPtr[:] = 0.0 + + # initialize fractional areas to 1 (unless supplied) + if srcFrac is None: + self.srcFracField = EsmfStructField(self.srcField.grid, + name='src_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcFracField.getPointer() + dataPtr[:] = 1.0 + + if dstFrac is None: + self.dstFracField = EsmfStructField(self.dstField.grid, + name='dst_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstFracField.getPointer() + dataPtr[:] = 1.0 + + srcMaskValueArr = None + if srcMaskValues is not None: + srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) + + dstMaskValueArr = None + if dstMaskValues is not None: + dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) + + self.regridHandle = ESMF.Regrid( + srcField.field, + dstField.field, + src_frac_field=self.srcFracField.field, + dst_frac_field=self.dstFracField.field, + src_mask_values=srcMaskValueArr, + dst_mask_values=dstMaskValueArr, + regrid_method=regridMethod, + unmapped_action=unMappedAction, + ignore_degenerate=self.ignoreDegenerate) + + def getSrcAreas(self, rootPe): + """ + Get the src grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.srcAreaField.data.T + return None + + def getDstAreas(self, rootPe): + """ + Get the dst grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.dstAreaField.data.T + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.srcFracField is not None: + # self.srcFracField.get_area() + return self.srcFracField.data.T + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.dstFracField is not None: + # self.dstFracField.get_area() + return self.dstFracField.data.T + return None + + def __call__(self, srcField=None, dstField=None, zero_region=None): + """ + Apply interpolation weights + + Parameters + ---------- + + srcField source field (or None if src field passed to + constructor is to be used) + + dstField destination field (or None if dst field passed + to constructor is to be used) + + zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) + """ + if srcField is None: + srcField = self.srcField + if dstField is None: + dstField = self.dstField + + # default is keep the masked values intact + zeroregion = ESMF.Region.SELECT + if self.regridMethod == CONSERVE: + zeroregion = None # will initalize to zero + + self.regridHandle( + srcfield=srcField.field, + dstfield=dstField.field, + zero_region=zeroregion) + + def __del__(self): + if self.regridHandle is not None: + self.regridHandle.destroy() diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py new file mode 100644 index 00000000..de150dba --- /dev/null +++ b/regrid2/Lib/gsRegrid.py @@ -0,0 +1,1179 @@ +#!/usr/bin/env python + +""" +Regridding of curvilinear structured grids +Alex Pletzer and Dave Kindig, Tech-X (2011) +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. +""" +# standard python includes +# from re import search, sub +from ctypes import c_double, c_float, c_int, \ + c_wchar_p, CDLL, byref, POINTER +# import ctypes +import operator +import sys +import os +import copy +import numpy +import warnings +from regrid2 import RegridError +from functools import reduce +import fnmatch + +C_DOUBLE_P = POINTER(c_double) + +# libcf +try: + from pycf import libCFConfig, __path__ +except BaseException: + raise ImportError('Error: could not import pycf') + +LIBCFDIR = __path__[0] + "/pylibcf" + +__FILE__ = sys._getframe().f_code.co_filename + + +def catchError(status, lineno): + if status != 0: + raise RegridError("ERROR in %s: status = %d at line %d" + % (__FILE__, status, lineno)) + + +def getTensorProduct(axis, dim, dims): + """ + Convert an axis into a curvilinear coordinate by applying + a tensor product + + Parameters + ---------- + + axis 1D array of coordinates + + dim dimensional index of the above coordinate + + dims sizes of all coordinates + + Returns + ------- + + coordinate values obtained by tensor product + """ + return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), + numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) + + +def makeCurvilinear(coords): + """ + Turn a mixture of axes and curvilinear coordinates into + full curvilinear coordinates + + Parameters + ---------- + + coords list of coordinates + + Returns + ------- + + new list of coordinates and associated dimensions + """ + rank = len(coords) + + count1DAxes = 0 + dims = [] + for i in range(rank): + coord = coords[i] + if len(coord.shape) == 1: + # axis + dims.append(len(coord)) + count1DAxes += 1 + elif len(coord.shape) == rank: + # fully curvilinear + dims.append(coord.shape[i]) + else: + # assumption: all 1D axes preceed curvilinear + # coordinates!!! + dims.append(coord.shape[i - count1DAxes]) + + for i in range(rank): + nd = len(coords[i].shape) + if nd == rank: + # already in curvilinear form, keep as is + pass + elif nd == 1: + # it's an axis + coords[i] = getTensorProduct(coords[i][:], i, dims) + elif rank == 3 and nd == 2 and i > 0: + # assume leading coordinate is an axis + o1 = numpy.ones((len(coords[0]),), coords[i].dtype) + coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) + else: + raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" + % (__FILE__, str([x.shape for x in coords]))) + return coords, dims + + +def makeCoordsCyclic(coords, dims): + """ + Make coordinates cyclic + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + new, extended coordinates such that the longitudes cover the sphere + and new dimensions + """ + # assume lon is the last coordinate!! + + # check if already extended + eps = 1.e-3 + + # some models already overlap + diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # some models are already periodic + diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # make cyclic by appending a column to the coordinates + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-1] += 1 # append to the right + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:-1] = coords[i][...] + newCoords[i][..., -1] = coords[i][..., 0] + + # add modulo term, want deltas ~ order of dlon otherwise add + # or subtract a periodicity length + nlon = dims[-1] + dlon = 360.0 / float(nlon) # average resolution + tol = 360.0 - min(5, nlon) * dlon + mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) + mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) + newCoords[-1][..., -1] += 360.0 * mask1 + newCoords[-1][..., -1] -= 360.0 * mask2 + + return newCoords, newDims + + +def checkForCoordCut(coords, dims): + """ + Look for a cut in a coordinate system (e.g. tri-polar grid) + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + True for cut found + False for no cut + """ + + # Assume latitude is next to last coordinate and longitude is last + # coordinate!!! + + rank = len(dims) + if rank < 2: + # print 'no cut: dims < 2' + return False + if len(coords[-2].shape) < 2: + # Is the 'lat' coordinate an axis? + return False + + nlat, nlon = dims[-2], dims[-1] + lat = coords[-2] + eps = 1.e-7 + + # Check to see if the top row has already be dealt with by the modeling + # agency. Last row is repeated in reverse. + + topRow = coords[-2][..., nlat - 1, :] + revTop = coords[-2][..., nlat - 1, ::-1] + nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow + diffs = abs(revTop - nextRow) + + # If already accounted for all diffs are 0. + if numpy.all(diffs < eps): + # print "no cut: reversed" + return False + + # Lon of max latitude -- Looking for a rotated pole + maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) + inTopRow = False + if len(maxLats[0] > 0): + inTopRow = numpy.all(maxLats[-2] == nlat - 1) + if not inTopRow: + # The max lats are not in the top row. The cut may already be handled + # print 'no cut: max lat not in top row.' + \ + # 'Either: it is a funky grid or rotated pole' + return False + + # Only in top row. + maxLatInd = lat[..., nlat - 1, :].argmax() + maxLonInd = lat[..., maxLatInd].argmax() + rowOfMaxLat = lat[..., maxLonInd, :] + diffs = rowOfMaxLat - topRow + + if diffs.max() != 0: + # Rotated Pole + # print "no cut: rotated pole" + return False + + # Find locale minima. + # A rotated pole grid has only one minimum. A tripolar grid should + # have two, though they may not be at the same latitude + + minInds = numpy.where(abs(topRow - topRow.min()) < eps) + if len(minInds[0]) > 2: + # Account for the end points matching + # Multiple minima in the top row + return True + + # Now if we have an offset tri-pole. The extra poles are not at the same + # latitude + minCount = 0 + firstInd = topRow.argmin() + diffs = numpy.diff(topRow) + if firstInd == 0: + if revTop.argmin() == 0: + if topRow[firstInd] == revTop[0]: + minCount += 1 + else: + minCount += 1 + # Look for next Minima + index = firstInd + 1 + while diffs[index] > 0: + index += 1 + if index == nlon: + break + nextIndex = topRow[index + 1:].argmin() + index + 1 + if nextIndex != index + 1 and nextIndex != nlon - 1: + minCount += 1 + if minCount == 1: + # print "no cut: one pole" + return False + + return True + + +def handleCoordsCut(coords, dims, bounds): + """ + Generate connectivity across a cut. e.g. from a tri-polar grid. + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates list of rank + + dims input dimensions + + bounds boundaries for each coordinate + + Returns + ------- + + extended coordinates such that there is an extra row containing + connectivity information across the cut + """ + + # Assume latitude is next to last coordinate and longitude is + # last coordinate!!! + + dims = coords[-2].shape + + # Add row to top with connectivity information. This means rearranging + # the top row + def getIndices(array, nlon, newI): + """ + Find indices where a cell edge matches for two cells + + Parameters + ---------- + + array Array of booleans + + nlon number of longitudes + + newI index row with connectivity to be updated + + Returns + ------- + + new coordinates, new dimensions, index row + """ + for i in range(len(array)): + # An edge + if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa + if newI[i] < 0: + newI[i] = (nlon - 1) - i + if newI[(nlon - 1) - i] < 0: + newI[(nlon - 1) - i] = i + + # Assume mkCyclic == True + newI = numpy.arange(nlon - 1, -1, -1) - 1 + newI[nlon - 1] = 0 # Complete the rotation + + # Build new coordinate array and adjust dims + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-2] += 1 + + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:dims[-2], :] = coords[i][...] + newCoords[i][..., dims[-2], + :] = coords[i][..., dims[-2] - 1, newI] + + return newCoords, newDims, newI + + +class Regrid: + + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, + handleCut=False, verbose=False): + """ + Constructor + + Parameters + ---------- + + src_grid source grid, a list of [x, y, ...] coordinates + or a cdms2.grid.Transient + + dst_grid destination grid, a list of [x, y, ...] coordinates + + src_bounds list of cell bounding coordinates (to be used when + handling a cut in coordinates) + + mkCyclic Add a column to the right side of the grid to complete + a cyclic grid + + handleCut Add a row to the top of grid to handle a cut for + grids such as the tri-polar grid + + verbose print diagnostic messages + + + Note: the grid coordinates can either be axes (rectilinear grid) or + n-dimensional for curvilinear grids. Rectilinear grids will + be converted to curvilinear grids. + """ + self.regridid = c_int(-1) + self.src_gridid = c_int(-1) + self.dst_gridid = c_int(-1) + self.rank = 0 + self.src_dims = [] + self.dst_dims = [] + self.src_coords = [] + self.dst_coords = [] + self.lib = None + self.extendedGrid = False + self.handleCut = False + self.dst_Index = [] + self.verbose = verbose + self.weightsComputed = False + self.maskSet = False + + # Open the shaped library + dynLibFound = False + for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': + if os.path.exists(LIBCFDIR + sosuffix): + dynLibFound = True + CFfile = self.find('pylibcf.*', __path__[0]) + if os.path.exists(CFfile): + try: + self.lib = CDLL(CFfile) + except BaseException: + pass +# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': +# if os.path.exists(LIBCFDIR + sosuffix): +# dynLibFound = True +# try: +# self.lib = CDLL(LIBCFDIR + sosuffix) +# break +# except: +# pass + if self.lib is None: + if not dynLibFound: + raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + + # Number of space dimensions + self.rank = len(src_grid) + + if len(dst_grid) != self.rank: + raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" + % (__FILE__, len(dst_grid), self.rank)) + + if self.rank <= 0: + raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" + % (__FILE__, self.rank)) + + # Convert src_grid/dst_grid to curvilinear grid, if need be + if self.rank > 1: + src_grid, src_dims = makeCurvilinear(src_grid) + dst_grid, dst_dims = makeCurvilinear(dst_grid) + + # Make sure coordinates wrap around if mkCyclic is True + if mkCyclic: + src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + for i in range(self.rank): + print(('...... src_gridNew[%d].shape = %s' + % (i, str(src_gridNew[i].shape)))) + # flag indicating that the grid was extended + if reduce(lambda x, y: x + y, + [src_dimsNew[i] - src_dims[i] + for i in range(self.rank)]) > 0: + self.extendedGrid = True + # reset + src_grid = src_gridNew + src_dims = src_dimsNew + + # Handle a cut in the coordinate system. Run after mkCyclic. + # e.g. a tri-polar grid + if handleCut and src_bounds is not None: + # Test for the presence of a cut. + isCut = checkForCoordCut(src_grid, src_dims) + if isCut: + # No cut + src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, + src_dims, src_bounds) + if dst_Index is not None: + self.handleCut = True + self.extendedGrid = self.extendedGrid + else: + self.handleCut = False + self.extendedGrid = self.extendedGrid + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + src_grid = src_gridNew + src_dims = src_dimsNew + self.dst_Index = dst_Index + + self.src_dims = (c_int * self.rank)() + self.dst_dims = (c_int * self.rank)() + + # Build coordinate objects + src_dimnames = (c_wchar_p * self.rank)() + dst_dimnames = (c_wchar_p * self.rank)() + for i in range(self.rank): + src_dimnames[i] = 'src_n%d' % i + dst_dimnames[i] = 'dst_n%d' % i + self.src_dims[i] = src_dims[i] + self.dst_dims[i] = dst_dims[i] + self.src_coordids = (c_int * self.rank)() + self.dst_coordids = (c_int * self.rank)() + save = 0 + standard_name = "" + units = "" + coordid = c_int(-1) + for i in range(self.rank): + data = numpy.array(src_grid[i], numpy.float64) + self.src_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "src_coord%d" % i + # assume [lev,] lat, lon ordering + if i == self.rank - 2: + standard_name = 'latitude' + units = 'degrees_north' + elif i == self.rank - 1: + standard_name = 'longitude' + units = 'degrees_east' + status = self.lib.nccf_def_coord(self.rank, self.src_dims, + src_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.src_coordids[i] = coordid + + data = numpy.array(dst_grid[i], numpy.float64) + self.dst_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "dst_coord%d" % i + status = self.lib.nccf_def_coord(self.rank, self.dst_dims, + dst_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.dst_coordids[i] = coordid + + # Build grid objects + status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", + byref(self.src_gridid)) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", + byref(self.dst_gridid)) + catchError(status, sys._getframe().f_lineno) + + # Create regrid object + status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, + byref(self.regridid)) + catchError(status, sys._getframe().f_lineno) + + def getPeriodicities(self): + """ + Get the periodicity lengths of the coordinates + + Returns + ------- + + numpy array, values inf indicate no periodicity + """ + coord_periodicity = numpy.zeros((self.rank,), numpy.float64) + status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, + coord_periodicity.ctypes.data_as(C_DOUBLE_P)) + catchError(status, sys._getframe().f_lineno) + return coord_periodicity + + def __del__(self): + """ + Destructor, will be called automatically + """ + status = self.lib.nccf_free_regrid(self.regridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.src_gridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.dst_gridid) + catchError(status, sys._getframe().f_lineno) + + for i in range(self.rank): + + status = self.lib.nccf_free_coord(self.src_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_coord(self.dst_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + def find(self, pattern, path): + result = "" + for root, dirs, files in os.walk(path): + for name in files: + if fnmatch.fnmatch(name, pattern): + result = os.path.join(root, name) + return result + + def setValidMask(self, inMask): + """ + Set valid mask array for the grid + + Parameters + ---------- + + inMask flat numpy array of type numpy.int32 or a valid cdms2 variable + with its mask set. + 0 - invalid, 1 - valid data + + Note: This must be invoked before computing the weights, the + mask is a property of the grid (not the data). + """ + if self.weightsComputed: + raise RegridError('Must set mask before computing weights') + + mask = numpy.array(inMask, dtype=numpy.int32) + + # extend src data if grid was made cyclic and or had a cut accounted + # for + newMask = self._extend(mask) + c_intmask = newMask.ctypes.data_as(POINTER(c_int)) + status = self.lib.nccf_set_grid_validmask(self.src_gridid, + c_intmask) + catchError(status, sys._getframe().f_lineno) + self.maskSet = True + + def setMask(self, inDataOrMask): + """ + Set mask array. The mask is defined for nodes + + Parameters + ---------- + + inDataOrMask cdms2 array or flat mask array, + 0 - valid data + 1 - invalid data + + Note: this definition is compatible with the numpy masked arrays + + Note: note see setValidMask for the opposite definition + + Note: should be called before computing the weights + """ + mask = None + if hasattr(inDataOrMask, 'getmask'): + # cdms2 variable + mask = inDataOrMask.getmask() + else: + # flat mask array + mask = inDataOrMask + # reversing the meaning 1 == valid, 0 == invalid + mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) + # now calling our own mask setter + self.setValidMask(mask) + + def computeWeights(self, nitermax=100, tolpos=1.e-2): + """ + Compute the the interpolation weights + + Parameters + ---------- + + nitermax max number of iterations + + tolpos max tolerance when locating destination positions in + index space + """ + status = self.lib.nccf_compute_regrid_weights(self.regridid, + nitermax, + c_double(tolpos)) + catchError(status, sys._getframe().f_lineno) + self.weightsComputed = True + + def apply(self, src_data_in, dst_data, missingValue=None): + """ + Apply interpolation + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + if not self.weightsComputed: + raise RegridError('Weights must be set before applying the regrid') + # extend src data if grid was made cyclic and or had a cut accounted + # for + src_data = self._extend(src_data_in) + + # Check + if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + + "%s != %s") % (__FILE__, str(src_data.shape), + str(tuple([d for d in self.src_dims])))) + if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + + "%s != %s") % (__FILE__, str(dst_data.shape), + str(tuple([d for d in self.dst_dims])))) + + # Create temporary data objects + src_dataid = c_int(-1) + dst_dataid = c_int(-1) + save = 0 + standard_name = "" + units = "" + time_dimname = "" + + status = self.lib.nccf_def_data(self.src_gridid, "src_data", + standard_name, units, time_dimname, + byref(src_dataid)) + catchError(status, sys._getframe().f_lineno) + + if src_data.dtype != dst_data.dtype: + try: # try recasting + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" + % (src_data.dtype, dst_data.dtype)) + src_data = src_data.astype(dst_data.dtype) + except BaseException: + try: + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" + % (src_data.dtype, dst_data.dtype)) + dst_data = dst_data.astype(src_data.dtype) + except BaseException: + raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" + % (__FILE__, src_data.dtype, dst_data.dtype)) + + # only float64 and float32 data types are supported for interpolation + if src_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif src_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" + % (__FILE__, src_data.dtype)) + + status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", + standard_name, units, time_dimname, + byref(dst_dataid)) + catchError(status, sys._getframe().f_lineno) + if dst_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif dst_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid dst_data type = %s" + % (__FILE__, dst_data.dtype)) + + # Now apply weights + status = self.lib.nccf_apply_regrid( + self.regridid, src_dataid, dst_dataid) + catchError(status, sys._getframe().f_lineno) + + # Clean up + status = self.lib.nccf_free_data(src_dataid) + catchError(status, sys._getframe().f_lineno) + status = self.lib.nccf_free_data(dst_dataid) + catchError(status, sys._getframe().f_lineno) + + return dst_data + + def __call__(self, src_data, dst_data, missingValue=None): + """ + Apply interpolation (synonymous to apply method) + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + self.apply(src_data, dst_data, missingValue) + + def getNumValid(self): + """ + Return the number of valid destination points. Destination points + falling outside the source domain, more gnerally, points which + could not be located on the source grid, reduce the number of + valid points. + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_nvalid(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getNumDstPoints(self): + """ + Return the number of points on the destination grid + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_ntargets(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getSrcGrid(self): + """ + Return the source grid + + Returns + ------- + + grid + """ + return self.src_coords + + def getDstGrid(self): + """ + Return the destination grid + + Returns + ------- + + grid + """ + return self.dst_coords + + def getIndicesAndWeights(self, dst_indices): + """ + Get the indices and weights for a single target location + + Parameters + ---------- + + dst_indices index set on the target grid + + Returns + ------- + + [index sets on original grid, weights] + """ + dinds = numpy.array(dst_indices) + sinds = (c_int * 2**self.rank)() + weights = numpy.zeros((2**self.rank,), numpy.float64) + status = self.lib.nccf_inq_regrid_weights(self.regridid, + dinds.ctypes.data_as( + POINTER(c_double)), + sinds, + weights.ctypes.data_as(POINTER(c_double))) + catchError(status, sys._getframe().f_lineno) + # convert the flat indices to index sets + ori_inds = [] + for i in range(2**self.rank): + inx = numpy.zeros((self.rank,), numpy.int32) + self.lib.nccf_get_multi_index(self.rank, self.src_dims, + sinds[i], + inx.ctypes.data_as(POINTER(c_int))) + ori_inds.append(inx) + + return ori_inds, weights + + def _extend(self, src_data): + """ + Extend the data by padding a column and a row, depending on whether the + grid was made cyclic and a fold was added or not + + Parameters + ---------- + + src_data input source data + + Returns + ------- + + extended source data (or source input data of no padding was applied) + """ + + # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] + # original dimensions, before extension + # assuming ..., lat, lon ordering + nlat, nlon = src_data.shape[-2:] + + # no cut and no cyclic extension + src_dataNew = src_data + + if self.handleCut or self.extendedGrid: + # copy data into new, extended container + src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) + # start filling in... + src_dataNew[..., :nlat, :nlon] = src_data[...] + + if self.handleCut: + # fill in polar cut (e.g. tripolar cut), top row + # self.dst_Index[i] knows how to fold + for i in range(nlon): + src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] + + if self.extendedGrid: + # make data periodic in longitudes + src_dataNew[..., -1] = src_dataNew[..., 0] + + return src_dataNew + + def _findIndices(self, targetPos, nitermax, tolpos, + dindicesGuess): + """ + Find the floating point indices + + Parameters + ---------- + + targetPos numpy array of target positions + + nitermax max number of iterations + + tolpos max toelrance in positions + + dindicesGuess guess for the floating point indices + + Returns + ------- + + indices, number of iterations, achieved tolerance + """ + posPtr = targetPos.ctypes.data_as(POINTER(c_double)) + adjustFunc = None + hit_bounds = numpy.zeros((self.rank), + dtype=int).ctypes.data_as(POINTER(c_int)) + # no periodicity + coord_periodicity = float( + 'inf') * numpy.ones((self.rank), targetPos.dtype) + coord_periodicity_ptr = coord_periodicity.ctypes.data_as( + POINTER(c_double)) + res = copy.copy(dindicesGuess) + resPtr = res.ctypes.data_as(POINTER(c_double)) + src_coords = (POINTER(c_double) * self.rank)() + niter = c_int(nitermax) + tol = c_double(tolpos) + for i in range(self.rank): + ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) + src_coords[i] = ptr + status = self.lib.nccf_find_indices_double(self.rank, + self.src_dims, + src_coords, + coord_periodicity_ptr, + posPtr, + byref(niter), + byref(tol), + adjustFunc, + resPtr, + hit_bounds) + catchError(status, sys._getframe().f_lineno) + return resPtr.contents.value, niter.value, tol.value + +###################################################################### + + +def testMakeCyclic(): + + y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) + x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) + yy = getTensorProduct(y, 0, [len(y), len(x)]) + xx = getTensorProduct(x, 1, [len(y), len(x)]) + coords = [yy, xx] + dims = [len(y), len(x)] + newCoords, newDims = makeCoordsCyclic(coords, dims) +# print 'cyclic lats' +# print newCoords[0] +# print 'cyclic lons' +# print newCoords[1] + + +def testHandleCut(): + + import cdms2 + # Need tripolar grid + filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" + f = cdms2.open(filename) + if not f: + return + + # so = f.variables['so'][0, 0, :, :] + if 'lon' in list(f.variables.keys()): + alllat = f.variables['lat'] + alllon = f.variables['lon'] + else: + alllat = f.getAxis("lat").getData() + alllon = f.getAxis("lon").getData() + + bounds = [f.variables['bounds_lon'][:].data, + f.variables['bounds_lat'][:].data] + coords = [alllat[:].data, alllon[:].data] + dims = alllat.shape + newCoords, newDims = makeCoordsCyclic(coords, dims) + newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) + + +# def testOuterProduct(): + + # 2d + # x = numpy.array([1, 2, 3, 4]) + # y = numpy.array([10, 20, 30]) + # xx = getTensorProduct(x, 0, [len(x), len(y)]) + # yy = getTensorProduct(y, 1, [len(x), len(y)]) + + # z = numpy.array([100, 200]) + # Mixed coordinates and axes + # aa = makeCurvilinear([z, yy, xx]) + # for g in aa: + # print g + +def test(): + def func1(coords): + return coords[0] * coords[1] + coords[2] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = numpy.array([1, 2, 3, 4, 5, 6]) + src_y = numpy.array([10, 20, 30, 40, 50]) + src_z = numpy.array([100, 200]) + + # destination grid, product of axes + dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) + dst_y = numpy.array([15., 20., 25., 30., 40.]) + dst_z = numpy.array([120.0, 180.0, 240.]) + + # regridding constructor + rg = Regrid([src_x, src_y, src_z], + [dst_x, dst_y, dst_z]) +# rg = Regrid([src_x, src_y], +# [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + maxNumIters = 20 + posTol = 1.e-3 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data = ', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +def testMasking(): + import numpy.ma as ma + + def func1(coords): + return coords[0] * coords[1] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) + src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) + + # destination grid, product of axes + dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, + 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) + dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) + + # regridding constructor + rg = Regrid([src_x, src_y], + [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + # Mask needs to be set before weights are computed + mask = rg.getSrcGrid()[0] == 3 + mask[:, 3] = True + rg.setValidMask(mask) + rg.setMask(mask) + maxNumIters = 20 + posTol = 1.e-2 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data =\n', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +if __name__ == '__main__': + # testOuterProduct() + test() + testMasking() + # testMakeCyclic() + # testHandleCut() diff --git a/regrid2/Lib/gs_horizontal.py b/regrid2/Lib/gs_horizontal.py new file mode 100644 index 00000000..20cfa4a6 --- /dev/null +++ b/regrid2/Lib/gs_horizontal.py @@ -0,0 +1,214 @@ +import sys +import os +import os.path +# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer +from ctypes import CDLL, c_double, c_uint +import cdms2 +import time +import config +sys.path.append("/home/painter1/libcf/") +libcf = CDLL(config.prefix + '/lib/libcf.so') + + +class GS_Regridder: + + def __init__(self, ingrid, outgrid, + infile=None, outfile=None, remapfile=None): + # Save the grids, make and save a Gridspec remap file. + # For now, we are using the libCF/Gridspec API which operates only on files; + # thus temporary files are written out and read back in. That requires the + # input grids to support a "write_gridspec" method. + # If a path is provided, it prefixes whatever filenames were input. + # If there is no path provided, each filename must include its path. + # Note: it's a bit messy to keep filenames and paths separate internally, + # but the presnet Gridspec function expects lots of directories. + + self.ingrid = ingrid + self.outgrid = outgrid + if (not hasattr(ingrid, "gsfile")): + ingrid.gsfile = None + ingrid.gspath = None + if (infile is None): + self.infile = ingrid.gsfile + self.inpath = ingrid.gspath + else: + self.infile = os.path.basename(infile) + self.inpath = os.path.dirname(infile) + if (not os.path.isfile(self.inpath + "/" + self.infile)): + raise OSError( + "cannot open infile " + + self.inpath + + "/" + + self.infile) + + if (not hasattr(outgrid, "gsfile")): + outgrid.gsfile = None + outgrid.gspath = None + if (outfile is None): + self.outfile = outgrid.gsfile + self.outpath = outgrid.gspath + else: + self.outfile = os.path.basename(outfile) + self.outpath = os.path.dirname(outfile) + if (not os.path.isfile(self.outpath + "/" + self.outfile)): + raise OSError( + "cannot open outfile " + + self.outpath + + "/" + + self.outfile) + + if (remapfile is None): + timestr = str(int(time.time())) + self.remapfile = "remap" + timestr + self.remappath = "/tmp" + else: + self.remapfile = os.path.basename(remapfile) + self.remappath = os.path.dirname(remapfile) + if (not os.path.isdir(self.remappath + "/")): + raise OSError( + "cannot open remapfile directory " + + self.remappath + + "/") + + ingrid.write_gridspec(self.inpath + "/" + self.infile) + outgrid.write_gridspec(self.outpath + "/" + self.outfile) + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + # No variables to interpolate; the gs_fregrid call will be just to + # make a remap file... + dir_in = 256 * "\x00" + dir_out = 256 * "\x00" + input_file = 256 * "\x00" + nfiles = 0 + output_file = 256 * "\x00" + nfiles_out = 0 + scalar_name = 256 * "\x00" + nscalar = 0 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + # For a call which only writes the remap files, gs_fregrid + # expects remapfile to be a full path. For a call in which + # remapping takes place, gs_fregrid expects remapfile to be + # a pure filename, in a path it gets from elsewhere, maybe dir_in. + # (ARRGH - but with the API slated to be replaced, I'll live with it) + remapf = os.path.abspath( + self.remappath + "/" + self.remapfile) + "\0" * 256 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + remapf, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + def __call__(self, ar): + # Interpolate the input variable to the new grid using the Gridspec + # remap file generated when this GS_Remapper object was initialized. + # >>>for now, ar is required to be a variable (MV) <<< + + # Here, convert ar into a file for gs_fregrid + # There's no special Gridspec way to write a variable; you write to any + # *.nc file. The tough part is making sure you have there exactly what's + # needed for the gs_fregrid call, especially because the grids are + # supposedly supergrids and you just have some keywords to use to figure + # out what goes where. And note that we'll need to check whether ar + # really lives on self.ingrid . Supposedly a future API will work + # better in this respect + + # Write the variable to a temporary file, as required by gs_fregrid. + # The remap path should be suitable. + # >>> this should be done more carefully, e.g. deal with failures; + # >>> more worth doing when we have mosaic variables. + timestr = str(int(time.time())) + varfile = cdms2.open( + self.inpath + + "/" + + "invvar" + + timestr + + ".nc", + 'w') + varfile.write(ar) + varfile.close() + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + dir_in = 256 * "\x00" # path is already encoded in input_file + dir_out = 256 * "\x00" # path is already encoded in output_file + input_file = varfile.id + 256 * "\x00" + nfiles = 1 + output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" + nfiles_out = 1 + scalar_name = ar.id + 256 * "\x00" + nscalar = 1 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + print(("__call__ remapfile=", self.remapfile)) + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + self.remapfile, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + # Read the output_file into a variable, and return the variable + f = cdms2.open(self.outpath + "/" + output_file) + vout = f(scalar_name) + f.close() + return vout diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py new file mode 100644 index 00000000..67d673f4 --- /dev/null +++ b/regrid2/Lib/horizontal.py @@ -0,0 +1,422 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import warnings +import cdms2 + +_debug = 0 # Set to 1 for debug + +# Map (n,2) boundary arrays to individual boundary arrays. Returns +# (lowerBounds, upperBounds) + + +def extractBounds(bounds): + if bounds[0, 0] < bounds[0, 1]: + lower = bounds[:, 0] + upper = bounds[:, 1] + else: + lower = bounds[:, 1] + upper = bounds[:, 0] + + return (lower.astype(numpy.float32), upper.astype(numpy.float32)) + +# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid +# objects. + + +class Horizontal: + + def __init__(self, ingrid, outgrid): + """ + Constructor for regridding class + + Parameters + ---------- + + ingrid cdms2, ndarray variable + + outgrid cdms2, ndarray variable + """ + + inlat = ingrid.getLatitude() + outlat = outgrid.getLatitude() + inlon = ingrid.getLongitude() + outlon = outgrid.getLongitude() + inlatBounds, inlonBounds = ingrid.getBounds() + outlatBounds, outlonBounds = outgrid.getBounds() + + self.nlati = len(inlat) + self.nlato = len(outlat) + self.nloni = len(inlon) + self.nlono = len(outlon) + self.inmask = ingrid.getMask() + self.outmask = outgrid.getMask() + # Make grid masks consistent with 'internal' convention: + # 0 == invalid + if self.inmask is not None: + self.inmask = 1. - self.inmask + if self.outmask is not None: + self.outmask = 1. - self.outmask + self.inshape = ingrid.shape + self.inorder = ingrid.getOrder() + self.outlat = outgrid.getLatitude().clone() + self.outlon = outgrid.getLongitude().clone() + + bsin, bnin = extractBounds(inlatBounds) + bwin, bein = extractBounds(inlonBounds) + bsout, bnout = extractBounds(outlatBounds) + bwout, beout = extractBounds(outlonBounds) + + if _debug == 1: + import sys + sys.stdout = open('debug_regrid.txt', 'w') + print(("bsin = ", numpy.array2string(bsin, precision=3))) + print(("bnin = ", numpy.array2string(bnin, precision=3))) + print(("bwin = ", numpy.array2string(bwin, precision=3))) + print(("bein = ", numpy.array2string(bein, precision=3))) + print(("bsout = ", numpy.array2string(bsout, precision=3))) + print(("bnout = ", numpy.array2string(bnout, precision=3))) + print(("bwout = ", numpy.array2string(bwout, precision=3))) + print(("beout = ", numpy.array2string(beout, precision=3))) + + self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( + self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) + + def __call__(self, ar, missing=None, order=None, + mask=None, returnTuple=0, **args): + """ + Call the regridder function. + @param ar is the input array. + @param order is of the form "tzyx", "tyx", etc. + @param missing is the missing data value, if any. + @param mask is either 2-D or the same shape as ar. + @param returnTuple If true, return the tuple (outArray, outWeights) where + outWeights is the fraction of each zone of the output grid + which overlaps non-missing zones of the input grid; it has + the same shape as the output array. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Compatibility + if mask is numpy.ma.nomask: + mask = None + + if ar.dtype.type is numpy.bool_: + ar = numpy.asarray(ar, numpy.float32) + + # Make sense of mask consistent with 'internal' convention (0 == + # invalid) + if mask is not None: + mask = 1. - mask + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + armask = ar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + armask = tempar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armask = armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if mask is None and missing is None: + missing = armiss + mask = armask + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = self.inorder + elif rank == 3: + order = "t" + self.inorder + else: + order = "tz" + self.inorder + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to ilon, ilat ... + itim1 = itim2 = 0 + ilon = ilat = -1 + idim = 0 + for i in range(rank - 1, -1, -1): + c = order[i] + if c == 'x': + ilon = idim + elif c == 'y': + ilat = idim + elif c == 'z': + itim1 = idim + elif c == 't': + if rank == 3: + itim1 = idim + else: + itim2 = idim + idim = idim + 1 + + # Map array shape to nloni, nlati, ... + ntim1 = ntim2 = 0 + shape = ar.shape + if ilon == -1: + raise RegridError("Input grid does not have a longitude axis") + if ilat == -1: + raise RegridError("Input grid does not have a latitude axis") + nlati = shape[rank - ilat - 1] + nloni = shape[rank - ilon - 1] + if nlati != self.nlati or nloni != self.nloni: + raise ( + 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % + (nlati, nloni, self.nlati, self.nloni)) + + if itim1 != 0: + ntim1 = shape[rank - itim1 - 1] + if itim2 != 0: + ntim2 = shape[rank - itim2 - 1] + + # Construct the input mask: + # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask + # if no user mask is specified) + # with the 'implicit mask' generated from the missing data, if any + if (mask is None) or len(mask.shape) == 2: + flag2D = 1 + if mask is not None: + assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' + inmask = mask + elif self.inmask is None: + inmask = numpy.ones(self.inshape) + else: + inmask = self.inmask + + if missing is not None: + if rank == 2: + firstslice = ar + elif rank == 3: + firstslice = ar[0] + else: + firstslice = ar[0, 0] + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + firstslice - + missing), + numpy.absolute( + 0.001 * + missing)), + inmask, + 0) + + # If the user mask was specified and is > 2-D, it overrides the grid + # mask + else: + assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' + inmask = mask + flag2D = 0 # 2-D user masks are handled above + # If armask is derived from the input array, it is probably consistent + # with the missing value - don't bother recalculating it + if missing is not None and armask is None: + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + ar - missing), + numpy.absolute( + 0.001 * missing)), + inmask, + 0) + # Cast the mask to float + inmask = inmask.astype(numpy.float32) + if missing is None: + missing = 1.0e20 + + # Cast the input array to 32-bit floats, if necessary + if ar.dtype.char != numpy.float32: + ar = ar.astype(numpy.float32) + + # Malloc return array + outshape = list(shape) + outshape[rank - ilat - 1] = self.nlato + outshape[rank - ilon - 1] = self.nlono + outar = numpy.zeros(tuple(outshape), numpy.float32) + + # Perform the regridding. The return array has the same shape + # as the output array, and is the fraction of the zone which overlaps + # a non-masked zone of the input grid. + amskout = _regrid.rgdarea( + ilon, + ilat, + itim1, + itim2, + ntim1, + ntim2, + nloni, + self.nlono, + nlati, + self.nlato, + flag2D, + missing, + self.londx, + self.lonpt, + self.wtlon, + self.latdx, + self.latpt, + self.wtlat, + inmask, + ar, + outar) + + # Correct the shape of output weights + amskout.shape = outar.shape + + # Set the missing data mask of the output array, if any. + hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) + if hasMissing: + slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) + else: + slabMask = None + + # Combine missing data mask and output grid mask + # Note: slabMask and outmask are Boolean here + if self.outmask is not None: + outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) + if hasMissing: + outmask = numpy.ma.logical_or(outmask, slabMask) + else: + outmask = slabMask + + # Create the result TransientVariable (if input ar is an AbstractVariable) + # or masked array + if inputIsVariable == 1: + for i in range(len(order)): + if order[i] == 'x': + axislist[i] = self.outlon + elif order[i] == 'y': + axislist[i] = self.outlat + result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array( + outar, mask=outmask, fill_value=missing) + + if returnTuple == 0: + return result + else: + return result, amskout + + +class Regridder(Horizontal): + def __init__(self, ingrid, outgrid): + warnings.warn( + "While this will work for now, please note that the Regridder class has been " + + "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + + "Please edit your code accordingly", + Warning) + Horizontal.__init__(self, ingrid, outgrid) + + +def input_mask(ain, type, mask, missing=None): + """ #------------------------------------------------------------------- + # + # purpose: set up the input mask including missing from ain + # + # usage: + # + # passed : + # + # returned: + # + # + #------------------------------------------------------------------------""" + if type != 'h' and type != 'v': + raise ValueError('Mask type must be h or v') + return + + if missing is None: + try: + omit = ain.missing_value + except AttributeError: + omit = 1.0e20 + else: + omit = missing + + # ----- insert 0.0 in mask where array has missing data ------- + + mask_size = len(mask.shape) + data_size = len(ain.shape) + + if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a + + if data_size == 3: # caution: assuming standard order lat-lon varying the fastest + if type == 'h': + reduced = ain[0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[:, :, 0] + elif data_size == 4: + if type == 'h': + reduced = ain[0, 0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[0, :, :, 0] + else: + raise IndexError('Data size is out of range') + return + + amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + else: # 0.0 -> missing in passed mask + + amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + return omit, amskin diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py new file mode 100644 index 00000000..235e1fd5 --- /dev/null +++ b/regrid2/Lib/mvESMFRegrid.py @@ -0,0 +1,483 @@ +""" +ESMF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import re +import numpy + +import ESMF +from . import esmf +from . import RegridError +from .mvGenericRegrid import GenericRegrid + +ESMF.Manager(debug=False) +HAVE_MPI = False +try: + from mpi4py import MPI + HAVE_MPI = True +except BaseException: + pass + +# constants +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class ESMFRegrid(GenericRegrid): + """ + Regrid class for ESMF + """ + + def __init__(self, srcGridshape, dstGridshape, dtype, + regridMethod, staggerLoc, periodicity, coordSys, + srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, + dstGridMask=None, hasDstBounds=False, dstGridAreas=None, + ignoreDegenerate=False, + **args): + """ + Constructor + @param srcGridShape tuple source grid shape + @param dstGridShape tuple destination grid shape + @param dtype a valid numpy data type for the src/dst data + @param regridMethod 'linear', 'conserve', or 'patch' + @param staggerLoc the staggering of the field, 'center' or 'corner' + @param periodicity 0 (no periodicity), + 1 (last coordinate is periodic, + 2 (both coordinates are periodic) + @param coordSys 'deg', 'cart', or 'rad' + @param hasSrcBounds tuple source bounds shape + @param hasDstBounds tuple destination bounds shape + @param ignoreDegenerate Ignore degenerate celss when checking inputs + """ + + # esmf grid objects (tobe constructed) + self.srcGrid = None + self.dstGrid = None + self.dtype = dtype + + self.srcGridShape = srcGridshape + self.dstGridShape = dstGridshape + self.ignoreDegenerate = ignoreDegenerate + self.ndims = len(self.srcGridShape) + + self.hasSrcBounds = hasSrcBounds + self.hasDstBounds = hasDstBounds + + self.regridMethod = BILINEAR + self.regridMethodStr = 'linear' + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.regridMethod = CONSERVE + self.regridMethodStr = 'conserve' + elif re.search('patch', regridMethod.lower()): + self.regridMethod = PATCH + self.regridMethodStr = 'patch' + + # data stagger + self.staggerloc = CENTER + self.staggerlocStr = 'center' + if isinstance(staggerLoc, str): + if re.search('vface', staggerLoc.lower(), re.I): + self.staggerloc = VFACE + self.staggerlocStr = 'vcorner' + # there are other staggers we could test here + elif re.search('corner', staggerLoc.lower(), re.I) or \ + re.search('node', staggerLoc.lower(), re.I): + self.staggerloc = CORNER + self.staggerlocStr = 'corner' + # there are other staggers we could test here + + # good for now + unMappedAction = args.get('unmappedaction', 'ignore') + self.unMappedAction = ESMF.UnmappedAction.IGNORE + if re.search('error', unMappedAction.lower()): + self.unMappedAction = ESMF.UnmappedAction.ERROR + + self.coordSys = ESMF.CoordSys.SPH_DEG + self.coordSysStr = 'deg' + if re.search('cart', coordSys.lower()): + self.coordSys = ESMF.CoordSys.CART + self.coordSysStr = 'cart' + elif re.search('rad', coordSys.lower()): + self.coordSys = ESMF.CoordSys.SPH_RAD + self.coordSysStr = 'rad' + + self.periodicity = periodicity + + # masks can take several values in ESMF, we'll have just one + # value (1) which means invalid +# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) +# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) + + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.srcMaskValues = numpy.array([1], dtype=numpy.int32) + self.dstMaskValues = numpy.array([1], dtype=numpy.int32) + else: + self.srcMaskValues = srcGridMask + self.dstMaskValues = dstGridMask + + # provided by user or None + self.srcGridAreas = srcGridAreas + self.dstGridAreas = dstGridAreas + self.maskPtr = None + + # MPI stuff + self.pe = 0 + self.nprocs = 1 + self.comm = None + if HAVE_MPI: + self.comm = MPI.COMM_WORLD + self.pe = self.comm.Get_rank() + self.nprocs = self.comm.Get_size() + + # checks + if self.ndims != len(self.dstGridShape): + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological +dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ + (self.ndims, len(self.dstGridShape)) + raise RegridError(msg) + + # Initialize the grids without data. + self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasSrcBounds) + self.dstGrid = esmf.EsmfStructGrid(dstGridshape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasDstBounds) + + # Initialize the fields with data. + self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.srcFld.field.data[:] = -1 + self.dstFld.field.data[:] = -1 + self.srcAreaField.field.data[:] = 0.0 + self.dstAreaField.field.data[:] = 0.0 + self.srcFracField.field.data[:] = 1.0 + self.dstFracField.field.data[:] = 1.0 + + def setCoords(self, srcGrid, dstGrid, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + globalIndexing=False, **args): + """ + Populator of grids, bounds and masks + @param srcGrid list [[z], y, x] of source grid arrays + @param dstGrid list [[z], y, x] of dstination grid arrays + @param srcGridMask list [[z], y, x] of arrays + @param srcBounds list [[z], y, x] of arrays + @param srcGridAreas list [[z], y, x] of arrays + @param dstGridMask list [[z], y, x] of arrays + @param dstBounds list [[z], y, x] of arrays + @param dstGridAreas list [[z], y, x] of arrays + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + """ + + # create esmf source Grid + self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + + if srcGridMask is not None: + self.srcGrid.setMask(srcGridMask, self.staggerloc) + + if srcBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + # VCORNER for 3D + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + # create destination Grid + self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + if dstGridMask is not None: + self.dstGrid.setMask(dstGridMask) + + if dstBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args (not used) + """ + self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, + dstfield=self.dstFld.field, + src_mask_values=self.srcMaskValues, + dst_mask_values=self.dstMaskValues, + regrid_method=self.regridMethod, + unmapped_action=self.unMappedAction, + ignore_degenerate=True) + + def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): + """ + Regrid source to destination. + When used in parallel, if the processor is not the root processor, + the dstData returns None. + + Source data mask: + + . If you provide srcDataMask in args the source grid will + be masked and weights will be recomputed. + + . Subsequently, if you do not provide a srcDataMask the last + weights will be used to regrid the source data array. + + . By default, only the data are masked, but not the grid. + + @param srcData array source data, shape should + cover entire global index space + @param dstData array destination data, shape should + cover entire global index space + @param rootPe if other than None, then data will be MPI gathered + on the specified rootPe processor + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + @param **args + """ + +# if args.has_key('srcDataMask'): +# srcDataMask=args.get('srcDataMask') + # Make sure with have a mask intialized for this grid. + +# if(self.maskPtr is None): +# if(self.srcFld.field.grid.mask[self.staggerloc] is None): +# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) +# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, +# staggerloc=self.staggerloc) + # Recompute weights only if masks are different. +# if(not numpy.array_equal(self.maskPtr, srcDataMask)): +# self.maskPtr[:] = srcDataMask[:] +# self.computeWeights(**args) + + zero_region = ESMF.Region.SELECT + if 'zero_region' in args.keys(): + zero_region=args.get('zero_region') + + self.srcFld.field.data[:] = srcData.T + self.dstFld.field.data[:] = dstData.T + # regrid + + self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) + + # fill in dstData + if rootPe is None and globalIndexing: + # only fill in the relevant portion of the data + slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) + dstData[slab] = self.dstFld.getData(rootPe=rootPe) + else: + tmp = self.dstFld.field.data.T + if tmp is None: + dstData = None + else: + dstData[:] = tmp + + def getDstGrid(self): + """ + Get the destination grid on this processor + @return grid + """ + return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) + for i in range(self.ndims)] + + def getSrcAreas(self, rootPe): + """ + Get the source grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.srcAreaField.field.get_area() + return self.srcAreaField.field.data + else: + return None + + def getDstAreas(self, rootPe): + """ + Get the destination grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.dstAreaField.field.get_area() + return self.dstAreaField.field.data + else: + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.srcFracField.field.data + else: + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.dstFracField.field.data + else: + return + + def getSrcLocalShape(self, staggerLoc): + """ + Get the local source coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getCoordShape(stgloc) + + def getDstLocalShape(self, staggerLoc): + """ + Get the local destination coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getCoordShape(stgloc) + + def getSrcLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center'): + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getLocalSlab(stgloc) + + def getDstLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center') + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getLocalSlab(stgloc) + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'srcAreaFractions', 'dstAreaFractions', + 'srcAreas', 'dstAreas' + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + oldMethods = {} + oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' + oldMethods['dstAreaFractions'] = 'getDstAreaFractions' + oldMethods['srcAreas'] = 'getSrcAreas' + oldMethods['dstAreas'] = 'getDstAreas' + for entry in 'srcAreaFractions', 'dstAreaFractions', \ + 'srcAreas', 'dstAreas': + if entry in diag: + diag[entry] = eval( + 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T + diag['regridTool'] = 'esmf' + diag['regridMethod'] = self.regridMethodStr + diag['periodicity'] = self.periodicity + diag['coordSys'] = self.coordSysStr + diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py new file mode 100644 index 00000000..2452e9c4 --- /dev/null +++ b/regrid2/Lib/mvGenericRegrid.py @@ -0,0 +1,313 @@ +""" +Generic interface to multiple regrid classes. No dependence on cdms2 variables. + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import operator +import numpy + +import regrid2 +import re +from distarray import MultiArrayIter +from functools import reduce + +# used to locate fully masked cells +EPS = 10 * 1.19209e-07 + + +def guessPeriodicity(srcBounds): + """ + Guess if a src grid is periodic + @param srcBounds the nodal src set of coordinates + @return 1 if periodic, warp around, 0 otherwise + """ + res = 0 + if srcBounds is not None: + res = 1 + # assume longitude to be the last coordinate + lonsb = srcBounds[-1] + nlon = lonsb.shape[-1] + dlon = (lonsb.max() - lonsb.min()) / float(nlon) + tol = 1.e-2 * dlon + if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] + ).sum() / float(lonsb.size)) > tol: + # looks like a regional model + res = 0 + return res + + +class GenericRegrid: + """ + Generic Regrid class. + """ + + def __init__(self, srcGrid, dstGrid, + dtype, + regridMethod, + regridTool, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + **args): + """ + Constructor. + @param srcGrid list of numpy arrays, source horizontal coordinates + @param dstGrid list of numpy arrays, destination horizontal coordinate + @param dtype numpy data type for src/dst data + @param regridMethod linear (bi, tri,...) default or conservative + @param regridTool currently either 'libcf' or 'esmf' + @param srcGridMask array of same shape as srcGrid + @param srcBounds list of numpy arrays of same shape as srcGrid + @param srcGridAreas array of same shape as srcGrid + @param dstGridMask array of same shape as dstGrid + @param dstBounds list of numpy arrays of same shape as dstGrid + @param dstGridAreas array of same shape as dstGrid + @param **args additional arguments to be passed to the + specific tool + 'libcf': mkCyclic={True, False}, handleCut={True,False} + 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... + """ + + self.nGridDims = len(srcGrid) + self.regridMethod = regridMethod + + if len(srcGrid) != len(dstGrid): + msg = 'mvGenericRegrid.__init__: mismatch in number of dims' + msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ + (self.nGridDims, len(dstGrid)) + raise regrid2.RegridError(msg) + + # parse the options + if re.search('libcf', regridTool.lower()) or \ + re.search('gsreg', regridTool.lower()): + # LibCF + self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + **args) + elif re.search('esm', regridTool.lower()): + # ESMF + staggerLoc = args.get('staggerLoc', 'center') + if 'staggerLoc' in args: + del args['staggerLoc'] + periodicity = args.get('periodicity', + guessPeriodicity(srcBounds)) + if 'periodicity' in args: + del args['periodicity'] + coordSys = args.get('coordSys', 'deg') + if 'coordSys' in args: + del args['coordSys'] + + # Get the shapes + self.srcGridShape = srcGrid[0].shape + self.dstGridShape = dstGrid[0].shape + self.hasSrcBounds = False + self.hasDstBounds = False + + if srcBounds is not None: + self.hasSrcBounds = True + + if dstBounds is not None: + self.hasDstBounds = True + + self.srcGridAreasShape = None + self.dstGridAreasShape = None + + if srcGridAreas is not None: + self.srcGridAreasShape = srcGridAreas[0].shape + + if dstGridAreas is not None: + self.dstGridAreasShape = dstGridAreas[0].shape + + # Initialize + self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, + dtype=dtype, + regridMethod=regridMethod, + staggerLoc=staggerLoc, + periodicity=periodicity, + coordSys=coordSys, + hasSrcBounds=self.hasSrcBounds, + hasDstBounds=self.hasDstBounds, + srcGridAreasShape=self.srcGridAreasShape, + dstGridAreasShape=self.dstGridAreasShape, + **args) + + self.tool.setCoords(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + srcGridAreas=srcGridAreas, + dstGridMask=dstGridMask, + dstBounds=dstBounds, + dstGridAreas=dstGridAreas, + globalIndexing=True, + **args) + else: + msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, +valid choices are: 'libcf', 'esmf'""" % regridTool + raise regrid2.RegridError(msg) + + def computeWeights(self, **args): + """ + Compute Weights + """ + self.tool.computeWeights(**args) + + def apply(self, srcData, dstData, + rootPe=None, + missingValue=None, + **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param rootPe if other than None, then results will be MPI + gathered + @param missingValue if not None, then data mask will be interpolated + and data value set to missingValue when masked + """ + + # assuming the axes are the slowly varying indices + srcHorizShape = srcData.shape[-self.nGridDims:] + dstHorizShape = dstData.shape[-self.nGridDims:] + + srcDataMaskFloat = None + dstDataMaskFloat = None + dstMask = None + if missingValue is not None: + srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) + dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) + + nonHorizShape = srcData.shape[: -self.nGridDims] + + if len(nonHorizShape) == 0: + + # + # no axis... just call apply + # + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (srcData == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later + indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), + dtype=srcData.dtype) + + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, **args) + if re.search('conserv', self.regridMethod.lower(), re.I): + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) + + # Initialize output to missin_value + dstData[:] = missingValue + # interpolate the data + self.tool.apply(indata, dstData, rootPe=rootPe, + globalIndexing=True, **args) + + # add missing values + dstData *= (1 - dstMask) + dstData += dstMask * missingValue + + else: + # no masking, just interpolate the data + self.tool.apply(srcData, dstData, rootPe=rootPe, + globalIndexing=True, **args) + else: + + nonHorizShape2 = dstData.shape[: -self.nGridDims] + if not numpy.all(nonHorizShape2 == nonHorizShape): + msg = 'mvGenericRegrid.apply: axes detected ' + msg += 'but %s != %s ' % (str(nonHorizShape2), + str(nonHorizShape)) + raise regrid2.RegridError(msg) + + # + # iterate over all axes + # + + # create containers to hold input/output values + # (a copy is essential here) + zros = '[' + ('0,' * len(nonHorizShape)) + '...]' + indata = numpy.array(eval('srcData' + zros)) + outdata = numpy.array(eval('dstData' + zros)) + + # now iterate over all non lat/lon coordinates + for it in MultiArrayIter(nonHorizShape): + + indices = it.getIndices() + slce = '[' + slce += reduce(operator.add, ['%d,' % i for i in indices]) + slce += '...]' + indata = eval('srcData' + slce) + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (indata == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later +# indata *= (1 - (srcDataMaskFloat == 1)) + +# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, + srcDataMask=(1 - srcDataMaskFloat), **args) + + if re.search('conserv', self.regridMethod.lower(), re.I): + # cell interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + # nodal interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 0), numpy.int32) + + # interpolate the data, using the appropriate tool + self.tool.apply(indata, outdata, rootPe=rootPe, + globalIndexing=True, + srcDataMask=srcDataMaskFloat, **args) + +# import vcs +# pp = vcs.init() +# pp.plot(indata) +# pp.interact() +# pp.clear() +# pp.plot(outdata) +# pp.interact() +# pp.clear() + # apply missing value contribution + if missingValue is not None: + # add mask contribution + outdata *= (1 - dstMask) + outdata += dstMask * missingValue + + # fill in dstData + exec('dstData' + slce + ' = outdata') + + def getDstGrid(self): + """ + Return the destination grid, may be different from the dst grid provided + to the constructor due to domain decomposition + @return local grid on this processor + """ + return self.tool.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe=None): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + entries are tool dependent + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py new file mode 100644 index 00000000..30c5f4bf --- /dev/null +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -0,0 +1,101 @@ +""" +LibCF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" + +from regrid2 import gsRegrid +from regrid2 import GenericRegrid + + +class LibCFRegrid(GenericRegrid): + """ + """ + + def __init__(self, srcGrid, dstGrid, srcGridMask=None, + srcBounds=None, **args): + """ + Constructor + @param srcGrid array + @param dstGrid array + @param srcBounds cell boundaries + @param **args keyword arguments, eg mkCyclic, handleCut, ... + to be passed to gsRegrid + """ + self.regridMethodStr = 'linear' + self.mkCyclic = args.get('mkCyclic', False) + self.handleCut = args.get('handleCut', False) + self.verbose = args.get('verbose', False) + self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, + src_bounds=srcBounds, + mkCyclic=self.mkCyclic, + handleCut=self.handleCut) + if srcGridMask is not None: + self.regridObj.setMask(srcGridMask) + + # min resolution, required in order to set the tolerance (tolpos) + self.delta = float('inf') + for i in range(len(dstGrid)): + coordMin = dstGrid[i].min() + coordMax = dstGrid[i].max() + n = max(dstGrid[i].shape) + self.delta = min(self.delta, (coordMax - coordMin) / float(n)) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args arguments to be passed to gsRegrid, e.g. + nitermax, tolpos, ... + """ + nitermax = args.get('nitermax', 20) + # make tolpos relative to the min cell size + tolpos = args.get('tolpos', 0.01) * self.delta + self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) + + def apply(self, srcData, dstData, missingValue=None, **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param missingValue value that should be set for points falling outside + the src domain, pass None if these should not be + touched. + """ + + self.regridObj.apply(srcData, dstData, missingValue) + + def getSrcGrid(self): + """ + Get the grid of the src data (maybe larger than the + dst grid passed to the constructor due to column/row + padding) + @return grid + """ + return self.regridObj.getSrcGrid() + + def getDstGrid(self): + """ + Get the grid of the dst data + @return grid + """ + return self.regridObj.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'numDstPoints' and 'numValid' + @param rootPe not used + """ + for entry in 'numDstPoints', 'numValid': + if entry in diag: + meth = 'get' + entry[0].upper() + entry[1:] + diag[entry] = eval('self.regridObj.' + meth + '()') + diag['regridTool'] = 'libcf' + diag['regridMethod'] = self.regridMethodStr + diag['handleCut'] = self.handleCut + diag['mkCyclic'] = self.mkCyclic + diag['verbose'] = self.verbose diff --git a/regrid2/Lib/mytest.py b/regrid2/Lib/mytest.py new file mode 100644 index 00000000..e91d1361 --- /dev/null +++ b/regrid2/Lib/mytest.py @@ -0,0 +1,2 @@ +import ESMF # noqa +from .mvESMFRegrid import ESMFRegrid # noqa diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py new file mode 100644 index 00000000..fb79a9e2 --- /dev/null +++ b/regrid2/Lib/pressure.py @@ -0,0 +1,490 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by +import cdms2 +import numpy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import copy + + +class PressureRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along + # the pressure dimension only. + # + # PROCEDURE: Step One: + # Make an instance of class PressureRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, axisIn, axisOut): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, levIn, levOut): + # + # PROCEDURE: + # + # The user must assemble two pieces of information: + # + # axisIn - the input level axis + # + # axisOut - the output level axis + # + # USAGE: + # + # To make an instance preparing for a regrid along the level dimension pnly, type + # + # r = PressureRegridder(levIn, levOut) + # + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.axisIn = axisIn + self.axisOut = axisOut + self.nlevi = len(axisIn) + self.nlevo = len(axisOut) + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the pressure regridder function. + ar is the input array, a variable, masked array, or numpy array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = ar.getAxisList() + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # Set missing value + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 3: + order = "zyx" + elif rank == 4: + order = "tzyx" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to positionIn + positionIn = [None] * 4 + for i in range(len(order)): + if order[i] == 'x': + positionIn[0] = i + elif order[i] == 'y': + positionIn[1] = i + elif order[i] == 'z': + positionIn[2] = i + if inputIsVariable: + axislist[i] = self.axisOut + else: + positionIn[3] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + if inputIsVariable == 1: + result = cdms2.createVariable(outar, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, + logYes='yes', positionIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, + # dataout along the level dimension only. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using + # the value passed in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence longitude, + # latitude, level and time. Longitude, latitude and level are + # required. If time is missing submit None in its slot in the + # tuple. Notice that the length of the tuple is always four. + # + # Explicitly, in terms of the shape of dataIn as returned by Python's shape function + # + # positionIn[0] contains the position of longitude in dataIn + # positionIn[1] contains the position of latitude in dataIn + # positionIn[2] contains the position of level in dataIn or None + # positionIn[3] contains the position of time in dataIn or None + # + # As examples: + # If the C order shape of 4D data is + # (number of longitudes, number of times, number of levels, + # number of latitudes) + # submit + # (0, 3, 2, 1) + # + # If the C order shape of 3D data is + # (number of longitudes, number of times, number oflatitudes) + # submit + # (0, 2, 1, None) + # + # Send in None if the shape is a subset of (time, level, + # latitude, longitude) which is evaluated as follows: + # 3D -- code assumes (2,1,0,None) + # 4D -- code assumes (3,2,1,0) + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last + # resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # ----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + # --- evaluate positionIn ---- + + # --- make standard positionIn as a check---- + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + for n in range(numberDim, 4): # fill end of list with Nones + positionList.append(None) + + positionCheck = tuple(positionList) + + standardPosition = 0 # transpose required + + if positionIn is None: # construct the default positionIn tuple + positionIn = positionCheck + standardPosition = 1 # no need for a transpose with this data + else: + if positionIn == positionCheck: # compare to the standard + standardPosition = 1 # no need for a transpose with this data + + if len(positionIn) != 4: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' + sendmsg(msg) + raise TypeError + + # transpose data to the standard order (t,z,y,x) + if standardPosition == 0: + + newOrder, inverseOrder = checkorder(positionIn) + + # transpose data to standard order (t,z,y,x) + dataIn = numpy.transpose(dataIn, newOrder) + dataIn = numpy.array( + dataIn.astype( + numpy.float32), + numpy.float32) # make contiguous + + # set dimension sizes and check for consistency + + if positionIn[0] is not None: + self.nlon = (dataShape[positionIn[0]]) + else: + self.nlon = 0 + if positionIn[1] is not None: + self.nlat = (dataShape[positionIn[1]]) + else: + self.nlat = 0 + if positionIn[2] is not None: + if self.nlevi != (dataShape[positionIn[2]]): + msg = 'Level size is inconsistent with input data' + sendmsg(msg) + raise ValueError + if positionIn[3] is not None: + self.ntime = (dataShape[positionIn[3]]) + else: + self.ntime = 0 + + # allocate memory for dataOut -- the array with new number of levels + + outList = list(dataIn.shape) + + for i in range(len(outList)): + if outList[i] == self.nlevi: + outList[i] = self.nlevo + break + + dataOut = numpy.zeros( + tuple(outList), + numpy.float32) # memory for aout + + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.axisIn[:].astype(numpy.float64) + levOut = self.axisOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlat, + self.nlon, + self.ntime, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + dataIn, + dataOut) + + # if no missing do not pass None + if missingMatch == 'none': + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + if standardPosition == 0: + # transpose data to original order + dataOut = numpy.transpose(dataOut, inverseOrder) + dataOut = numpy.array( + dataOut.astype( + numpy.float32), + numpy.float32) # make contiguous + + if missingValueOut is not None: # set the missing value in data to missingValueOut + + if missingMatch == 'greater': + if missingValueIn > 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.greater( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'equal': + missing = missingValueIn + dataOut = numpy.where( + numpy.equal( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'less': + if missingValueIn < 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.less( + dataOut, + missing), + missingValueOut, + dataOut) + + return dataOut + + +def checkorder(positionIn): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the tuples for transposing the data to standard dimension order and the + # inverse for transposing it back to the original dimension order + # + # usage: newOrder, inverseOrder = checkorder(positionIn) + # + # passed: positionIn -- array with location of longitude, latitude. level and time respectively + # in the sense of the python shape of the data + # + # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) + # inverseOrder -- tuple to transpose data to back to the original order + # + #----------------------------------------------------------------------------------------------""" + + # remove the None values from positionIn and reverse the order + + reducedPosition = [] + for item in positionIn: + if item is not None: + reducedPosition.append(item) + reducedPosition.reverse() + + # make the newOrder tuple + + newOrder = tuple(reducedPosition) + + # ----- Determine the inverse to this new order for use in mathtogeo ----- + + xform = [] + for i in range(len(newOrder)): + xform.append([newOrder[i], i]) + xform.sort() + + inverse_shapelist = [] + for item in xform: + inverse_shapelist.append(item[1]) + inverseOrder = tuple(inverse_shapelist) + + return newOrder, inverseOrder + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py new file mode 100644 index 00000000..5a052700 --- /dev/null +++ b/regrid2/Lib/scrip.py @@ -0,0 +1,447 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +#from . import _scrip +import regrid2._scrip as _scrip +from .error import RegridError +import numpy +from functools import reduce + +"""Regrid support for nonrectangular grids, based on the SCRIP package.""" + + +class ScripRegridder: + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + self.outputGrid = outputGrid + self.remapMatrix = remapMatrix + self.sourceAddress = sourceAddress + self.destAddress = destAddress + self.inputGrid = inputGrid + self.sourceFrac = sourceFrac + self.destFrac = destFrac + + def __call__(self, input): + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + # this expects contiguous arrays + if input.iscontiguous() is False: + input = input.ascontiguous() + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + + # Regrid + output = self.regrid(input) + + # Reshape output and restore input shape + input.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + def getOutputGrid(self): + return self.outputGrid + + def getInputGrid(self): + return self.inputGrid + + def getSourceFraction(self): + return self.sourceFrac + + def getDestinationFraction(self): + return self.destFrac + + +class ConservativeRegridder(ScripRegridder): + """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' + is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length + as the output grid size, with values: + 1.0 for normalize="fracarea", + grid_frac for normalize="destarea", or + grid_frac*grid_area for normalize="none". + sourceArea is the area of the source grid cells + destArea is the area of the destination grid cells + """ + + def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, + sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): + if normalize not in ["fracarea", "destarea", "none"]: + raise RegridError("Invalid normalization option: %s" % normalize) + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + self.normalize = normalize + self.normal = None + self.sourceArea = sourceArea + self.destArea = destArea + + def getSourceArea(self): + return self.sourceArea + + def getDestinationArea(self): + return self.destArea + + def regrid(self, input): + if self.normal is None: + # print "On input, num_links = %d"%(len(self.sourceAddress)) + # print "On input, nextra = %d"%(input.shape[0]) + # print "On input, ninput = %d"%(input.shape[1]) + # print "On input, noutput = %d"%(self.outputGrid.size()) + # print "On input, shape(input) = %s"%`input.shape` + # print "On input, shape(output) = %s"%`self.outputGrid.shape` + # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` + # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` + # print "On input, shape(dst_address) = + # %s"%`self.destAddress.shape` + result = _scrip.conserv_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + else: + result = _scrip.conserv_regrid_normal( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + self.normal) + return result + + +class BilinearRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.bilinear_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +class BicubicRegridder(ScripRegridder): + """Bicubic regrid.""" + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def __call__(self, input, gradLat, gradLon, gradLatlon): + """gradLat = df/di + gradLon = df/dj + gradLatlon = d(df)/(di)(dj) + """ + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + if (gradLat.shape != input.shape or + gradLon.shape != input.shape or + gradLatlon.shape != input.shape): + raise RegridError( + "All input arrays must have shape %s" % + repr( + input.shape)) + + if (not isinstance(gradLat, type(input)) or + not isinstance(gradLon, type(input)) or + not isinstance(gradLatlon, type(input))): + raise RegridError( + "All input arrays must have type %s" % + repr( + type(input))) + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + gradLat = gradLat.subSlice() + gradLon = gradLon.subSlice() + gradLatlon = gradLatlon.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + gradLat = gradLat.filled() + gradLon = gradLon.filled() + gradLatlon = gradLatlon.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + gradLat.shape = newshape + gradLon.shape = newshape + gradLatlon.shape = newshape + + # Regrid + output = _scrip.bicubic_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + gradLat, + gradLon, + gradLatlon) + + # Reshape output and restore input shape + input.shape = oldshape + gradLat.shape = oldshape + gradLon.shape = oldshape + gradLatlon.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + +class DistwgtRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.distwgt_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +def readRegridder(fileobj, mapMethod=None, checkGrid=1): + """Read a regridder from an open fileobj. + mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method + defined in the file. + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, + and 'repaired' if necessary. + """ + + if isinstance(fileobj, str): + fileobj = cdms2.open(fileobj) + elif not isinstance(fileobj, cdms2.dataset.CdmsFile): + raise RegridError( + "fileobj arguments must be a cdms2 file or a string pointing to a file") + + if mapMethod is None: + mapString = fileobj.map_method.strip().lower() + if mapString[0:12] == "conservative": + mapMethod = "conservative" + elif mapString[0:8] == "bilinear": + mapMethod = "bilinear" + elif mapString[0:7] == "bicubic": + mapMethod = "bicubic" + elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": + mapMethod = "distwgt" + else: + raise RegridError("Unrecognized map method: %s" % mapString) + + convention = 'SCRIP' + if list(fileobj.variables.keys()).count('S'): + convention = 'NCAR' + if convention == 'SCRIP': + remapMatrix = fileobj('remap_matrix').filled() + srcAddress = fileobj('src_address').filled() + dstAddress = fileobj('dst_address').filled() + srcfrac = fileobj('src_grid_frac') + dstfrac = fileobj('dst_grid_frac') + else: + remapMatrix = fileobj('S').filled() + srcAddress = fileobj('col').filled() + dstAddress = fileobj('row').filled() + srcfrac = fileobj('frac_a') + dstfrac = fileobj('frac_b') + ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) + outgrid = fileobj.readScripGrid( + whichGrid="destination", + checkGrid=checkGrid) + + if mapMethod == "conservative": + if convention == 'SCRIP': + srcarea = fileobj('src_grid_area') + dstarea = fileobj('dst_grid_area') + else: # NCAR stuff + if "S2" in list(fileobj.variables.keys()): + remapMatrix = fileobj("S2") + sh = list(remapMatrix.shape) + if len(sh) == 2 and sh[-1] == 2: + sh[-1] = 1 + S = fileobj("S").filled() + S.shape = sh + remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) + srcarea = fileobj('area_a') + dstarea = fileobj('area_b') + regridder = ConservativeRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac, + sourceArea=srcarea, + destArea=dstarea) + elif mapMethod == "bilinear": + regridder = BilinearRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "bicubic": + regridder = BicubicRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "distwgt": + regridder = DistwgtRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + else: + raise RegridError("Unrecognized map method: %s" % mapMethod) + + return regridder From 463c72147eb3a0f68c0b0b05798703f2fc9dced7 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 13:24:07 -0700 Subject: [PATCH 094/239] add mock modules --- docs/source/conf.py | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 20534c0a..bc49944e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,31 +11,6 @@ # # All configuration values have a default; values that are commented out # serve to show the default. -from future.standard_library import install_aliases -install_aliases() -import sys,os -sys.path.append(os.path.abspath('..')) -sys.path.append(os.path.abspath('../..')) -print sys.path -import mock -os.environ['READTHEDOCS']="True" -#MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] -MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif'] - -def side_effect(*args, **kwargs): - return mock.DEFAULT - -for mod_name in MOCK_MODULES: - m = mock.Mock() - m.return_value=3 - m.side_effect = side_effect - print mod_name - sys.modules[mod_name] = m - - -open('../../Lib/git.py','a').close() - - from future.standard_library import install_aliases install_aliases() import sys,os @@ -44,7 +19,7 @@ def side_effect(*args, **kwargs): import mock os.environ['READTHEDOCS']="True" #MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] -MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip'] +MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip','distarray'] def side_effect(*args, **kwargs): return mock.DEFAULT From 62e160f16f209e257ff589886135a86db48d1af9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 13:28:33 -0700 Subject: [PATCH 095/239] add git.py --- docs/source/conf.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index bc49944e..ebc46937 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -39,8 +39,12 @@ def side_effect(*args, **kwargs): print glob.glob("../../regrid2/*") print os.getcwd() -open("../../Lib/git.py", 'wb').close() -open("../../regrid2/Libregrid/git.py", 'wb').close() +f=open("../../Lib/git.py", 'wb') +f.write("closest_tag = '3.0'") +f.close() +f=open("../../regrid2/Libregrid/git.py", 'wb') +f.write("closest_tag = '3.0'") +f.close() import sys From 1b12f721dd77810b14fdc9c7b82a1e3da72a1bb1 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 13:50:00 -0700 Subject: [PATCH 096/239] try with new mock list --- docs/source/conf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index ebc46937..313b787a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,10 @@ import mock os.environ['READTHEDOCS']="True" #MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] -MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip','distarray'] +MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip'] +#,'distarray','collections'] +#'urllib.parse','urllib.request','urllib.error','ESMF'] + def side_effect(*args, **kwargs): return mock.DEFAULT From 932d66fdf0861efd2176facad41a3bcbf7477c32 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:00:07 -0700 Subject: [PATCH 097/239] force git.py --- Lib/__init__.py | 2 + Lib/git.py | 1 + docs/source/conf.py | 9 +- regrid2/Lib/PET0.ESMF_LogFile | 1 - regrid2/Lib/__init__.py | 36 - regrid2/Lib/crossSection.py | 1092 --------------------------- regrid2/Lib/crossSection.py.orig | 1095 --------------------------- regrid2/Lib/error.py | 3 - regrid2/Lib/esmf.py | 842 --------------------- regrid2/Lib/gsRegrid.py | 1179 ------------------------------ regrid2/Lib/gs_horizontal.py | 214 ------ regrid2/Lib/horizontal.py | 422 ----------- regrid2/Lib/mvESMFRegrid.py | 483 ------------ regrid2/Lib/mvGenericRegrid.py | 313 -------- regrid2/Lib/mvLibCFRegrid.py | 101 --- regrid2/Lib/mytest.py | 2 - regrid2/Lib/pressure.py | 490 ------------- regrid2/Lib/scrip.py | 447 ----------- 18 files changed, 5 insertions(+), 6727 deletions(-) create mode 100644 Lib/git.py delete mode 100644 regrid2/Lib/PET0.ESMF_LogFile delete mode 100644 regrid2/Lib/__init__.py delete mode 100644 regrid2/Lib/crossSection.py delete mode 100644 regrid2/Lib/crossSection.py.orig delete mode 100644 regrid2/Lib/error.py delete mode 100644 regrid2/Lib/esmf.py delete mode 100644 regrid2/Lib/gsRegrid.py delete mode 100644 regrid2/Lib/gs_horizontal.py delete mode 100644 regrid2/Lib/horizontal.py delete mode 100644 regrid2/Lib/mvESMFRegrid.py delete mode 100644 regrid2/Lib/mvGenericRegrid.py delete mode 100644 regrid2/Lib/mvLibCFRegrid.py delete mode 100644 regrid2/Lib/mytest.py delete mode 100644 regrid2/Lib/pressure.py delete mode 100644 regrid2/Lib/scrip.py diff --git a/Lib/__init__.py b/Lib/__init__.py index 23c2a595..d27d186a 100644 --- a/Lib/__init__.py +++ b/Lib/__init__.py @@ -4,7 +4,9 @@ import cdat_info cdat_info.pingPCMDIdb("cdat", "cdms2") # noqa + from . import git # noqa + from . import myproxy_logon # noqa __all__ = ["cdmsobj", "axis", "coord", "grid", "hgrid", "avariable", diff --git a/Lib/git.py b/Lib/git.py new file mode 100644 index 00000000..30023a51 --- /dev/null +++ b/Lib/git.py @@ -0,0 +1 @@ +closest_tag = '3.0' \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 313b787a..4183add0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,7 +13,8 @@ # serve to show the default. from future.standard_library import install_aliases install_aliases() -import sys,os +import sys +import os sys.path.append(os.path.abspath('../../regrid2')) sys.path.append(os.path.abspath('../..')) import mock @@ -42,12 +43,6 @@ def side_effect(*args, **kwargs): print glob.glob("../../regrid2/*") print os.getcwd() -f=open("../../Lib/git.py", 'wb') -f.write("closest_tag = '3.0'") -f.close() -f=open("../../regrid2/Libregrid/git.py", 'wb') -f.write("closest_tag = '3.0'") -f.close() import sys diff --git a/regrid2/Lib/PET0.ESMF_LogFile b/regrid2/Lib/PET0.ESMF_LogFile deleted file mode 100644 index 3494c8e2..00000000 --- a/regrid2/Lib/PET0.ESMF_LogFile +++ /dev/null @@ -1 +0,0 @@ -20170308 152041.534 INFO PET0 Running with ESMF Version 7.0.0 diff --git a/regrid2/Lib/__init__.py b/regrid2/Lib/__init__.py deleted file mode 100644 index 36b7f9e2..00000000 --- a/regrid2/Lib/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Interface to regridding facilities -""" - -__all__ = ["horizontal", "pressure", "crossSection", "scrip", - "error", "mvGenericRegrid", ] - -from .error import RegridError # noqa -from .horizontal import Horizontal, Regridder # noqa -from .pressure import PressureRegridder # noqa -from .crossSection import CrossSectionRegridder # noqa -from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa -from .scrip import DistwgtRegridder, readRegridder # noqa -from regrid2 import gsRegrid # noqa -from .mvGenericRegrid import GenericRegrid # noqa -from .mvLibCFRegrid import LibCFRegrid # noqa -try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - from .mvESMFRegrid import ESMFRegrid # noqa -except BaseException: - pass - -from . import git # noqa - -ESMF_HAS_BEEN_INITIALIZED = False -if not ESMF_HAS_BEEN_INITIALIZED: - try: - import ESMF - ESMF.deprecated.__globals__[ - 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning - ESMF.Manager(debug=False) - # this turns off the PET file logs - ESMF_HAS_BEEN_INITIALIZED = True - except BaseException: - pass diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py deleted file mode 100644 index cf23b45d..00000000 --- a/regrid2/Lib/crossSection.py +++ /dev/null @@ -1,1092 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError - - -class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, - latTypeOut=None, latSizeOut=None): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, - # latTypeOut = None, latSizeOut = None): - # - # PROCEDURE: - # - # The user must assemble at least the following four pieces of information: - # - # latIn - the axis specifying the latitude grid for the input data - # - # latOut - the axis specifying the latitude grid for the output data - # - # levIn - the axis specifying the pressure grid for the input data - # - # levOut - the axis specifying the pressure grid for the output data - # - # - # Additional information is required if a latitude grid is not global. It may be generic. - # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice - # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the - # computation requires the size of the global grid from which the subset was choosen. Consequently, - # the user must assemble: - # - # latTypeIn -- for input latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region - # - # latTypeOut -- for output latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region - # - # USAGE: - # - # To make an instance preparing for a global to global regrid, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) - # - # To make an instance preparing for a global to a regional grid which, for example, is a subset of - # a global gaussian grid of size 64, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) - # - # where the latOut axis must have been selected from the global 64 length gaussian grid - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.latOut = latOut - self.levIn = levIn - self.levOut = levOut - self.nlevi = len(levIn) - self.nlevo = len(levOut) - - latIn, self.nlati = checkdimension(latIn, 'input latitude') - latOut, self.nlato = checkdimension(latOut, 'output latitude') - - # --- check for a single grid point in the latitude-level plane - - if self.nlevo == 1 and self.nlato != 1: - sendmsg( - 'Error in output grid - a single level value requires a single latitude value') - raise ValueError - if self.nlevo != 1 and self.nlato == 1: - sendmsg( - 'Error in output grid - a single latitude value requires a single longitude value') - raise ValueError - if self.nlevo == 1 and self.nlato == 1: - calculateMean = 1 - msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' - sendmsg(msg) - else: - calculateMean = 0 - - # --- get the latitude coordinate grid boundaries for the input grid - - if latTypeIn is None: # global latIn - lat_wts_bndsIn = get_latitude_wts_bnds(latIn) - else: - lat_wts_bndsIn = get_region_latitude_wts_bnds( - latIn, latTypeIn, latSizeIn) - - lat_bndsIn = lat_wts_bndsIn[1] - bnin, bsin = latitude_bounds(lat_bndsIn) - - if calculateMean == 0: # meaningful grid - - # --- get the latitude coordinate grid boundaries for the output grid - - if latTypeOut is None: # global latOut - lat_wts_bndsOut = get_latitude_wts_bnds(latOut) - else: - lat_wts_bndsOut = get_region_latitude_wts_bnds( - latOut, latTypeOut, latSizeOut) - - lat_bndsOut = lat_wts_bndsOut[1] - bnout, bsout = latitude_bounds(lat_bndsOut) - - else: - bnout = numpy.array([90.0], numpy.float32) - bsout = numpy.array([-90.0], numpy.float32) - - # --- call maplength to get the rest of the self data needed by rgrdlength - - t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) - - self.latdx, self.latpt, self.wtlat = t - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the regridder function. - ar is the input array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = "zy" - else: - order = "tzy" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = str.lower(order) - - # Map order to positionIn - positionIn = [None] * 3 - for i in range(len(order)): - if order[i] == 'y': - positionIn[0] = i - if inputIsVariable: - axislist[i] = self.latOut - elif order[i] == 'z': - positionIn[1] = i - if inputIsVariable: - axislist[i] = self.levOut - else: - positionIn[2] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - # Mask fill_value and return results - if inputIsVariable == 1: - result = numpy.ma.masked_values(outar, missing) - result = cdms2.createVariable(result, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - result = numpy.ma.masked_values(result, missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', - positionIn=None, maskIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in - # the latitude-level plane. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, - # missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed - # in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence latitude, - # level and time. Latitude and level are required. If time is missing submit None in its - # slot in the tuple. Notice that the length of the tuple is - # always three. - # - # Explicitly, in terms of the shape of dataIn as returned by python's shape function - # - # positionIn[0] contains the position of latitude in dataIn - # positionIn[1] contains the position of level in dataIn or None - # positionIn[2] contains the position of time in dataIn or None - # - # As examples: - # If the c order shape of 3D data is - # (number of times, number of levels, number of latitudes) - # submit - # (2, 1, 0). - # - # If the c order shape of 2D data is - # (number of times, number of latitudes) - # submit - # (1, None, 0). - # - # Send in None if the shape is a subset of (time, level, latitude) which is evaluated - # as follows: - # 2D -- code assumes (1,0,None) - # 3D -- code assumes (2,1,0) - # - # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This - # mask only works on the latitude grid. It is not possible to mask out a region in the level - # plane. The 0.0 value removes the data from correponding grid point. The user can supply the - # following choices: - # - # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing - # data in the input data array, dataIn - # - # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, - # dataIn. This user supplied mask might be used to mask a latitude region. It is not - # required to account for missing data in the input data. The code uses missingValueIn - # and missingMatch to supply the 0.0s for grid points with missing data in the input - # data array, dataIn. - # - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # WARNING: This code does not regrid cross sections which have a single dummy longitude value! - # - # - #-----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # try to identify a single dummy longitude - - dataShape = dataIn.shape - - if len(dataShape) > 3: - msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is not None: - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # set missing value to be used in dataOut - - if missingValueOut is None: - if missingValueIn is not None: - # default - omit = missingValueIn - else: - # default - omit = 1.0e20 - else: - # user choice - omit = missingValueOut - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - # produce the input for rgdlength not generated by maplength - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is None: # construct the default positionIn tuple - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - if numberDim == 2: # fill end of list with a None - positionList.append(None) - - positionIn = tuple(positionList) - - if len(positionIn) != 3: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' - sendmsg(msg) - raise TypeError - - # set ilon, ilat in Fortran order except that the first index is 0 - - # not 1 - ilat = numberDim - 1 - positionIn[0] - - itim1 = itim2 = -1 - ntim1 = ntim2 = 0 - - if numberDim == 2: # lat and level field - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - - if numberDim == 3: # lon_lat field + level + time - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - itim2 = numberDim - 1 - positionIn[2] - ntim2 = dataShape[positionIn[2]] - - # check for consistency between the grid axiss and the dataIn shape - - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # allocate memory for aout -- the array with original number of levels - # but the new number of latitudes - - aoutList = list(dataIn.shape) - aoutList[positionIn[0]] = self.nlato - # memory for aout - aout = numpy.zeros(tuple(aoutList), numpy.float32) - - # generate the mask - - amskin = sectionmask( - dataIn, - positionIn, - maskIn, - missingValueIn, - missingMatch) - - # ------------- call rgdlength to regrid latitude --------------- - - _regrid.rgdlength( - ilat, - itim1, - itim2, - ntim1, - ntim2, - self.nlati, - self.nlato, - omit, - self.latdx, - self.latpt, - self.wtlat, - amskin, - dataIn, - aout) - - # ------------- call rgdpressure to regrid pressure ------------- - - # allocate memory for ap -- the array with new number of levels and the - # new number of latitudes - - apList = list(dataIn.shape) - apList[positionIn[0]] = self.nlato - apList[positionIn[1]] = self.nlevo - # memory for ap - ap = numpy.zeros(tuple(apList), numpy.float32) - - nlon = 0 - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.levIn[:].astype(numpy.float64) - levOut = self.levOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlato, - nlon, - ntim2, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - aout, - ap) - - if missingMatch == 'none': # if no missing do not pass None - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - return ap - - -def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" - - data = x[:] - try: - xsize = len(x) - except TypeError: - sendmsg('Hgrid instance error -- instance requires a ' + name) - raise TypeError - - if data.dtype.char != 'f': - x[:] = x[:].astype(numpy.float32) - - # ----- check for consistency ----- - - if x[0] > x[xsize - 1]: - for n in range(1, xsize): - if x[n] > x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - else: - for n in range(1, xsize): - if x[n] < x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - - return x, xsize - - -def generic_wts_bnds(lat): - try: - bnds = lat.getBounds() - if bnds is None: # No bounds defined - newLat = lat.clone() - newLat.setBounds(None) - bnds = lat.getBounds() - except BaseException: # just an array.... - newLat = cdms2.createAxis(lat) - newLat.setBounds(None) - bnds = newLat.getBounds() - outBnds = bnds[:, 0].tolist() - outBnds.append(bnds[-1][-1]) - outBnds = numpy.array(outBnds) - wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] - wts = numpy.array(wts) / numpy.sum(wts) - return wts, outBnds - - -def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - small = 0.001 # use as tolerance in checking values - - nlat = len(checklatpass) - - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if checklatpass[0] < checklatpass[nlat - - 1]: # need a copy? - checklat = numpy.array(checklatpass, numpy.float64) - checklat = checklat[::-1] - reverse_latitude = 'yes' - else: - checklat = checklatpass - - # ------ check the pass for evenly spaced latitudes ------- - - firstdelta = abs(checklat[0] - checklat[1]) - maxdiff = 0.0 - for i in range(1, nlat - 1): - diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) - if diff > maxdiff: - maxdiff = diff - - if maxdiff < small: - # if abs(90. - checklat[0]) > small or abs(-90. - - # checklat[nlat - 1]) > small: - # grid_type = 'even' # evenly spaced without poles - # wts, bnds = generic_wts_bnds(checklat) - # if reverse_latitude == 'yes': - # wts = wts[::-1] - # bnds = bnds[::-1] - # return (wts, bnds) - # else: - grid_type = 'uniform' # evenly spaced with poles - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for gaussian latitudes ------- - - grid_type = 'gaussian' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for equalarea latitudes ------- - - grid_type = 'equalarea' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ must be generic latitude ------- - wts, bnds = generic_wts_bnds(checklatpass) - return (wts, bnds) - - -def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" - - latbnds = lat_bnds.astype(numpy.float32) - - if latbnds[0] > latbnds[len(latbnds) - 1]: - bn = latbnds[:-1] - bs = latbnds[1:] - else: - bn = latbnds[1:] - bs = latbnds[:-1] - - return (bn, bs) - - -def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - - latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] - - if latType not in latTypeList: - sendmsg( - "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", - latType) - raise ValueError - return - - if latSize is None: - sendmsg('Error in latSize -- it must be a number') - raise ValueError - return - - nlat = len(latRegionpass) - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if latRegionpass[0] < latRegionpass[nlat - - 1]: # need a copy? - latRegion = numpy.array(latRegionpass, numpy.float64) - latRegion = latRegion[::-1] - reverse_latitude = 'yes' - else: - latRegion = latRegionpass - - small = 0.001 # use as tolerance in checking values - - # ------ check the pass for gaussian latitudes ------- - - if latType != 'generic': - # n to s global pts, wts and bnds - pts_wts_bnds = _regrid.gridattr(latSize, latType) - latvals = pts_wts_bnds[0] - - imatch = -1 - i = 0 - while(imatch == -1): - if abs(latvals[i] - latRegion[0]) < small: # first index found - startIndex = i - imatch = 0 - i = i + 1 - imatch = -1 - while(imatch == -1): - if abs(latvals[i] - latRegion[nlat - 1] - ) < small: # last index found - lastIndex = i - imatch = 0 - i = i + 1 - - wts = pts_wts_bnds[1][startIndex:lastIndex + 1] - bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] - - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - - return (wts, bnds) - -# else: # must be generic latitude ------- -# -# wts, bnds = generic_wts_bnds(latIn) -# if reverse_latitude == 'yes': -# wts = wts[::-1] -# bnds = bnds[::-1] -# return (wts, bnds) - - -def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" - # Logic outline - # START NO USER MASK SECTION ? - # - # START USER MASK SECTION ? - # USER SUPPLIED MASK IS 2D ? - # USER SUPPLIED MASK IS FULL SIZE ? - - # ---- check the missingMatch pass -------- - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' - sendmsg(msg) - raise ValueError - - # ----- Check for missing data in dataIn, set missingFlag and miss, the va - - # missingFlag = 0 if there is no missing data - # missingFlag = 1 if there is missing data found using greater than missingValueIn - # missingFlag = 1 if there is missing data found using the default 1.0e20 - # missingFlag = 2 if there is missing data found using equal to missingValueIn - # missingFlag = 3 if there is missing data found using less than - # missingValueIn - - missingFlag = 0 - - # use value from the file - if missingValueIn is not None: - - if missingMatch == 'greater': - if missingValueIn > 0: - miss = 0.99 * missingValueIn - else: - miss = 1.01 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.greater( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 1 - - elif missingMatch == 'equal': - miss = missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.equal( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 2 - - elif missingMatch == 'less': - if missingValueIn > 0: - miss = 1.01 * missingValueIn - else: - miss = 0.99 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.less( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 3 - - # ----- get the shape of dataIn and set the number of dimensions in the da - - dataShape = dataIn.shape - # set size and check against positionIn - numberDataDim = len(dataShape) - - # remove the None fillers - reducedPositionIn = [] - for i in range(len(positionIn)): - if positionIn[i] is not None: - reducedPositionIn.append(positionIn[i]) - - if numberDataDim != len(reducedPositionIn): - msg = 'positionIn does not describe the number of dimensions in the data' - sendmsg(msg) - raise ValueError - - # ----- Determine the order of latitude and level in the data ------- - - # sequence is standard (lat,lon) - if positionIn[0] > positionIn[1]: - levlatFlag = 1 - else: - levlatFlag = 0 - - # ------------------------------------------------------------------------------------------------------ - # ----------------------------------------- Generate the mask ----------- - # ------------------------------------------------------------------------------------------------------ - - # ------------------------------------------------------------------------------------------------------ - # ---------- START NO USER MASK SECTION - - if maskIn is None: # ---- need to generate the mask from scratch ---- - - # allocate memory - amskin = numpy.ones(dataShape, numpy.float32) - - # ---------- START USER MASK SECTION - - else: # ---- use the users supplied mask ---- - - numberMaskDim = len(maskIn.shape) - - if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D - - # mask shape is (lat,lon) - if levlatFlag == 1: - checkmaskShape = ( - dataShape[positionIn[1]], dataShape[positionIn[0]]) - # mask shape is (lon,lat) - else: - checkmaskShape = ( - dataShape[positionIn[0]], dataShape[positionIn[1]]) - - if maskIn.shape != checkmaskShape: # check the mask shape - msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' - sendmsg(msg) - raise IndexError - - # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED - - if numberDataDim > 2: - # replicate the mask to size of dataIn - amskin = numpy.resize(maskIn, dataShape) - - else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE - - amskin = maskIn - - if numberMaskDim != numberDataDim: - msg = 'Error -- user supplied mask must be 2D or the size of the data' - sendmsg(msg) - raise IndexError - - if amskin.shape != dataIn.shape: - msg = 'Error -- full size mask supplied must have the same shape as the input data' - sendmsg(msg) - raise IndexError - - # there is missing data in dataIn to add to amskin - if missingFlag != 0: - if missingFlag == 1: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - elif missingFlag == 2: - amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) - elif missingFlag == 3: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - - amskin = amskin.astype(numpy.float32) - - return amskin - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None - - -def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" - - nlev = len(levvals) - - nlat = len(latvals) - theta = (math.pi / 180.) * latvals - - xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory - - t0 = 60. - p0 = 1000. - - for j in range(nlat): - for i in range(nlev): - x = math.cos(theta[j])**2 - y = t0 * ((levvals[i] / p0)**.3) - xsection[i, j] = x * y - 30. - - return xsection - - -def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" - - if data1.shape != data2.shape: - print('Error in shape in rmserror') - print(('data1 shape = ', data1.shape)) - print(('data2 shape = ', data2.shape)) - raise ValueError - - d1 = numpy.ravel(data1) - d2 = numpy.ravel(data2) - - sq = (d1 - d2) * (d1 - d2) - error = numpy.sum(sq) / len(d1) - rmserror = numpy.sqrt(error) - - return rmserror - - -if __name__ == '__main__': - import math - - latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) - levList = [10., 40., 75., 100., 150., 250., 350., 500., - 650., 850., 1000.] # pick some levels - levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - latOut = cdms2.createGaussianAxis(64) - levList = [10., 30., 50., 70., 100., 200., 300., 400., - 500., 700., 850., 1000.] # pick some levels - levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - - xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) - - # make some artificial data - dataIn = section(latIn[:], levIn[:]) - var = cdms2.createVariable( - dataIn, axes=( - levIn, latIn), attributes={ - 'units': 'N/A'}, id='test') - - dataOut = xregridf(dataIn) - - # make the exact answer - dataCheck = section(latOut[:], levOut[:]) - # find the rms error - error = rmserror(dataOut, dataCheck) - - print('expected cross section test case rms error = 0.18581882') - # print 'expected cross section test case rms error = 0.23062' - print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig deleted file mode 100644 index c06eae4a..00000000 --- a/regrid2/Lib/crossSection.py.orig +++ /dev/null @@ -1,1095 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -import numpy -import copy -from . import _regrid -from .error import RegridError - - -class CrossSectionRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the - # latitude-level plane for all times - # - # PROCEDURE: Step One: - # Make an instance of class CrossSectionRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, - latTypeOut=None, latSizeOut=None): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, - # latTypeOut = None, latSizeOut = None): - # - # PROCEDURE: - # - # The user must assemble at least the following four pieces of information: - # - # latIn - the axis specifying the latitude grid for the input data - # - # latOut - the axis specifying the latitude grid for the output data - # - # levIn - the axis specifying the pressure grid for the input data - # - # levOut - the axis specifying the pressure grid for the output data - # - # - # Additional information is required if a latitude grid is not global. It may be generic. - # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice - # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the - # computation requires the size of the global grid from which the subset was choosen. Consequently, - # the user must assemble: - # - # latTypeIn -- for input latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region - # - # latTypeOut -- for output latitude, one of the following: - # 'gaussian' - # 'equalarea' - # 'uniform' - # 'generic' - # - # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region - # - # USAGE: - # - # To make an instance preparing for a global to global regrid, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) - # - # To make an instance preparing for a global to a regional grid which, for example, is a subset of - # a global gaussian grid of size 64, type - # - # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) - # - # where the latOut axis must have been selected from the global 64 length gaussian grid - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.latOut = latOut - self.levIn = levIn - self.levOut = levOut - self.nlevi = len(levIn) - self.nlevo = len(levOut) - - latIn, self.nlati = checkdimension(latIn, 'input latitude') - latOut, self.nlato = checkdimension(latOut, 'output latitude') - - # --- check for a single grid point in the latitude-level plane - - if self.nlevo == 1 and self.nlato != 1: - sendmsg( - 'Error in output grid - a single level value requires a single latitude value') - raise ValueError - if self.nlevo != 1 and self.nlato == 1: - sendmsg( - 'Error in output grid - a single latitude value requires a single longitude value') - raise ValueError - if self.nlevo == 1 and self.nlato == 1: - calculateMean = 1 - msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' - sendmsg(msg) - else: - calculateMean = 0 - - # --- get the latitude coordinate grid boundaries for the input grid - - if latTypeIn is None: # global latIn - lat_wts_bndsIn = get_latitude_wts_bnds(latIn) - else: - lat_wts_bndsIn = get_region_latitude_wts_bnds( - latIn, latTypeIn, latSizeIn) - - lat_bndsIn = lat_wts_bndsIn[1] - bnin, bsin = latitude_bounds(lat_bndsIn) - - if calculateMean == 0: # meaningful grid - - # --- get the latitude coordinate grid boundaries for the output grid - - if latTypeOut is None: # global latOut - lat_wts_bndsOut = get_latitude_wts_bnds(latOut) - else: - lat_wts_bndsOut = get_region_latitude_wts_bnds( - latOut, latTypeOut, latSizeOut) - - lat_bndsOut = lat_wts_bndsOut[1] - bnout, bsout = latitude_bounds(lat_bndsOut) - - else: - bnout = numpy.array([90.0], numpy.float32) - bsout = numpy.array([-90.0], numpy.float32) - - # --- call maplength to get the rest of the self data needed by rgrdlength - - t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) - - self.latdx, self.latpt, self.wtlat = t - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the regridder function. - ar is the input array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = "zy" - else: - order = "tzy" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = str.lower(order) - - # Map order to positionIn - positionIn = [None] * 3 - for i in range(len(order)): - if order[i] == 'y': - positionIn[0] = i - if inputIsVariable: - axislist[i] = self.latOut - elif order[i] == 'z': - positionIn[1] = i - if inputIsVariable: - axislist[i] = self.levOut - else: - positionIn[2] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - # Mask fill_value and return results - print("INPUT IS VAR:", inputIsVariable) - if inputIsVariable == 1: - result = numpy.ma.masked_values(outar, missing) - result = cdms2.createVariable(result, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - result = numpy.ma.masked_values(result, missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', - positionIn=None, maskIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in - # the latitude-level plane. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, - # missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed - # in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence latitude, - # level and time. Latitude and level are required. If time is missing submit None in its - # slot in the tuple. Notice that the length of the tuple is - # always three. - # - # Explicitly, in terms of the shape of dataIn as returned by python's shape function - # - # positionIn[0] contains the position of latitude in dataIn - # positionIn[1] contains the position of level in dataIn or None - # positionIn[2] contains the position of time in dataIn or None - # - # As examples: - # If the c order shape of 3D data is - # (number of times, number of levels, number of latitudes) - # submit - # (2, 1, 0). - # - # If the c order shape of 2D data is - # (number of times, number of latitudes) - # submit - # (1, None, 0). - # - # Send in None if the shape is a subset of (time, level, latitude) which is evaluated - # as follows: - # 2D -- code assumes (1,0,None) - # 3D -- code assumes (2,1,0) - # - # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This - # mask only works on the latitude grid. It is not possible to mask out a region in the level - # plane. The 0.0 value removes the data from correponding grid point. The user can supply the - # following choices: - # - # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing - # data in the input data array, dataIn - # - # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, - # dataIn. This user supplied mask might be used to mask a latitude region. It is not - # required to account for missing data in the input data. The code uses missingValueIn - # and missingMatch to supply the 0.0s for grid points with missing data in the input - # data array, dataIn. - # - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # WARNING: This code does not regrid cross sections which have a single dummy longitude value! - # - # - #-----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # try to identify a single dummy longitude - - dataShape = dataIn.shape - - if len(dataShape) > 3: - msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is not None: - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # set missing value to be used in dataOut - - if missingValueOut is None: - if missingValueIn is not None: - # default - omit = missingValueIn - else: - # default - omit = 1.0e20 - else: - # user choice - omit = missingValueOut - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - # produce the input for rgdlength not generated by maplength - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - if positionIn is None: # construct the default positionIn tuple - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - if numberDim == 2: # fill end of list with a None - positionList.append(None) - - positionIn = tuple(positionList) - - if len(positionIn) != 3: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' - sendmsg(msg) - raise TypeError - - # set ilon, ilat in Fortran order except that the first index is 0 - - # not 1 - ilat = numberDim - 1 - positionIn[0] - - itim1 = itim2 = -1 - ntim1 = ntim2 = 0 - - if numberDim == 2: # lat and level field - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - - if numberDim == 3: # lon_lat field + level + time - itim1 = numberDim - 1 - positionIn[1] - ntim1 = dataShape[positionIn[1]] - itim2 = numberDim - 1 - positionIn[2] - ntim2 = dataShape[positionIn[2]] - - # check for consistency between the grid axiss and the dataIn shape - - if self.nlati != (dataShape[positionIn[0]]): - msg = 'Latitude vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - if self.nlevi != (dataShape[positionIn[1]]): - msg = 'Level vector is inconsistent with input data' - sendmsg(msg) - raise ValueError - - # allocate memory for aout -- the array with original number of levels - # but the new number of latitudes - - aoutList = list(dataIn.shape) - aoutList[positionIn[0]] = self.nlato - # memory for aout - aout = numpy.zeros(tuple(aoutList), numpy.float32) - - # generate the mask - - amskin = sectionmask( - dataIn, - positionIn, - maskIn, - missingValueIn, - missingMatch) - - # ------------- call rgdlength to regrid latitude --------------- - - _regrid.rgdlength( - ilat, - itim1, - itim2, - ntim1, - ntim2, - self.nlati, - self.nlato, - omit, - self.latdx, - self.latpt, - self.wtlat, - amskin, - dataIn, - aout) - - # ------------- call rgdpressure to regrid pressure ------------- - - # allocate memory for ap -- the array with new number of levels and the - # new number of latitudes - - apList = list(dataIn.shape) - apList[positionIn[0]] = self.nlato - apList[positionIn[1]] = self.nlevo - # memory for ap - ap = numpy.zeros(tuple(apList), numpy.float32) - - nlon = 0 - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.levIn[:].astype(numpy.float64) - levOut = self.levOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlato, - nlon, - ntim2, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - aout, - ap) - - if missingMatch == 'none': # if no missing do not pass None - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - return ap - - -def checkdimension(x, name): - """ #--------------------------------------------------------------------------------- - # - # purpose: dimension checks - # 1. has a len method - # 2. data type is float32 - # 3. monotonically increasing vectors - # - # passed : x - coordinate vector - # name - coordinate vector ID - # - # returned: x, xsize -- dimension vector and its size - # - #---------------------------------------------------------------------------------""" - - data = x[:] - try: - xsize = len(x) - except TypeError: - sendmsg('Hgrid instance error -- instance requires a ' + name) - raise TypeError - - if data.dtype.char != 'f': - x[:] = x[:].astype(numpy.float32) - - # ----- check for consistency ----- - - if x[0] > x[xsize - 1]: - for n in range(1, xsize): - if x[n] > x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - else: - for n in range(1, xsize): - if x[n] < x[n - 1]: - sendmsg('Hgrid instance error -- ' + name + 'not monotonic') - raise ValueError - return - - return x, xsize - - -def generic_wts_bnds(lat): - try: - bnds = lat.getBounds() - if bnds is None: # No bounds defined - newLat = lat.clone() - newLat.setBounds(None) - bnds = lat.getBounds() - except BaseException: # just an array.... - newLat = cdms2.createAxis(lat) - newLat.setBounds(None) - bnds = newLat.getBounds() - outBnds = bnds[:, 0].tolist() - outBnds.append(bnds[-1][-1]) - outBnds = numpy.array(outBnds) - wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] - wts = numpy.array(wts) / numpy.sum(wts) - return wts, outBnds - - -def get_latitude_wts_bnds(checklatpass): - """ #------------------------------------------------------------------- - # - # routine: get_latitude_wts_bnds - # - # purpose: compare the passed checklatpass with the correct geophysical - # ones calculated here. After finding a match call the function - # to get the bounds. - # - # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) - # where checklatpass is the grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - small = 0.001 # use as tolerance in checking values - - nlat = len(checklatpass) - - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if checklatpass[0] < checklatpass[nlat - - 1]: # need a copy? - checklat = numpy.array(checklatpass, numpy.float64) - checklat = checklat[::-1] - reverse_latitude = 'yes' - else: - checklat = checklatpass - - # ------ check the pass for evenly spaced latitudes ------- - - firstdelta = abs(checklat[0] - checklat[1]) - maxdiff = 0.0 - for i in range(1, nlat - 1): - diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) - if diff > maxdiff: - maxdiff = diff - - if maxdiff < small: - # if abs(90. - checklat[0]) > small or abs(-90. - - # checklat[nlat - 1]) > small: - # grid_type = 'even' # evenly spaced without poles - # wts, bnds = generic_wts_bnds(checklat) - # if reverse_latitude == 'yes': - # wts = wts[::-1] - # bnds = bnds[::-1] - # return (wts, bnds) - # else: - grid_type = 'uniform' # evenly spaced with poles - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for gaussian latitudes ------- - - grid_type = 'gaussian' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ check the pass for equalarea latitudes ------- - - grid_type = 'equalarea' - pts_wts_bnds = _regrid.gridattr(nlat, grid_type) - latvals = pts_wts_bnds[0] - laterror = max(abs(latvals - checklat)) - if laterror < small: - wts = pts_wts_bnds[1] - bnds = pts_wts_bnds[2] - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - # ------ must be generic latitude ------- - wts, bnds = generic_wts_bnds(checklat) - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - return (wts, bnds) - - -def latitude_bounds(lat_bnds): - """ #------------------------------------------------------------------- - # - # purpose: set up the shape and bounds for use by maparea - # - # usage: - # - # returned: tuple ( bn,bs ) - # - #------------------------------------------------------------------------""" - - latbnds = lat_bnds.astype(numpy.float32) - - if latbnds[0] > latbnds[len(latbnds) - 1]: - bn = latbnds[:-1] - bs = latbnds[1:] - else: - bn = latbnds[1:] - bs = latbnds[:-1] - - return (bn, bs) - - -def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): - """ #------------------------------------------------------------------- - # - # routine: get_region_latitude_wts_bnds - # - # purpose: compare the passed latitudes, latRegion, with the global - # ones calculated here and extract the wts and bounds for - # the region - # - # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) - # where latRegion is the regional grid to check - # - # return: wts, bnds - tuple with weights and bounds - # - #-------------------------------------------------------------------------""" - - latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] - - if latType not in latTypeList: - sendmsg( - "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", - latType) - raise ValueError - return - - if latSize is None: - sendmsg('Error in latSize -- it must be a number') - raise ValueError - return - - nlat = len(latRegionpass) - reverse_latitude = 'no' - - # ------ set latitude direction to n to s for comparisons ------- - - if latRegionpass[0] < latRegionpass[nlat - - 1]: # need a copy? - latRegion = numpy.array(latRegionpass, numpy.float64) - latRegion = latRegion[::-1] - reverse_latitude = 'yes' - else: - latRegion = latRegionpass - - small = 0.001 # use as tolerance in checking values - - # ------ check the pass for gaussian latitudes ------- - - if latType != 'generic': - # n to s global pts, wts and bnds - pts_wts_bnds = _regrid.gridattr(latSize, latType) - latvals = pts_wts_bnds[0] - - imatch = -1 - i = 0 - while(imatch == -1): - if abs(latvals[i] - latRegion[0]) < small: # first index found - startIndex = i - imatch = 0 - i = i + 1 - imatch = -1 - while(imatch == -1): - if abs(latvals[i] - latRegion[nlat - 1] - ) < small: # last index found - lastIndex = i - imatch = 0 - i = i + 1 - - wts = pts_wts_bnds[1][startIndex:lastIndex + 1] - bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] - - if reverse_latitude == 'yes': - wts = wts[::-1] - bnds = bnds[::-1] - - return (wts, bnds) - -# else: # must be generic latitude ------- -# -# wts, bnds = generic_wts_bnds(latIn) -# if reverse_latitude == 'yes': -# wts = wts[::-1] -# bnds = bnds[::-1] -# return (wts, bnds) - - -def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the mask for the input data for use by rgdlength - # - # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) - # - # returned: amskin - # - #----------------------------------------------------------------------------------------------""" - # Logic outline - # START NO USER MASK SECTION ? - # - # START USER MASK SECTION ? - # USER SUPPLIED MASK IS 2D ? - # USER SUPPLIED MASK IS FULL SIZE ? - - # ---- check the missingMatch pass -------- - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' - sendmsg(msg) - raise ValueError - - # ----- Check for missing data in dataIn, set missingFlag and miss, the va - - # missingFlag = 0 if there is no missing data - # missingFlag = 1 if there is missing data found using greater than missingValueIn - # missingFlag = 1 if there is missing data found using the default 1.0e20 - # missingFlag = 2 if there is missing data found using equal to missingValueIn - # missingFlag = 3 if there is missing data found using less than - # missingValueIn - - missingFlag = 0 - - # use value from the file - if missingValueIn is not None: - - if missingMatch == 'greater': - if missingValueIn > 0: - miss = 0.99 * missingValueIn - else: - miss = 1.01 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.greater( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 1 - - elif missingMatch == 'equal': - miss = missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.equal( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 2 - - elif missingMatch == 'less': - if missingValueIn > 0: - miss = 1.01 * missingValueIn - else: - miss = 0.99 * missingValueIn - n = numpy.add.reduce( - numpy.where( - numpy.less( - numpy.ravel(dataIn), - miss), - 1, - 0)) - if n > 0: - missingFlag = 3 - - # ----- get the shape of dataIn and set the number of dimensions in the da - - dataShape = dataIn.shape - # set size and check against positionIn - numberDataDim = len(dataShape) - - # remove the None fillers - reducedPositionIn = [] - for i in range(len(positionIn)): - if positionIn[i] is not None: - reducedPositionIn.append(positionIn[i]) - - if numberDataDim != len(reducedPositionIn): - msg = 'positionIn does not describe the number of dimensions in the data' - sendmsg(msg) - raise ValueError - - # ----- Determine the order of latitude and level in the data ------- - - # sequence is standard (lat,lon) - if positionIn[0] > positionIn[1]: - levlatFlag = 1 - else: - levlatFlag = 0 - - # ------------------------------------------------------------------------------------------------------ - # ----------------------------------------- Generate the mask ----------- - # ------------------------------------------------------------------------------------------------------ - - # ------------------------------------------------------------------------------------------------------ - # ---------- START NO USER MASK SECTION - - if maskIn is None: # ---- need to generate the mask from scratch ---- - - # allocate memory - amskin = numpy.ones(dataShape, numpy.float32) - - # ---------- START USER MASK SECTION - - else: # ---- use the users supplied mask ---- - - numberMaskDim = len(maskIn.shape) - - if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D - - # mask shape is (lat,lon) - if levlatFlag == 1: - checkmaskShape = ( - dataShape[positionIn[1]], dataShape[positionIn[0]]) - # mask shape is (lon,lat) - else: - checkmaskShape = ( - dataShape[positionIn[0]], dataShape[positionIn[1]]) - - if maskIn.shape != checkmaskShape: # check the mask shape - msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' - sendmsg(msg) - raise IndexError - - # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED - - if numberDataDim > 2: - # replicate the mask to size of dataIn - amskin = numpy.resize(maskIn, dataShape) - - else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE - - amskin = maskIn - - if numberMaskDim != numberDataDim: - msg = 'Error -- user supplied mask must be 2D or the size of the data' - sendmsg(msg) - raise IndexError - - if amskin.shape != dataIn.shape: - msg = 'Error -- full size mask supplied must have the same shape as the input data' - sendmsg(msg) - raise IndexError - - # there is missing data in dataIn to add to amskin - if missingFlag != 0: - if missingFlag == 1: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - elif missingFlag == 2: - amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) - elif missingFlag == 3: - amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) - - amskin = amskin.astype(numpy.float32) - - return amskin - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None - - -def section(latvals, levvals): - """ #--------------------------------------------------------------------------------- - # - # purpose: make the crossi section analytical test case - # - # passed : the grid coordinate vectors - # - # returned: xsection -- a temerature like cross section - # - #---------------------------------------------------------------------------------""" - - nlev = len(levvals) - - nlat = len(latvals) - theta = (math.pi / 180.) * latvals - - xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory - - t0 = 60. - p0 = 1000. - - for j in range(nlat): - for i in range(nlev): - x = math.cos(theta[j])**2 - y = t0 * ((levvals[i] / p0)**.3) - xsection[i, j] = x * y - 30. - - return xsection - - -def rmserror(data1, data2): - """ #--------------------------------------------------------------------------------- - # - # purpose: compute the rms error for two data sets having the same shape - # - # passed : the two data sets - # - # returned: rms error - # - #---------------------------------------------------------------------------------""" - - if data1.shape != data2.shape: - print('Error in shape in rmserror') - print(('data1 shape = ', data1.shape)) - print(('data2 shape = ', data2.shape)) - raise ValueError - - d1 = numpy.ravel(data1) - d2 = numpy.ravel(data2) - - sq = (d1 - d2) * (d1 - d2) - error = numpy.sum(sq) / len(d1) - rmserror = numpy.sqrt(error) - - return rmserror - - -if __name__ == '__main__': - import math - - latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) - levList = [10., 40., 75., 100., 150., 250., 350., 500., - 650., 850., 1000.] # pick some levels - levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - latOut = cdms2.createGaussianAxis(64) - levList = [10., 30., 50., 70., 100., 200., 300., 400., - 500., 700., 850., 1000.] # pick some levels - levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') - - xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) - - # make some artificial data - dataIn = section(latIn[:], levIn[:]) - var = cdms2.createVariable( - dataIn, axes=( - levIn, latIn), attributes={ - 'units': 'N/A'}, id='test') - - dataOut = xregridf(dataIn) - - # make the exact answer - dataCheck = section(latOut[:], levOut[:]) - # find the rms error - error = rmserror(dataOut, dataCheck) - - print('expected cross section test case rms error = 0.18581882') - # print 'expected cross section test case rms error = 0.23062' - print('calculated cross section test case rms error = ', error) diff --git a/regrid2/Lib/error.py b/regrid2/Lib/error.py deleted file mode 100644 index 327dff22..00000000 --- a/regrid2/Lib/error.py +++ /dev/null @@ -1,3 +0,0 @@ -class RegridError (Exception): - def __init__(self, args="Unspecified error from regrid package"): - self.args = (args,) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py deleted file mode 100644 index 830910a1..00000000 --- a/regrid2/Lib/esmf.py +++ /dev/null @@ -1,842 +0,0 @@ -#!/usr/bin/env python - -""" -Copyright (c) 2008-2012, Tech-X Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the conditions -specified in the license file 'license.txt' are met. - -Authors: David Kindig and Alex Pletzer -""" -import re -import time -import numpy -from regrid2 import RegridError -import ESMF -from functools import reduce - -# constants -R8 = ESMF.TypeKind.R8 -R4 = ESMF.TypeKind.R4 -I8 = ESMF.TypeKind.I8 -I4 = ESMF.TypeKind.I4 -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER -CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class EsmfUnstructGrid: - """ - Unstructured grid - """ - - def __init__(self, numTopoDims, numSpaceDims): - """Constructor - - Parameters - ---------- - - numTopoDims - number of topological dimensions - - numSpaceDims - number of space dimensions - """ - # handle to the grid object - self.grid = None - # whether or not nodes were added - self.nodesAdded = False - # whether or not cells were added - self.cellsAdded = False - # the local processor rank - self.pe = 0 - # number of processors - self.nprocs = 1 - # communicator - self.comm = None - - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - self.grid = ESMF.Mesh( - parametric_dim=numTopoDims, - spatial_dim=numSpaceDims) - - def setCells(self, cellIndices, cellTypes, connectivity, - cellMask=None, cellAreas=None): - """ - Set Cell connectivity - - Parameters - ---------- - - cell indices (0-based) - - cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - - connectivity node connectivity array, see below for node ordering - - cellMask - - cellAreas area (volume) of each cell - - Note - ---- - - 3 - / \ - / \ - / \ - / \ - / \ - 1 --------- 2 - - - - - 4------------3 - | | - | | - | | - | | - | | - 1 ---------- 2 - - - - 3 8---------------7 - /|\ /| /| - / | \ / | / | - / | \ / | / | - / | \ / | / | - / | \ 5---------------6 | - 4-----|-----2 | | | | - \ | / | 4----------|----3 - \ | / | / | / - \ | / | / | / - \ | / | / | / - \|/ |/ |/ - 1 1---------------2 - - ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX - - """ - n = len(cellIndices) - if not self.cellsAdded: - # node/cell indices are 1-based in ESMF - cellIndices += 1 - self.grid.add_elements(n, cellIndices, cellTypes, - connectivity, elementMask=cellMask, - elementArea=cellAreas) - self.cellsAdded = True - - def setNodes(self, indices, coords, peOwners=None): - """ - Set the nodal coordinates - - Parameters - ---------- - - indices Ids of the nodes (0-based) - - coords nodal coordinates - - peOwners processor ranks where the coordinates reside (0-based) - """ - n = len(indices) - if not self.nodesAdded: - if peOwners is None: - peOwners = numpy.ones((n,), numpy.int32) * self.pe - # node indices are 1-based - indices += 1 - self.grid.add_nodes(n, indices, coords, peOwners) - self.nodesAdded = True - - def toVTK(self, filename): - """ - Write grid to VTK file format - - Parameters - ---------- - - filename VTK file name - _: None - - """ - self.grid.write(filename) - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructGrid: - """ - Structured grid - """ - - def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, - periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, - hasBounds=False): - """ - Constructor - - Parameters - ---------- - - shape Tuple of cell sizes along each axis - - coordSys coordinate system - ESMF.CoordSys.CART Cartesian - ESMF.CoordSys.SPH_DEG (default) Degrees - ESMF.CoordSys.SPH_RAD Radians - - periodicity Does the grid have a periodic coordinate - 0 No periodicity - 1 Periodic in x (1st) axis - 2 Periodic in x, y axes - - staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX - The stagger constants are listed at the top - - hasBounds If the grid has bounds, Run AddCoords for the bounds - """ - # ESMF grid object - self.grid = None - # number of cells in [z,] y, x on all processors - self.shape = shape[::-1] - # number of dimensions - self.ndims = len(self.shape) - # whether or not cell areas were set - self.cellAreasSet = False - # whether or not nodal coords were set - self.nodesSet = False - # whether or not cell centered coordinates were set - self.centersSet = False - - # assume last 2 dimensions are Y,X - # For esmf reverse to X, Y - maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) - - self.centersSet = False - periodic_dim = 0 - pole_dim = 1 - if periodicity == 0: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], - coord_sys=coordSys) - elif periodicity == 1: - self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, - periodic_dim=periodic_dim, pole_dim=pole_dim, - staggerloc=[staggerloc], coord_sys=coordSys) - else: - msg = """ -esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. - """ % periodicity - raise RegridError(msg) - - # Grid add coordinates call must go here for parallel runs - # This occur before the fields are created, making the fields - # parallel aware. - if ((staggerloc == CENTER) and (not self.centersSet)): - self.centersSet = True - elif (staggerloc == CORNER) and (not self.nodesSet): - self.nodesSet = True - - if hasBounds is not None: - if self.ndims == 2: - self.grid.add_coords([CORNER], coord_dim=None, from_file=False) - if self.ndims == 3: - self.grid.add_coords( - [VCORNER], coord_dim=None, from_file=False) - - def getLocalSlab(self, staggerloc): - """ - Get the local slab (ellipsis). You can use this to grab - the data local to this processor - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple of slices - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([slice(lo[i], hi[i], None) - for i in range(self.ndims)])[::-1] - - def getLoHiBounds(self, staggerloc): - """ - Get the local lo/hi index values for the coordinates (per processor) - (hi is not inclusive, lo <= index < hi) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - lo, hi lists - """ - lo = self.grid.lower_bounds[staggerloc] - hi = self.grid.upper_bounds[staggerloc] - return lo, hi - - def getCoordShape(self, staggerloc): - """ - Get the local coordinate shape (may be different on each processor) - - Parameters - ---------- - - staggerloc - (e.g. ESMF.StaggerLoc.CENTER) - - _: None - - Returns - ------- - - tuple - """ - lo, hi = self.getLoHiBounds(staggerloc) - return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] - - def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): - """ - Populate the grid with staggered coordinates (e.g. corner or center). - - - Parameters - ---------- - - coords - The curvilinear coordinates of the grid. - List of numpy arrays. Must exist on all procs. - - staggerloc - The stagger location - ESMF.StaggerLoc.CENTER (default) - ESMF.StaggerLoc.CORNER - - globalIndexing - if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - - Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, - hence the dimensions are reversed here. - """ - # allocate space for coordinates, can only add coordinates once - for i in range(self.ndims): - ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) - if globalIndexing: - slab = self.getLocalSlab(staggerloc)[::-1] - # Populate self.grid with coordinates or the bounds as needed - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] - else: - ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] - - def getCoords(self, dim, staggerloc): - """ - Return the coordinates for a dimension - - Parameters - --------- - - dim desired dimension (zero based indexing) - - staggerloc Stagger location - """ - gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) - shp = self.getCoordShape(staggerloc)[::-1] - return numpy.reshape(gridPtr, shp).T - - def setCellAreas(self, areas): - """ - Set the cell areas - - Parameters - --------- - - areas numpy array - - _: None - - """ - self.grid.add_item(item=ESMF.GridItem.Area) - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - areaPtr[:] = areas.T.flat - self.cellAreasSet = True - - def getCellAreas(self): - """ - - Returns - ------- - - cell areas or None if setCellAreas was not called - """ - if self.cellAreasSet: - areaPtr = self.grid.get_item( - item=ESMF.GridItem.AREA, - staggerloc=self.staggerloc) - return numpy.reshape(areaPtr, self.shape).T - else: - return None - - def getMask(self, staggerloc=CENTER): - """ - Get mask array. In ESMF, the mask is applied to cells. - - Returns - ------- - - mask numpy array. 1 is invalid by default. This array exists on all procs - """ - try: - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, staggerloc=staggerloc) - except BaseException: - maskPtr = None - return maskPtr.T - - def setMask(self, mask, staggerloc=CENTER): - """ - Set mask array. In ESMF, the mask is applied to cells. - - Parameters - ---------- - - mask numpy array. 1 is invalid by default. This array exists - on all procs - - _: None - """ - self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) - maskPtr = self.grid.get_item( - item=ESMF.GridItem.MASK, - staggerloc=staggerloc) - slab = self.getLocalSlab(CENTER)[::-1] - maskPtr[:] = mask.T[slab] - - def __del__(self): - self.grid.destroy() - -########################################################################## - - -class EsmfStructField: - """ - Structured field. - """ - - def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): - """ - Creator for structured ESMF Field - - Parameters - ---------- - - esmfGrid - instance of an ESMF - - name field - name (must be unique) - - datatype - data type, one of 'float64', 'float32', 'int64', or 'int32' - (or equivalent numpy dtype) - - staggerloc - ESMF.StaggerLoc.CENTER - ESMF.StaggerLoc.CORNER - """ - # field object - self.field = None - # the local processor rank - self.pe = 0 - # the number of processors - self.nprocs = 1 - # associated grid - self.grid = esmfGrid - # staggering - self.staggerloc = staggerloc - # communicator - self.comm = None - - try: - from mpi4py import MPI - self.comm = MPI.COMM_WORLD - except BaseException: - pass - - etype = None - sdatatype = str(datatype) # in case user passes a numpy dtype - if re.search('float64', sdatatype): - etype = R8 - elif re.search('float32', sdatatype): - etype = R4 - elif re.search('int64', sdatatype): - etype = I8 - elif re.search('int32', sdatatype): - etype = I4 - else: - msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype - raise RegridError(msg) - - self.field = ESMF.Field( - grid=esmfGrid.grid, - name=name, - typekind=etype, - staggerloc=staggerloc) - vm = ESMF.ESMP_VMGetGlobal() - self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) - - def getPointer(self): - """ - Get field data as a flat array - - Returns - ------- - - pointer - """ - return numpy.ravel(self.field.data) - - def getData(self, rootPe): - """ - Get field data as a numpy array - - Parameters - ---------- - - rootPe if None then local data will be fetched, otherwise - gather the data on processor "rootPe" (all other - procs will return None). - - _: None - - Returns - ------- - - numpy array or None - """ - ptr = self.getPointer() - if rootPe is None: - shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] - # local data, copy - return numpy.reshape(ptr, shp).T - else: - # gather the data on rootPe - lo, hi = self.grid.getLoHiBounds(self.staggerloc) - los = [lo] - his = [hi] - ptrs = [ptr] - ptr = numpy.reshape(ptr, hi) - if self.comm is not None: - los = self.comm.gather(lo) # Local - his = self.comm.gather(hi) # Local - ptrs = self.comm.gather(ptr, root=rootPe) - - if self.pe == rootPe: # Local - # reassemble, find the largest hi indices to set - # the shape of the data container - bigHi = [0 for i in range(self.grid.ndims)] - for i in range(self.grid.ndims): - bigHi[i] = reduce(lambda x, y: max(x, y), - [his[p][i] for p in range(self.nprocs)]) - # allocate space to retrieve the data - bigData = numpy.empty(bigHi, ptr.dtype) - bigData[:] = 0.0 - - # populate the data - for p in range(self.nprocs): - slab = tuple([slice(los[p][i], his[p][i], None) for - i in range(self.grid.ndims)]) - # copy - bigData[slab].flat = ptrs[p] - return bigData.T # Local - - # rootPe is not None and self.pe != rootPe - return None - - def setLocalData(self, data, staggerloc, globalIndexing=False): - """ - Set local field data - - Parameters - ---------- - - data full numpy array, this method will take care of setting a - the subset of the data that reside on the local processor - - staggerloc stagger location of the data - - - globalIndexing if True array was allocated over global index - space, array was allocated over local index - space (on this processor) - """ - ptr = self.field.data - if globalIndexing: - slab = self.grid.getLocalSlab(staggerloc)[::-1] - ptr[:] = data.T[slab] - else: - ptr[:] = data.T - - -########################################################################## - -class EsmfRegrid: - """ - Regrid source grid data to destination grid data - """ - - def __init__(self, srcField, dstField, - srcFrac=None, - dstFrac=None, - srcMaskValues=None, - dstMaskValues=None, - regridMethod=BILINEAR, - ignoreDegenerate=False, - unMappedAction=IGNORE): - """ - Constuct regrid object - - Parameters - ---------- - - srcField - the source field object of type EsmfStructField - - dstField - the destination field object of type EsmfStructField - - srcMaskValues - Value of masked cells in source - - dstMaskValues - Value of masked cells in destination - - srcFrac - Cell fractions on source grid (type EsmfStructField) - - dstFrac - Cell fractions on destination grid (type EsmfStructField) - - regridMethod - ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} - - unMappedAction - ESMF.UnmappedAction.{IGNORE,ERROR} - - ignoreDegenerate - Ignore degenerate cells when checking inputs - """ - self.srcField = srcField - self.dstField = dstField - self.regridMethod = regridMethod - self.srcAreaField = None - self.dstAreaField = None - self.srcFracField = srcFrac - self.dstFracField = dstFrac - self.regridHandle = None - self.ignoreDegenerate = ignoreDegenerate - - timeStamp = re.sub('\.', '', str(time.time())) - - # create and initialize the cell areas to zero - if regridMethod == CONSERVE: - self.srcAreaField = EsmfStructField(self.srcField.grid, - name='src_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcAreaField.getPointer() - dataPtr[:] = 0.0 - self.dstAreaField = EsmfStructField(self.dstField.grid, - name='dst_areas_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstAreaField.getPointer() - dataPtr[:] = 0.0 - - # initialize fractional areas to 1 (unless supplied) - if srcFrac is None: - self.srcFracField = EsmfStructField(self.srcField.grid, - name='src_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.srcFracField.getPointer() - dataPtr[:] = 1.0 - - if dstFrac is None: - self.dstFracField = EsmfStructField(self.dstField.grid, - name='dst_cell_area_fractions_%s' % timeStamp, - datatype='float64', - staggerloc=CENTER) - dataPtr = self.dstFracField.getPointer() - dataPtr[:] = 1.0 - - srcMaskValueArr = None - if srcMaskValues is not None: - srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) - - dstMaskValueArr = None - if dstMaskValues is not None: - dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) - - self.regridHandle = ESMF.Regrid( - srcField.field, - dstField.field, - src_frac_field=self.srcFracField.field, - dst_frac_field=self.dstFracField.field, - src_mask_values=srcMaskValueArr, - dst_mask_values=dstMaskValueArr, - regrid_method=regridMethod, - unmapped_action=unMappedAction, - ignore_degenerate=self.ignoreDegenerate) - - def getSrcAreas(self, rootPe): - """ - Get the src grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.srcAreaField.data.T - return None - - def getDstAreas(self, rootPe): - """ - Get the dst grid areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array or None if interpolation is not conservative - """ - if self.srcAreaField is not None: - return self.dstAreaField.data.T - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.srcFracField is not None: - # self.srcFracField.get_area() - return self.srcFracField.data.T - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid fraction areas as used by conservative interpolation - - Parameters - ---------- - - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered - - _: None - - Returns - ------- - - numpy array - """ - if self.dstFracField is not None: - # self.dstFracField.get_area() - return self.dstFracField.data.T - return None - - def __call__(self, srcField=None, dstField=None, zero_region=None): - """ - Apply interpolation weights - - Parameters - ---------- - - srcField source field (or None if src field passed to - constructor is to be used) - - dstField destination field (or None if dst field passed - to constructor is to be used) - - zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) - """ - if srcField is None: - srcField = self.srcField - if dstField is None: - dstField = self.dstField - - # default is keep the masked values intact - zeroregion = ESMF.Region.SELECT - if self.regridMethod == CONSERVE: - zeroregion = None # will initalize to zero - - self.regridHandle( - srcfield=srcField.field, - dstfield=dstField.field, - zero_region=zeroregion) - - def __del__(self): - if self.regridHandle is not None: - self.regridHandle.destroy() diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py deleted file mode 100644 index de150dba..00000000 --- a/regrid2/Lib/gsRegrid.py +++ /dev/null @@ -1,1179 +0,0 @@ -#!/usr/bin/env python - -""" -Regridding of curvilinear structured grids -Alex Pletzer and Dave Kindig, Tech-X (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. -""" -# standard python includes -# from re import search, sub -from ctypes import c_double, c_float, c_int, \ - c_wchar_p, CDLL, byref, POINTER -# import ctypes -import operator -import sys -import os -import copy -import numpy -import warnings -from regrid2 import RegridError -from functools import reduce -import fnmatch - -C_DOUBLE_P = POINTER(c_double) - -# libcf -try: - from pycf import libCFConfig, __path__ -except BaseException: - raise ImportError('Error: could not import pycf') - -LIBCFDIR = __path__[0] + "/pylibcf" - -__FILE__ = sys._getframe().f_code.co_filename - - -def catchError(status, lineno): - if status != 0: - raise RegridError("ERROR in %s: status = %d at line %d" - % (__FILE__, status, lineno)) - - -def getTensorProduct(axis, dim, dims): - """ - Convert an axis into a curvilinear coordinate by applying - a tensor product - - Parameters - ---------- - - axis 1D array of coordinates - - dim dimensional index of the above coordinate - - dims sizes of all coordinates - - Returns - ------- - - coordinate values obtained by tensor product - """ - return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), - numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) - - -def makeCurvilinear(coords): - """ - Turn a mixture of axes and curvilinear coordinates into - full curvilinear coordinates - - Parameters - ---------- - - coords list of coordinates - - Returns - ------- - - new list of coordinates and associated dimensions - """ - rank = len(coords) - - count1DAxes = 0 - dims = [] - for i in range(rank): - coord = coords[i] - if len(coord.shape) == 1: - # axis - dims.append(len(coord)) - count1DAxes += 1 - elif len(coord.shape) == rank: - # fully curvilinear - dims.append(coord.shape[i]) - else: - # assumption: all 1D axes preceed curvilinear - # coordinates!!! - dims.append(coord.shape[i - count1DAxes]) - - for i in range(rank): - nd = len(coords[i].shape) - if nd == rank: - # already in curvilinear form, keep as is - pass - elif nd == 1: - # it's an axis - coords[i] = getTensorProduct(coords[i][:], i, dims) - elif rank == 3 and nd == 2 and i > 0: - # assume leading coordinate is an axis - o1 = numpy.ones((len(coords[0]),), coords[i].dtype) - coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) - else: - raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" - % (__FILE__, str([x.shape for x in coords]))) - return coords, dims - - -def makeCoordsCyclic(coords, dims): - """ - Make coordinates cyclic - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - new, extended coordinates such that the longitudes cover the sphere - and new dimensions - """ - # assume lon is the last coordinate!! - - # check if already extended - eps = 1.e-3 - - # some models already overlap - diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # some models are already periodic - diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) - diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) - diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) - adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ - / float(dims[-1]) - if adiff < eps: - # cyclic, return input coordinates unchanged - return coords, dims - - # make cyclic by appending a column to the coordinates - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-1] += 1 # append to the right - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:-1] = coords[i][...] - newCoords[i][..., -1] = coords[i][..., 0] - - # add modulo term, want deltas ~ order of dlon otherwise add - # or subtract a periodicity length - nlon = dims[-1] - dlon = 360.0 / float(nlon) # average resolution - tol = 360.0 - min(5, nlon) * dlon - mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) - mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) - newCoords[-1][..., -1] += 360.0 * mask1 - newCoords[-1][..., -1] -= 360.0 * mask2 - - return newCoords, newDims - - -def checkForCoordCut(coords, dims): - """ - Look for a cut in a coordinate system (e.g. tri-polar grid) - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates - - dims input dimensions - - Returns - ------- - - True for cut found - False for no cut - """ - - # Assume latitude is next to last coordinate and longitude is last - # coordinate!!! - - rank = len(dims) - if rank < 2: - # print 'no cut: dims < 2' - return False - if len(coords[-2].shape) < 2: - # Is the 'lat' coordinate an axis? - return False - - nlat, nlon = dims[-2], dims[-1] - lat = coords[-2] - eps = 1.e-7 - - # Check to see if the top row has already be dealt with by the modeling - # agency. Last row is repeated in reverse. - - topRow = coords[-2][..., nlat - 1, :] - revTop = coords[-2][..., nlat - 1, ::-1] - nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow - diffs = abs(revTop - nextRow) - - # If already accounted for all diffs are 0. - if numpy.all(diffs < eps): - # print "no cut: reversed" - return False - - # Lon of max latitude -- Looking for a rotated pole - maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) - inTopRow = False - if len(maxLats[0] > 0): - inTopRow = numpy.all(maxLats[-2] == nlat - 1) - if not inTopRow: - # The max lats are not in the top row. The cut may already be handled - # print 'no cut: max lat not in top row.' + \ - # 'Either: it is a funky grid or rotated pole' - return False - - # Only in top row. - maxLatInd = lat[..., nlat - 1, :].argmax() - maxLonInd = lat[..., maxLatInd].argmax() - rowOfMaxLat = lat[..., maxLonInd, :] - diffs = rowOfMaxLat - topRow - - if diffs.max() != 0: - # Rotated Pole - # print "no cut: rotated pole" - return False - - # Find locale minima. - # A rotated pole grid has only one minimum. A tripolar grid should - # have two, though they may not be at the same latitude - - minInds = numpy.where(abs(topRow - topRow.min()) < eps) - if len(minInds[0]) > 2: - # Account for the end points matching - # Multiple minima in the top row - return True - - # Now if we have an offset tri-pole. The extra poles are not at the same - # latitude - minCount = 0 - firstInd = topRow.argmin() - diffs = numpy.diff(topRow) - if firstInd == 0: - if revTop.argmin() == 0: - if topRow[firstInd] == revTop[0]: - minCount += 1 - else: - minCount += 1 - # Look for next Minima - index = firstInd + 1 - while diffs[index] > 0: - index += 1 - if index == nlon: - break - nextIndex = topRow[index + 1:].argmin() + index + 1 - if nextIndex != index + 1 and nextIndex != nlon - 1: - minCount += 1 - if minCount == 1: - # print "no cut: one pole" - return False - - return True - - -def handleCoordsCut(coords, dims, bounds): - """ - Generate connectivity across a cut. e.g. from a tri-polar grid. - Assume latitude is next to last coordinate and longitude is last coordinate!!! - - Parameters - ---------- - - coords input coordinates list of rank - - dims input dimensions - - bounds boundaries for each coordinate - - Returns - ------- - - extended coordinates such that there is an extra row containing - connectivity information across the cut - """ - - # Assume latitude is next to last coordinate and longitude is - # last coordinate!!! - - dims = coords[-2].shape - - # Add row to top with connectivity information. This means rearranging - # the top row - def getIndices(array, nlon, newI): - """ - Find indices where a cell edge matches for two cells - - Parameters - ---------- - - array Array of booleans - - nlon number of longitudes - - newI index row with connectivity to be updated - - Returns - ------- - - new coordinates, new dimensions, index row - """ - for i in range(len(array)): - # An edge - if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa - if newI[i] < 0: - newI[i] = (nlon - 1) - i - if newI[(nlon - 1) - i] < 0: - newI[(nlon - 1) - i] = i - - # Assume mkCyclic == True - newI = numpy.arange(nlon - 1, -1, -1) - 1 - newI[nlon - 1] = 0 # Complete the rotation - - # Build new coordinate array and adjust dims - newCoords = [] - newDims = list(copy.copy(dims)) - newDims[-2] += 1 - - for i in range(len(coords)): - newCoords.append(numpy.zeros(newDims, coords[i].dtype)) - newCoords[i][..., 0:dims[-2], :] = coords[i][...] - newCoords[i][..., dims[-2], - :] = coords[i][..., dims[-2] - 1, newI] - - return newCoords, newDims, newI - - -class Regrid: - - def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, - handleCut=False, verbose=False): - """ - Constructor - - Parameters - ---------- - - src_grid source grid, a list of [x, y, ...] coordinates - or a cdms2.grid.Transient - - dst_grid destination grid, a list of [x, y, ...] coordinates - - src_bounds list of cell bounding coordinates (to be used when - handling a cut in coordinates) - - mkCyclic Add a column to the right side of the grid to complete - a cyclic grid - - handleCut Add a row to the top of grid to handle a cut for - grids such as the tri-polar grid - - verbose print diagnostic messages - - - Note: the grid coordinates can either be axes (rectilinear grid) or - n-dimensional for curvilinear grids. Rectilinear grids will - be converted to curvilinear grids. - """ - self.regridid = c_int(-1) - self.src_gridid = c_int(-1) - self.dst_gridid = c_int(-1) - self.rank = 0 - self.src_dims = [] - self.dst_dims = [] - self.src_coords = [] - self.dst_coords = [] - self.lib = None - self.extendedGrid = False - self.handleCut = False - self.dst_Index = [] - self.verbose = verbose - self.weightsComputed = False - self.maskSet = False - - # Open the shaped library - dynLibFound = False - for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': - if os.path.exists(LIBCFDIR + sosuffix): - dynLibFound = True - CFfile = self.find('pylibcf.*', __path__[0]) - if os.path.exists(CFfile): - try: - self.lib = CDLL(CFfile) - except BaseException: - pass -# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': -# if os.path.exists(LIBCFDIR + sosuffix): -# dynLibFound = True -# try: -# self.lib = CDLL(LIBCFDIR + sosuffix) -# break -# except: -# pass - if self.lib is None: - if not dynLibFound: - raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" - % (__FILE__, LIBCFDIR)) - - # Number of space dimensions - self.rank = len(src_grid) - - if len(dst_grid) != self.rank: - raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" - % (__FILE__, len(dst_grid), self.rank)) - - if self.rank <= 0: - raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" - % (__FILE__, self.rank)) - - # Convert src_grid/dst_grid to curvilinear grid, if need be - if self.rank > 1: - src_grid, src_dims = makeCurvilinear(src_grid) - dst_grid, dst_dims = makeCurvilinear(dst_grid) - - # Make sure coordinates wrap around if mkCyclic is True - if mkCyclic: - src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - for i in range(self.rank): - print(('...... src_gridNew[%d].shape = %s' - % (i, str(src_gridNew[i].shape)))) - # flag indicating that the grid was extended - if reduce(lambda x, y: x + y, - [src_dimsNew[i] - src_dims[i] - for i in range(self.rank)]) > 0: - self.extendedGrid = True - # reset - src_grid = src_gridNew - src_dims = src_dimsNew - - # Handle a cut in the coordinate system. Run after mkCyclic. - # e.g. a tri-polar grid - if handleCut and src_bounds is not None: - # Test for the presence of a cut. - isCut = checkForCoordCut(src_grid, src_dims) - if isCut: - # No cut - src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, - src_dims, src_bounds) - if dst_Index is not None: - self.handleCut = True - self.extendedGrid = self.extendedGrid - else: - self.handleCut = False - self.extendedGrid = self.extendedGrid - if self.verbose: - aa, bb = str(src_dims), str(src_dimsNew) - print(('... src_dims = %s, after making cyclic src_dimsNew = %s' - % (aa, bb))) - src_grid = src_gridNew - src_dims = src_dimsNew - self.dst_Index = dst_Index - - self.src_dims = (c_int * self.rank)() - self.dst_dims = (c_int * self.rank)() - - # Build coordinate objects - src_dimnames = (c_wchar_p * self.rank)() - dst_dimnames = (c_wchar_p * self.rank)() - for i in range(self.rank): - src_dimnames[i] = 'src_n%d' % i - dst_dimnames[i] = 'dst_n%d' % i - self.src_dims[i] = src_dims[i] - self.dst_dims[i] = dst_dims[i] - self.src_coordids = (c_int * self.rank)() - self.dst_coordids = (c_int * self.rank)() - save = 0 - standard_name = "" - units = "" - coordid = c_int(-1) - for i in range(self.rank): - data = numpy.array(src_grid[i], numpy.float64) - self.src_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "src_coord%d" % i - # assume [lev,] lat, lon ordering - if i == self.rank - 2: - standard_name = 'latitude' - units = 'degrees_north' - elif i == self.rank - 1: - standard_name = 'longitude' - units = 'degrees_east' - status = self.lib.nccf_def_coord(self.rank, self.src_dims, - src_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.src_coordids[i] = coordid - - data = numpy.array(dst_grid[i], numpy.float64) - self.dst_coords.append(data) - dataPtr = data.ctypes.data_as(C_DOUBLE_P) - name = "dst_coord%d" % i - status = self.lib.nccf_def_coord(self.rank, self.dst_dims, - dst_dimnames, - dataPtr, save, name, - standard_name, units, - byref(coordid)) - catchError(status, sys._getframe().f_lineno) - self.dst_coordids[i] = coordid - - # Build grid objects - status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", - byref(self.src_gridid)) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", - byref(self.dst_gridid)) - catchError(status, sys._getframe().f_lineno) - - # Create regrid object - status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, - byref(self.regridid)) - catchError(status, sys._getframe().f_lineno) - - def getPeriodicities(self): - """ - Get the periodicity lengths of the coordinates - - Returns - ------- - - numpy array, values inf indicate no periodicity - """ - coord_periodicity = numpy.zeros((self.rank,), numpy.float64) - status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, - coord_periodicity.ctypes.data_as(C_DOUBLE_P)) - catchError(status, sys._getframe().f_lineno) - return coord_periodicity - - def __del__(self): - """ - Destructor, will be called automatically - """ - status = self.lib.nccf_free_regrid(self.regridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.src_gridid) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_grid(self.dst_gridid) - catchError(status, sys._getframe().f_lineno) - - for i in range(self.rank): - - status = self.lib.nccf_free_coord(self.src_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - status = self.lib.nccf_free_coord(self.dst_coordids[i]) - catchError(status, sys._getframe().f_lineno) - - def find(self, pattern, path): - result = "" - for root, dirs, files in os.walk(path): - for name in files: - if fnmatch.fnmatch(name, pattern): - result = os.path.join(root, name) - return result - - def setValidMask(self, inMask): - """ - Set valid mask array for the grid - - Parameters - ---------- - - inMask flat numpy array of type numpy.int32 or a valid cdms2 variable - with its mask set. - 0 - invalid, 1 - valid data - - Note: This must be invoked before computing the weights, the - mask is a property of the grid (not the data). - """ - if self.weightsComputed: - raise RegridError('Must set mask before computing weights') - - mask = numpy.array(inMask, dtype=numpy.int32) - - # extend src data if grid was made cyclic and or had a cut accounted - # for - newMask = self._extend(mask) - c_intmask = newMask.ctypes.data_as(POINTER(c_int)) - status = self.lib.nccf_set_grid_validmask(self.src_gridid, - c_intmask) - catchError(status, sys._getframe().f_lineno) - self.maskSet = True - - def setMask(self, inDataOrMask): - """ - Set mask array. The mask is defined for nodes - - Parameters - ---------- - - inDataOrMask cdms2 array or flat mask array, - 0 - valid data - 1 - invalid data - - Note: this definition is compatible with the numpy masked arrays - - Note: note see setValidMask for the opposite definition - - Note: should be called before computing the weights - """ - mask = None - if hasattr(inDataOrMask, 'getmask'): - # cdms2 variable - mask = inDataOrMask.getmask() - else: - # flat mask array - mask = inDataOrMask - # reversing the meaning 1 == valid, 0 == invalid - mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) - # now calling our own mask setter - self.setValidMask(mask) - - def computeWeights(self, nitermax=100, tolpos=1.e-2): - """ - Compute the the interpolation weights - - Parameters - ---------- - - nitermax max number of iterations - - tolpos max tolerance when locating destination positions in - index space - """ - status = self.lib.nccf_compute_regrid_weights(self.regridid, - nitermax, - c_double(tolpos)) - catchError(status, sys._getframe().f_lineno) - self.weightsComputed = True - - def apply(self, src_data_in, dst_data, missingValue=None): - """ - Apply interpolation - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - if not self.weightsComputed: - raise RegridError('Weights must be set before applying the regrid') - # extend src data if grid was made cyclic and or had a cut accounted - # for - src_data = self._extend(src_data_in) - - # Check - if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + - "%s != %s") % (__FILE__, str(src_data.shape), - str(tuple([d for d in self.src_dims])))) - if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] - for i in range(self.rank)]) == False: # noqa - raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + - "%s != %s") % (__FILE__, str(dst_data.shape), - str(tuple([d for d in self.dst_dims])))) - - # Create temporary data objects - src_dataid = c_int(-1) - dst_dataid = c_int(-1) - save = 0 - standard_name = "" - units = "" - time_dimname = "" - - status = self.lib.nccf_def_data(self.src_gridid, "src_data", - standard_name, units, time_dimname, - byref(src_dataid)) - catchError(status, sys._getframe().f_lineno) - - if src_data.dtype != dst_data.dtype: - try: # try recasting - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" - % (src_data.dtype, dst_data.dtype)) - src_data = src_data.astype(dst_data.dtype) - except BaseException: - try: - warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" - % (src_data.dtype, dst_data.dtype)) - dst_data = dst_data.astype(src_data.dtype) - except BaseException: - raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" - % (__FILE__, src_data.dtype, dst_data.dtype)) - - # only float64 and float32 data types are supported for interpolation - if src_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif src_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - ptr = src_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - src_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" - % (__FILE__, src_data.dtype)) - - status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", - standard_name, units, time_dimname, - byref(dst_dataid)) - catchError(status, sys._getframe().f_lineno) - if dst_data.dtype == numpy.float64: - fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) - if missingValue is not None: - fill_value = c_double(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_double)) - status = self.lib.nccf_set_data_double( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - elif dst_data.dtype == numpy.float32: - fill_value = c_float(libCFConfig.NC_FILL_FLOAT) - if missingValue is not None: - fill_value = c_float(missingValue) - dst_data[:] = missingValue - ptr = dst_data.ctypes.data_as(POINTER(c_float)) - status = self.lib.nccf_set_data_float( - dst_dataid, ptr, save, fill_value) - catchError(status, sys._getframe().f_lineno) - else: - raise RegridError("ERROR in %s: invalid dst_data type = %s" - % (__FILE__, dst_data.dtype)) - - # Now apply weights - status = self.lib.nccf_apply_regrid( - self.regridid, src_dataid, dst_dataid) - catchError(status, sys._getframe().f_lineno) - - # Clean up - status = self.lib.nccf_free_data(src_dataid) - catchError(status, sys._getframe().f_lineno) - status = self.lib.nccf_free_data(dst_dataid) - catchError(status, sys._getframe().f_lineno) - - return dst_data - - def __call__(self, src_data, dst_data, missingValue=None): - """ - Apply interpolation (synonymous to apply method) - - Parameters - ---------- - - src_data data on source grid - - dst_data data on destination grid - - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. - """ - self.apply(src_data, dst_data, missingValue) - - def getNumValid(self): - """ - Return the number of valid destination points. Destination points - falling outside the source domain, more gnerally, points which - could not be located on the source grid, reduce the number of - valid points. - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_nvalid(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getNumDstPoints(self): - """ - Return the number of points on the destination grid - - Returns - ------- - - number of points - """ - res = c_int(-1) - status = self.lib.nccf_inq_regrid_ntargets(self.regridid, - byref(res)) - catchError(status, sys._getframe().f_lineno) - return res.value - - def getSrcGrid(self): - """ - Return the source grid - - Returns - ------- - - grid - """ - return self.src_coords - - def getDstGrid(self): - """ - Return the destination grid - - Returns - ------- - - grid - """ - return self.dst_coords - - def getIndicesAndWeights(self, dst_indices): - """ - Get the indices and weights for a single target location - - Parameters - ---------- - - dst_indices index set on the target grid - - Returns - ------- - - [index sets on original grid, weights] - """ - dinds = numpy.array(dst_indices) - sinds = (c_int * 2**self.rank)() - weights = numpy.zeros((2**self.rank,), numpy.float64) - status = self.lib.nccf_inq_regrid_weights(self.regridid, - dinds.ctypes.data_as( - POINTER(c_double)), - sinds, - weights.ctypes.data_as(POINTER(c_double))) - catchError(status, sys._getframe().f_lineno) - # convert the flat indices to index sets - ori_inds = [] - for i in range(2**self.rank): - inx = numpy.zeros((self.rank,), numpy.int32) - self.lib.nccf_get_multi_index(self.rank, self.src_dims, - sinds[i], - inx.ctypes.data_as(POINTER(c_int))) - ori_inds.append(inx) - - return ori_inds, weights - - def _extend(self, src_data): - """ - Extend the data by padding a column and a row, depending on whether the - grid was made cyclic and a fold was added or not - - Parameters - ---------- - - src_data input source data - - Returns - ------- - - extended source data (or source input data of no padding was applied) - """ - - # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] - # original dimensions, before extension - # assuming ..., lat, lon ordering - nlat, nlon = src_data.shape[-2:] - - # no cut and no cyclic extension - src_dataNew = src_data - - if self.handleCut or self.extendedGrid: - # copy data into new, extended container - src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) - # start filling in... - src_dataNew[..., :nlat, :nlon] = src_data[...] - - if self.handleCut: - # fill in polar cut (e.g. tripolar cut), top row - # self.dst_Index[i] knows how to fold - for i in range(nlon): - src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] - - if self.extendedGrid: - # make data periodic in longitudes - src_dataNew[..., -1] = src_dataNew[..., 0] - - return src_dataNew - - def _findIndices(self, targetPos, nitermax, tolpos, - dindicesGuess): - """ - Find the floating point indices - - Parameters - ---------- - - targetPos numpy array of target positions - - nitermax max number of iterations - - tolpos max toelrance in positions - - dindicesGuess guess for the floating point indices - - Returns - ------- - - indices, number of iterations, achieved tolerance - """ - posPtr = targetPos.ctypes.data_as(POINTER(c_double)) - adjustFunc = None - hit_bounds = numpy.zeros((self.rank), - dtype=int).ctypes.data_as(POINTER(c_int)) - # no periodicity - coord_periodicity = float( - 'inf') * numpy.ones((self.rank), targetPos.dtype) - coord_periodicity_ptr = coord_periodicity.ctypes.data_as( - POINTER(c_double)) - res = copy.copy(dindicesGuess) - resPtr = res.ctypes.data_as(POINTER(c_double)) - src_coords = (POINTER(c_double) * self.rank)() - niter = c_int(nitermax) - tol = c_double(tolpos) - for i in range(self.rank): - ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) - src_coords[i] = ptr - status = self.lib.nccf_find_indices_double(self.rank, - self.src_dims, - src_coords, - coord_periodicity_ptr, - posPtr, - byref(niter), - byref(tol), - adjustFunc, - resPtr, - hit_bounds) - catchError(status, sys._getframe().f_lineno) - return resPtr.contents.value, niter.value, tol.value - -###################################################################### - - -def testMakeCyclic(): - - y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) - x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) - yy = getTensorProduct(y, 0, [len(y), len(x)]) - xx = getTensorProduct(x, 1, [len(y), len(x)]) - coords = [yy, xx] - dims = [len(y), len(x)] - newCoords, newDims = makeCoordsCyclic(coords, dims) -# print 'cyclic lats' -# print newCoords[0] -# print 'cyclic lons' -# print newCoords[1] - - -def testHandleCut(): - - import cdms2 - # Need tripolar grid - filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" - f = cdms2.open(filename) - if not f: - return - - # so = f.variables['so'][0, 0, :, :] - if 'lon' in list(f.variables.keys()): - alllat = f.variables['lat'] - alllon = f.variables['lon'] - else: - alllat = f.getAxis("lat").getData() - alllon = f.getAxis("lon").getData() - - bounds = [f.variables['bounds_lon'][:].data, - f.variables['bounds_lat'][:].data] - coords = [alllat[:].data, alllon[:].data] - dims = alllat.shape - newCoords, newDims = makeCoordsCyclic(coords, dims) - newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) - - -# def testOuterProduct(): - - # 2d - # x = numpy.array([1, 2, 3, 4]) - # y = numpy.array([10, 20, 30]) - # xx = getTensorProduct(x, 0, [len(x), len(y)]) - # yy = getTensorProduct(y, 1, [len(x), len(y)]) - - # z = numpy.array([100, 200]) - # Mixed coordinates and axes - # aa = makeCurvilinear([z, yy, xx]) - # for g in aa: - # print g - -def test(): - def func1(coords): - return coords[0] * coords[1] + coords[2] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = numpy.array([1, 2, 3, 4, 5, 6]) - src_y = numpy.array([10, 20, 30, 40, 50]) - src_z = numpy.array([100, 200]) - - # destination grid, product of axes - dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) - dst_y = numpy.array([15., 20., 25., 30., 40.]) - dst_z = numpy.array([120.0, 180.0, 240.]) - - # regridding constructor - rg = Regrid([src_x, src_y, src_z], - [dst_x, dst_y, dst_z]) -# rg = Regrid([src_x, src_y], -# [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - maxNumIters = 20 - posTol = 1.e-3 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data = ', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -def testMasking(): - import numpy.ma as ma - - def func1(coords): - return coords[0] * coords[1] - - def func2(coords): - return coords[0] * coords[1] - - # source grid, tensor product of axes - src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) - src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) - - # destination grid, product of axes - dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, - 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) - dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) - - # regridding constructor - rg = Regrid([src_x, src_y], - [dst_x, dst_y]) - - # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) - # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), - # 20, 1.e-2, initialIndexGuess) - # Mask needs to be set before weights are computed - mask = rg.getSrcGrid()[0] == 3 - mask[:, 3] = True - rg.setValidMask(mask) - rg.setMask(mask) - maxNumIters = 20 - posTol = 1.e-2 - rg.computeWeights(maxNumIters, posTol) - - # number of valid points (some destination points may fall - # outside the domain) - nvalid = rg.getNumValid() - - # number of destination points - ndstpts = rg.getNumDstPoints() - print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) - - # get the indices and weights for a single target location - dst_indices = [4, 2, 1] - inds, weights = rg.getIndicesAndWeights(dst_indices) - print(('indices and weights are: ', inds, weights)) - - # data - src_coords = rg.getSrcGrid() - dst_coords = rg.getDstGrid() - # print 'src_coords = ', src_coords - # print 'dst_coords = ', dst_coords - src_data = numpy.array(func1(src_coords), numpy.float32) - dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) - - # regrid - rg(src_data, dst_data) - print(('after interp: dst_data =\n', dst_data)) - - # check - error = numpy.sum(abs(dst_data - func1(dst_coords))) - # print dst_data - # print func(dst_coords) - print(('error = ', error)) - - -if __name__ == '__main__': - # testOuterProduct() - test() - testMasking() - # testMakeCyclic() - # testHandleCut() diff --git a/regrid2/Lib/gs_horizontal.py b/regrid2/Lib/gs_horizontal.py deleted file mode 100644 index 20cfa4a6..00000000 --- a/regrid2/Lib/gs_horizontal.py +++ /dev/null @@ -1,214 +0,0 @@ -import sys -import os -import os.path -# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer -from ctypes import CDLL, c_double, c_uint -import cdms2 -import time -import config -sys.path.append("/home/painter1/libcf/") -libcf = CDLL(config.prefix + '/lib/libcf.so') - - -class GS_Regridder: - - def __init__(self, ingrid, outgrid, - infile=None, outfile=None, remapfile=None): - # Save the grids, make and save a Gridspec remap file. - # For now, we are using the libCF/Gridspec API which operates only on files; - # thus temporary files are written out and read back in. That requires the - # input grids to support a "write_gridspec" method. - # If a path is provided, it prefixes whatever filenames were input. - # If there is no path provided, each filename must include its path. - # Note: it's a bit messy to keep filenames and paths separate internally, - # but the presnet Gridspec function expects lots of directories. - - self.ingrid = ingrid - self.outgrid = outgrid - if (not hasattr(ingrid, "gsfile")): - ingrid.gsfile = None - ingrid.gspath = None - if (infile is None): - self.infile = ingrid.gsfile - self.inpath = ingrid.gspath - else: - self.infile = os.path.basename(infile) - self.inpath = os.path.dirname(infile) - if (not os.path.isfile(self.inpath + "/" + self.infile)): - raise OSError( - "cannot open infile " + - self.inpath + - "/" + - self.infile) - - if (not hasattr(outgrid, "gsfile")): - outgrid.gsfile = None - outgrid.gspath = None - if (outfile is None): - self.outfile = outgrid.gsfile - self.outpath = outgrid.gspath - else: - self.outfile = os.path.basename(outfile) - self.outpath = os.path.dirname(outfile) - if (not os.path.isfile(self.outpath + "/" + self.outfile)): - raise OSError( - "cannot open outfile " + - self.outpath + - "/" + - self.outfile) - - if (remapfile is None): - timestr = str(int(time.time())) - self.remapfile = "remap" + timestr - self.remappath = "/tmp" - else: - self.remapfile = os.path.basename(remapfile) - self.remappath = os.path.dirname(remapfile) - if (not os.path.isdir(self.remappath + "/")): - raise OSError( - "cannot open remapfile directory " + - self.remappath + - "/") - - ingrid.write_gridspec(self.inpath + "/" + self.infile) - outgrid.write_gridspec(self.outpath + "/" + self.outfile) - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - # No variables to interpolate; the gs_fregrid call will be just to - # make a remap file... - dir_in = 256 * "\x00" - dir_out = 256 * "\x00" - input_file = 256 * "\x00" - nfiles = 0 - output_file = 256 * "\x00" - nfiles_out = 0 - scalar_name = 256 * "\x00" - nscalar = 0 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - # For a call which only writes the remap files, gs_fregrid - # expects remapfile to be a full path. For a call in which - # remapping takes place, gs_fregrid expects remapfile to be - # a pure filename, in a path it gets from elsewhere, maybe dir_in. - # (ARRGH - but with the API slated to be replaced, I'll live with it) - remapf = os.path.abspath( - self.remappath + "/" + self.remapfile) + "\0" * 256 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - remapf, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - def __call__(self, ar): - # Interpolate the input variable to the new grid using the Gridspec - # remap file generated when this GS_Remapper object was initialized. - # >>>for now, ar is required to be a variable (MV) <<< - - # Here, convert ar into a file for gs_fregrid - # There's no special Gridspec way to write a variable; you write to any - # *.nc file. The tough part is making sure you have there exactly what's - # needed for the gs_fregrid call, especially because the grids are - # supposedly supergrids and you just have some keywords to use to figure - # out what goes where. And note that we'll need to check whether ar - # really lives on self.ingrid . Supposedly a future API will work - # better in this respect - - # Write the variable to a temporary file, as required by gs_fregrid. - # The remap path should be suitable. - # >>> this should be done more carefully, e.g. deal with failures; - # >>> more worth doing when we have mosaic variables. - timestr = str(int(time.time())) - varfile = cdms2.open( - self.inpath + - "/" + - "invvar" + - timestr + - ".nc", - 'w') - varfile.write(ar) - varfile.close() - - history = "GS_Regridder" - mosaic_in = self.inpath + "/" + self.infile - mosaic_out = self.outpath + "/" + self.outfile - - dir_in = 256 * "\x00" # path is already encoded in input_file - dir_out = 256 * "\x00" # path is already encoded in output_file - input_file = varfile.id + 256 * "\x00" - nfiles = 1 - output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" - nfiles_out = 1 - scalar_name = ar.id + 256 * "\x00" - nscalar = 1 - u_name = 256 * "\x00" - v_name = 256 * "\x00" - nvector = 0 - nvector2 = 0 - - interp_method = "conserve_order2" - test_case = None - test_param = c_double(1.0) - opcode = c_uint(0) - AGRID = 64 - grid_type = AGRID - finer_step = c_uint(0) - fill_missing = 0 - nlon = 0 - nlat = 0 - check_conserve = 0 - y_at_center = 0 - lonbegin = c_double(0.) - lonend = c_double(360.) - latbegin = c_double(-90.) - latend = c_double(90.) - lbegin = 0 - lend = -1 - kbegin = 0 - kend = -1 - - print(("__call__ remapfile=", self.remapfile)) - libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, - input_file, nfiles, output_file, nfiles_out, - self.remapfile, - scalar_name, nscalar, u_name, nvector, v_name, - nvector2, interp_method, test_case, test_param, opcode, - grid_type, finer_step, fill_missing, nlon, nlat, - check_conserve, y_at_center, lonbegin, lonend, latbegin, - latend, kbegin, kend, lbegin, lend) - - # Read the output_file into a variable, and return the variable - f = cdms2.open(self.outpath + "/" + output_file) - vout = f(scalar_name) - f.close() - return vout diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py deleted file mode 100644 index 67d673f4..00000000 --- a/regrid2/Lib/horizontal.py +++ /dev/null @@ -1,422 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import numpy -import copy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import warnings -import cdms2 - -_debug = 0 # Set to 1 for debug - -# Map (n,2) boundary arrays to individual boundary arrays. Returns -# (lowerBounds, upperBounds) - - -def extractBounds(bounds): - if bounds[0, 0] < bounds[0, 1]: - lower = bounds[:, 0] - upper = bounds[:, 1] - else: - lower = bounds[:, 1] - upper = bounds[:, 0] - - return (lower.astype(numpy.float32), upper.astype(numpy.float32)) - -# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid -# objects. - - -class Horizontal: - - def __init__(self, ingrid, outgrid): - """ - Constructor for regridding class - - Parameters - ---------- - - ingrid cdms2, ndarray variable - - outgrid cdms2, ndarray variable - """ - - inlat = ingrid.getLatitude() - outlat = outgrid.getLatitude() - inlon = ingrid.getLongitude() - outlon = outgrid.getLongitude() - inlatBounds, inlonBounds = ingrid.getBounds() - outlatBounds, outlonBounds = outgrid.getBounds() - - self.nlati = len(inlat) - self.nlato = len(outlat) - self.nloni = len(inlon) - self.nlono = len(outlon) - self.inmask = ingrid.getMask() - self.outmask = outgrid.getMask() - # Make grid masks consistent with 'internal' convention: - # 0 == invalid - if self.inmask is not None: - self.inmask = 1. - self.inmask - if self.outmask is not None: - self.outmask = 1. - self.outmask - self.inshape = ingrid.shape - self.inorder = ingrid.getOrder() - self.outlat = outgrid.getLatitude().clone() - self.outlon = outgrid.getLongitude().clone() - - bsin, bnin = extractBounds(inlatBounds) - bwin, bein = extractBounds(inlonBounds) - bsout, bnout = extractBounds(outlatBounds) - bwout, beout = extractBounds(outlonBounds) - - if _debug == 1: - import sys - sys.stdout = open('debug_regrid.txt', 'w') - print(("bsin = ", numpy.array2string(bsin, precision=3))) - print(("bnin = ", numpy.array2string(bnin, precision=3))) - print(("bwin = ", numpy.array2string(bwin, precision=3))) - print(("bein = ", numpy.array2string(bein, precision=3))) - print(("bsout = ", numpy.array2string(bsout, precision=3))) - print(("bnout = ", numpy.array2string(bnout, precision=3))) - print(("bwout = ", numpy.array2string(bwout, precision=3))) - print(("beout = ", numpy.array2string(beout, precision=3))) - - self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( - self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) - - def __call__(self, ar, missing=None, order=None, - mask=None, returnTuple=0, **args): - """ - Call the regridder function. - @param ar is the input array. - @param order is of the form "tzyx", "tyx", etc. - @param missing is the missing data value, if any. - @param mask is either 2-D or the same shape as ar. - @param returnTuple If true, return the tuple (outArray, outWeights) where - outWeights is the fraction of each zone of the output grid - which overlaps non-missing zones of the input grid; it has - the same shape as the output array. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Compatibility - if mask is numpy.ma.nomask: - mask = None - - if ar.dtype.type is numpy.bool_: - ar = numpy.asarray(ar, numpy.float32) - - # Make sense of mask consistent with 'internal' convention (0 == - # invalid) - if mask is not None: - mask = 1. - mask - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = list([x[0].clone() for x in ar.getDomain()]) - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - armask = ar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - armask = tempar.mask - if armask is numpy.ma.nomask: - armask = None - else: - armask = 1. - armask # Reverse numpy.ma convention for rgdarea - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armask = armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # If neither mask nor missing value is specified, get them from - # the input array. - if mask is None and missing is None: - missing = armiss - mask = armask - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 2: - order = self.inorder - elif rank == 3: - order = "t" + self.inorder - else: - order = "tz" + self.inorder - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to ilon, ilat ... - itim1 = itim2 = 0 - ilon = ilat = -1 - idim = 0 - for i in range(rank - 1, -1, -1): - c = order[i] - if c == 'x': - ilon = idim - elif c == 'y': - ilat = idim - elif c == 'z': - itim1 = idim - elif c == 't': - if rank == 3: - itim1 = idim - else: - itim2 = idim - idim = idim + 1 - - # Map array shape to nloni, nlati, ... - ntim1 = ntim2 = 0 - shape = ar.shape - if ilon == -1: - raise RegridError("Input grid does not have a longitude axis") - if ilat == -1: - raise RegridError("Input grid does not have a latitude axis") - nlati = shape[rank - ilat - 1] - nloni = shape[rank - ilon - 1] - if nlati != self.nlati or nloni != self.nloni: - raise ( - 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % - (nlati, nloni, self.nlati, self.nloni)) - - if itim1 != 0: - ntim1 = shape[rank - itim1 - 1] - if itim2 != 0: - ntim2 = shape[rank - itim2 - 1] - - # Construct the input mask: - # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask - # if no user mask is specified) - # with the 'implicit mask' generated from the missing data, if any - if (mask is None) or len(mask.shape) == 2: - flag2D = 1 - if mask is not None: - assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' - inmask = mask - elif self.inmask is None: - inmask = numpy.ones(self.inshape) - else: - inmask = self.inmask - - if missing is not None: - if rank == 2: - firstslice = ar - elif rank == 3: - firstslice = ar[0] - else: - firstslice = ar[0, 0] - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - firstslice - - missing), - numpy.absolute( - 0.001 * - missing)), - inmask, - 0) - - # If the user mask was specified and is > 2-D, it overrides the grid - # mask - else: - assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' - inmask = mask - flag2D = 0 # 2-D user masks are handled above - # If armask is derived from the input array, it is probably consistent - # with the missing value - don't bother recalculating it - if missing is not None and armask is None: - # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), - # numpy.absolute( 0.001*missing)), inmask) - if issubclass(ar.dtype.type, numpy.floating): - inmask = numpy.where( - numpy.greater( - numpy.absolute( - ar - missing), - numpy.absolute( - 0.001 * missing)), - inmask, - 0) - # Cast the mask to float - inmask = inmask.astype(numpy.float32) - if missing is None: - missing = 1.0e20 - - # Cast the input array to 32-bit floats, if necessary - if ar.dtype.char != numpy.float32: - ar = ar.astype(numpy.float32) - - # Malloc return array - outshape = list(shape) - outshape[rank - ilat - 1] = self.nlato - outshape[rank - ilon - 1] = self.nlono - outar = numpy.zeros(tuple(outshape), numpy.float32) - - # Perform the regridding. The return array has the same shape - # as the output array, and is the fraction of the zone which overlaps - # a non-masked zone of the input grid. - amskout = _regrid.rgdarea( - ilon, - ilat, - itim1, - itim2, - ntim1, - ntim2, - nloni, - self.nlono, - nlati, - self.nlato, - flag2D, - missing, - self.londx, - self.lonpt, - self.wtlon, - self.latdx, - self.latpt, - self.wtlat, - inmask, - ar, - outar) - - # Correct the shape of output weights - amskout.shape = outar.shape - - # Set the missing data mask of the output array, if any. - hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) - if hasMissing: - slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) - else: - slabMask = None - - # Combine missing data mask and output grid mask - # Note: slabMask and outmask are Boolean here - if self.outmask is not None: - outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) - if hasMissing: - outmask = numpy.ma.logical_or(outmask, slabMask) - else: - outmask = slabMask - - # Create the result TransientVariable (if input ar is an AbstractVariable) - # or masked array - if inputIsVariable == 1: - for i in range(len(order)): - if order[i] == 'x': - axislist[i] = self.outlon - elif order[i] == 'y': - axislist[i] = self.outlat - result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array( - outar, mask=outmask, fill_value=missing) - - if returnTuple == 0: - return result - else: - return result, amskout - - -class Regridder(Horizontal): - def __init__(self, ingrid, outgrid): - warnings.warn( - "While this will work for now, please note that the Regridder class has been " + - "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + - "Please edit your code accordingly", - Warning) - Horizontal.__init__(self, ingrid, outgrid) - - -def input_mask(ain, type, mask, missing=None): - """ #------------------------------------------------------------------- - # - # purpose: set up the input mask including missing from ain - # - # usage: - # - # passed : - # - # returned: - # - # - #------------------------------------------------------------------------""" - if type != 'h' and type != 'v': - raise ValueError('Mask type must be h or v') - return - - if missing is None: - try: - omit = ain.missing_value - except AttributeError: - omit = 1.0e20 - else: - omit = missing - - # ----- insert 0.0 in mask where array has missing data ------- - - mask_size = len(mask.shape) - data_size = len(ain.shape) - - if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a - - if data_size == 3: # caution: assuming standard order lat-lon varying the fastest - if type == 'h': - reduced = ain[0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[:, :, 0] - elif data_size == 4: - if type == 'h': - reduced = ain[0, 0, :, :] - elif type == 'v': - # removes lats dummy latitude - reduced = ain[0, :, :, 0] - else: - raise IndexError('Data size is out of range') - return - - amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - else: # 0.0 -> missing in passed mask - - amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) - amskin = amskin.astype(numpy.float32) - - return omit, amskin diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py deleted file mode 100644 index 235e1fd5..00000000 --- a/regrid2/Lib/mvESMFRegrid.py +++ /dev/null @@ -1,483 +0,0 @@ -""" -ESMF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import re -import numpy - -import ESMF -from . import esmf -from . import RegridError -from .mvGenericRegrid import GenericRegrid - -ESMF.Manager(debug=False) -HAVE_MPI = False -try: - from mpi4py import MPI - HAVE_MPI = True -except BaseException: - pass - -# constants -CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER -CORNER = ESMF.StaggerLoc.CORNER -VCORNER = ESMF.StaggerLoc.CORNER_VFACE -VFACE = VCORNER -CONSERVE = ESMF.RegridMethod.CONSERVE -PATCH = ESMF.RegridMethod.PATCH -BILINEAR = ESMF.RegridMethod.BILINEAR -IGNORE = ESMF.UnmappedAction.IGNORE -ERROR = ESMF.UnmappedAction.ERROR - - -class ESMFRegrid(GenericRegrid): - """ - Regrid class for ESMF - """ - - def __init__(self, srcGridshape, dstGridshape, dtype, - regridMethod, staggerLoc, periodicity, coordSys, - srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, - dstGridMask=None, hasDstBounds=False, dstGridAreas=None, - ignoreDegenerate=False, - **args): - """ - Constructor - @param srcGridShape tuple source grid shape - @param dstGridShape tuple destination grid shape - @param dtype a valid numpy data type for the src/dst data - @param regridMethod 'linear', 'conserve', or 'patch' - @param staggerLoc the staggering of the field, 'center' or 'corner' - @param periodicity 0 (no periodicity), - 1 (last coordinate is periodic, - 2 (both coordinates are periodic) - @param coordSys 'deg', 'cart', or 'rad' - @param hasSrcBounds tuple source bounds shape - @param hasDstBounds tuple destination bounds shape - @param ignoreDegenerate Ignore degenerate celss when checking inputs - """ - - # esmf grid objects (tobe constructed) - self.srcGrid = None - self.dstGrid = None - self.dtype = dtype - - self.srcGridShape = srcGridshape - self.dstGridShape = dstGridshape - self.ignoreDegenerate = ignoreDegenerate - self.ndims = len(self.srcGridShape) - - self.hasSrcBounds = hasSrcBounds - self.hasDstBounds = hasDstBounds - - self.regridMethod = BILINEAR - self.regridMethodStr = 'linear' - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.regridMethod = CONSERVE - self.regridMethodStr = 'conserve' - elif re.search('patch', regridMethod.lower()): - self.regridMethod = PATCH - self.regridMethodStr = 'patch' - - # data stagger - self.staggerloc = CENTER - self.staggerlocStr = 'center' - if isinstance(staggerLoc, str): - if re.search('vface', staggerLoc.lower(), re.I): - self.staggerloc = VFACE - self.staggerlocStr = 'vcorner' - # there are other staggers we could test here - elif re.search('corner', staggerLoc.lower(), re.I) or \ - re.search('node', staggerLoc.lower(), re.I): - self.staggerloc = CORNER - self.staggerlocStr = 'corner' - # there are other staggers we could test here - - # good for now - unMappedAction = args.get('unmappedaction', 'ignore') - self.unMappedAction = ESMF.UnmappedAction.IGNORE - if re.search('error', unMappedAction.lower()): - self.unMappedAction = ESMF.UnmappedAction.ERROR - - self.coordSys = ESMF.CoordSys.SPH_DEG - self.coordSysStr = 'deg' - if re.search('cart', coordSys.lower()): - self.coordSys = ESMF.CoordSys.CART - self.coordSysStr = 'cart' - elif re.search('rad', coordSys.lower()): - self.coordSys = ESMF.CoordSys.SPH_RAD - self.coordSysStr = 'rad' - - self.periodicity = periodicity - - # masks can take several values in ESMF, we'll have just one - # value (1) which means invalid -# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) -# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) - - if isinstance(regridMethod, str): - if re.search('conserv', regridMethod.lower()): - self.srcMaskValues = numpy.array([1], dtype=numpy.int32) - self.dstMaskValues = numpy.array([1], dtype=numpy.int32) - else: - self.srcMaskValues = srcGridMask - self.dstMaskValues = dstGridMask - - # provided by user or None - self.srcGridAreas = srcGridAreas - self.dstGridAreas = dstGridAreas - self.maskPtr = None - - # MPI stuff - self.pe = 0 - self.nprocs = 1 - self.comm = None - if HAVE_MPI: - self.comm = MPI.COMM_WORLD - self.pe = self.comm.Get_rank() - self.nprocs = self.comm.Get_size() - - # checks - if self.ndims != len(self.dstGridShape): - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological -dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ - (self.ndims, len(self.dstGridShape)) - raise RegridError(msg) - - # Initialize the grids without data. - self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasSrcBounds) - self.dstGrid = esmf.EsmfStructGrid(dstGridshape, - coordSys=self.coordSys, - periodicity=self.periodicity, - staggerloc=self.staggerloc, - hasBounds=self.hasDstBounds) - - # Initialize the fields with data. - self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - - self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', - datatype=self.dtype, - staggerloc=self.staggerloc) - self.srcFld.field.data[:] = -1 - self.dstFld.field.data[:] = -1 - self.srcAreaField.field.data[:] = 0.0 - self.dstAreaField.field.data[:] = 0.0 - self.srcFracField.field.data[:] = 1.0 - self.dstFracField.field.data[:] = 1.0 - - def setCoords(self, srcGrid, dstGrid, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - globalIndexing=False, **args): - """ - Populator of grids, bounds and masks - @param srcGrid list [[z], y, x] of source grid arrays - @param dstGrid list [[z], y, x] of dstination grid arrays - @param srcGridMask list [[z], y, x] of arrays - @param srcBounds list [[z], y, x] of arrays - @param srcGridAreas list [[z], y, x] of arrays - @param dstGridMask list [[z], y, x] of arrays - @param dstBounds list [[z], y, x] of arrays - @param dstGridAreas list [[z], y, x] of arrays - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - """ - - # create esmf source Grid - self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - - if srcGridMask is not None: - self.srcGrid.setMask(srcGridMask, self.staggerloc) - - if srcBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - # VCORNER for 3D - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - # cell field, need to provide the bounds - self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - # create destination Grid - self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, - globalIndexing=globalIndexing) - if dstGridMask is not None: - self.dstGrid.setMask(dstGridMask) - - if dstBounds is not None: - # Coords are CENTER (cell) based, bounds are CORNER (nodal) - if self.staggerloc != CORNER and self.staggerloc != VCORNER: - if self.ndims == 2: - self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, - globalIndexing=globalIndexing) - if self.ndims == 3: - self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, - globalIndexing=globalIndexing) - elif self.staggerloc == CORNER or self.staggerloc == VCORNER: - msg = """ -mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for -staggerLoc = %s!""" % self.staggerLoc - raise RegridError(msg) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args (not used) - """ - self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, - dstfield=self.dstFld.field, - src_mask_values=self.srcMaskValues, - dst_mask_values=self.dstMaskValues, - regrid_method=self.regridMethod, - unmapped_action=self.unMappedAction, - ignore_degenerate=True) - - def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): - """ - Regrid source to destination. - When used in parallel, if the processor is not the root processor, - the dstData returns None. - - Source data mask: - - . If you provide srcDataMask in args the source grid will - be masked and weights will be recomputed. - - . Subsequently, if you do not provide a srcDataMask the last - weights will be used to regrid the source data array. - - . By default, only the data are masked, but not the grid. - - @param srcData array source data, shape should - cover entire global index space - @param dstData array destination data, shape should - cover entire global index space - @param rootPe if other than None, then data will be MPI gathered - on the specified rootPe processor - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - @param **args - """ - -# if args.has_key('srcDataMask'): -# srcDataMask=args.get('srcDataMask') - # Make sure with have a mask intialized for this grid. - -# if(self.maskPtr is None): -# if(self.srcFld.field.grid.mask[self.staggerloc] is None): -# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) -# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, -# staggerloc=self.staggerloc) - # Recompute weights only if masks are different. -# if(not numpy.array_equal(self.maskPtr, srcDataMask)): -# self.maskPtr[:] = srcDataMask[:] -# self.computeWeights(**args) - - zero_region = ESMF.Region.SELECT - if 'zero_region' in args.keys(): - zero_region=args.get('zero_region') - - self.srcFld.field.data[:] = srcData.T - self.dstFld.field.data[:] = dstData.T - # regrid - - self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) - - # fill in dstData - if rootPe is None and globalIndexing: - # only fill in the relevant portion of the data - slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) - dstData[slab] = self.dstFld.getData(rootPe=rootPe) - else: - tmp = self.dstFld.field.data.T - if tmp is None: - dstData = None - else: - dstData[:] = tmp - - def getDstGrid(self): - """ - Get the destination grid on this processor - @return grid - """ - return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) - for i in range(self.ndims)] - - def getSrcAreas(self, rootPe): - """ - Get the source grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.srcAreaField.field.get_area() - return self.srcAreaField.field.data - else: - return None - - def getDstAreas(self, rootPe): - """ - Get the destination grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation - """ - if self.regridMethod == CONSERVE: - # self.dstAreaField.field.get_area() - return self.dstAreaField.field.data - else: - return None - - def getSrcAreaFractions(self, rootPe): - """ - Get the source grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.srcFracField.field.data - else: - return None - - def getDstAreaFractions(self, rootPe): - """ - Get the destination grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) - """ - if self.regridMethod == CONSERVE: - return self.dstFracField.field.data - else: - return - - def getSrcLocalShape(self, staggerLoc): - """ - Get the local source coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getCoordShape(stgloc) - - def getDstLocalShape(self, staggerLoc): - """ - Get the local destination coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getCoordShape(stgloc) - - def getSrcLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center'): - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.srcGrid.getLocalSlab(stgloc) - - def getDstLocalSlab(self, staggerLoc): - """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center') - @return tuple of slices - """ - stgloc = CENTER - if re.match('corner', staggerLoc, re.I) or \ - re.search('nod', staggerLoc, re.I): - stgloc = CORNER - elif re.search('vface', staggerLoc, re.I) or \ - re.search('vcorner', staggerLoc, re.I): - stgloc = VFACE - return self.dstGrid.getLocalSlab(stgloc) - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'srcAreaFractions', 'dstAreaFractions', - 'srcAreas', 'dstAreas' - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - oldMethods = {} - oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' - oldMethods['dstAreaFractions'] = 'getDstAreaFractions' - oldMethods['srcAreas'] = 'getSrcAreas' - oldMethods['dstAreas'] = 'getDstAreas' - for entry in 'srcAreaFractions', 'dstAreaFractions', \ - 'srcAreas', 'dstAreas': - if entry in diag: - diag[entry] = eval( - 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T - diag['regridTool'] = 'esmf' - diag['regridMethod'] = self.regridMethodStr - diag['periodicity'] = self.periodicity - diag['coordSys'] = self.coordSysStr - diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py deleted file mode 100644 index 2452e9c4..00000000 --- a/regrid2/Lib/mvGenericRegrid.py +++ /dev/null @@ -1,313 +0,0 @@ -""" -Generic interface to multiple regrid classes. No dependence on cdms2 variables. - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" -import operator -import numpy - -import regrid2 -import re -from distarray import MultiArrayIter -from functools import reduce - -# used to locate fully masked cells -EPS = 10 * 1.19209e-07 - - -def guessPeriodicity(srcBounds): - """ - Guess if a src grid is periodic - @param srcBounds the nodal src set of coordinates - @return 1 if periodic, warp around, 0 otherwise - """ - res = 0 - if srcBounds is not None: - res = 1 - # assume longitude to be the last coordinate - lonsb = srcBounds[-1] - nlon = lonsb.shape[-1] - dlon = (lonsb.max() - lonsb.min()) / float(nlon) - tol = 1.e-2 * dlon - if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] - ).sum() / float(lonsb.size)) > tol: - # looks like a regional model - res = 0 - return res - - -class GenericRegrid: - """ - Generic Regrid class. - """ - - def __init__(self, srcGrid, dstGrid, - dtype, - regridMethod, - regridTool, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - **args): - """ - Constructor. - @param srcGrid list of numpy arrays, source horizontal coordinates - @param dstGrid list of numpy arrays, destination horizontal coordinate - @param dtype numpy data type for src/dst data - @param regridMethod linear (bi, tri,...) default or conservative - @param regridTool currently either 'libcf' or 'esmf' - @param srcGridMask array of same shape as srcGrid - @param srcBounds list of numpy arrays of same shape as srcGrid - @param srcGridAreas array of same shape as srcGrid - @param dstGridMask array of same shape as dstGrid - @param dstBounds list of numpy arrays of same shape as dstGrid - @param dstGridAreas array of same shape as dstGrid - @param **args additional arguments to be passed to the - specific tool - 'libcf': mkCyclic={True, False}, handleCut={True,False} - 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... - """ - - self.nGridDims = len(srcGrid) - self.regridMethod = regridMethod - - if len(srcGrid) != len(dstGrid): - msg = 'mvGenericRegrid.__init__: mismatch in number of dims' - msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ - (self.nGridDims, len(dstGrid)) - raise regrid2.RegridError(msg) - - # parse the options - if re.search('libcf', regridTool.lower()) or \ - re.search('gsreg', regridTool.lower()): - # LibCF - self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - **args) - elif re.search('esm', regridTool.lower()): - # ESMF - staggerLoc = args.get('staggerLoc', 'center') - if 'staggerLoc' in args: - del args['staggerLoc'] - periodicity = args.get('periodicity', - guessPeriodicity(srcBounds)) - if 'periodicity' in args: - del args['periodicity'] - coordSys = args.get('coordSys', 'deg') - if 'coordSys' in args: - del args['coordSys'] - - # Get the shapes - self.srcGridShape = srcGrid[0].shape - self.dstGridShape = dstGrid[0].shape - self.hasSrcBounds = False - self.hasDstBounds = False - - if srcBounds is not None: - self.hasSrcBounds = True - - if dstBounds is not None: - self.hasDstBounds = True - - self.srcGridAreasShape = None - self.dstGridAreasShape = None - - if srcGridAreas is not None: - self.srcGridAreasShape = srcGridAreas[0].shape - - if dstGridAreas is not None: - self.dstGridAreasShape = dstGridAreas[0].shape - - # Initialize - self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, - dtype=dtype, - regridMethod=regridMethod, - staggerLoc=staggerLoc, - periodicity=periodicity, - coordSys=coordSys, - hasSrcBounds=self.hasSrcBounds, - hasDstBounds=self.hasDstBounds, - srcGridAreasShape=self.srcGridAreasShape, - dstGridAreasShape=self.dstGridAreasShape, - **args) - - self.tool.setCoords(srcGrid, dstGrid, - srcGridMask=srcGridMask, - srcBounds=srcBounds, - srcGridAreas=srcGridAreas, - dstGridMask=dstGridMask, - dstBounds=dstBounds, - dstGridAreas=dstGridAreas, - globalIndexing=True, - **args) - else: - msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, -valid choices are: 'libcf', 'esmf'""" % regridTool - raise regrid2.RegridError(msg) - - def computeWeights(self, **args): - """ - Compute Weights - """ - self.tool.computeWeights(**args) - - def apply(self, srcData, dstData, - rootPe=None, - missingValue=None, - **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param rootPe if other than None, then results will be MPI - gathered - @param missingValue if not None, then data mask will be interpolated - and data value set to missingValue when masked - """ - - # assuming the axes are the slowly varying indices - srcHorizShape = srcData.shape[-self.nGridDims:] - dstHorizShape = dstData.shape[-self.nGridDims:] - - srcDataMaskFloat = None - dstDataMaskFloat = None - dstMask = None - if missingValue is not None: - srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) - dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) - - nonHorizShape = srcData.shape[: -self.nGridDims] - - if len(nonHorizShape) == 0: - - # - # no axis... just call apply - # - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (srcData == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later - indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), - dtype=srcData.dtype) - - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, **args) - if re.search('conserv', self.regridMethod.lower(), re.I): - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) - - # Initialize output to missin_value - dstData[:] = missingValue - # interpolate the data - self.tool.apply(indata, dstData, rootPe=rootPe, - globalIndexing=True, **args) - - # add missing values - dstData *= (1 - dstMask) - dstData += dstMask * missingValue - - else: - # no masking, just interpolate the data - self.tool.apply(srcData, dstData, rootPe=rootPe, - globalIndexing=True, **args) - else: - - nonHorizShape2 = dstData.shape[: -self.nGridDims] - if not numpy.all(nonHorizShape2 == nonHorizShape): - msg = 'mvGenericRegrid.apply: axes detected ' - msg += 'but %s != %s ' % (str(nonHorizShape2), - str(nonHorizShape)) - raise regrid2.RegridError(msg) - - # - # iterate over all axes - # - - # create containers to hold input/output values - # (a copy is essential here) - zros = '[' + ('0,' * len(nonHorizShape)) + '...]' - indata = numpy.array(eval('srcData' + zros)) - outdata = numpy.array(eval('dstData' + zros)) - - # now iterate over all non lat/lon coordinates - for it in MultiArrayIter(nonHorizShape): - - indices = it.getIndices() - slce = '[' - slce += reduce(operator.add, ['%d,' % i for i in indices]) - slce += '...]' - indata = eval('srcData' + slce) - - # adjust for masking - if missingValue is not None: - - srcDataMaskFloat[:] = (indata == missingValue) - - # set field values to zero where missing, we'll add the mask - # contribution later -# indata *= (1 - (srcDataMaskFloat == 1)) - -# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 - # interpolate mask - self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, - rootPe=rootPe, globalIndexing=True, - srcDataMask=(1 - srcDataMaskFloat), **args) - - if re.search('conserv', self.regridMethod.lower(), re.I): - # cell interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 1 - EPS), numpy.int32) - else: - # nodal interpolation - dstMask = numpy.array( - (dstDataMaskFloat > 0), numpy.int32) - - # interpolate the data, using the appropriate tool - self.tool.apply(indata, outdata, rootPe=rootPe, - globalIndexing=True, - srcDataMask=srcDataMaskFloat, **args) - -# import vcs -# pp = vcs.init() -# pp.plot(indata) -# pp.interact() -# pp.clear() -# pp.plot(outdata) -# pp.interact() -# pp.clear() - # apply missing value contribution - if missingValue is not None: - # add mask contribution - outdata *= (1 - dstMask) - outdata += dstMask * missingValue - - # fill in dstData - exec('dstData' + slce + ' = outdata') - - def getDstGrid(self): - """ - Return the destination grid, may be different from the dst grid provided - to the constructor due to domain decomposition - @return local grid on this processor - """ - return self.tool.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe=None): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - entries are tool dependent - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - """ - self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py deleted file mode 100644 index 30c5f4bf..00000000 --- a/regrid2/Lib/mvLibCFRegrid.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -LibCF regridding class - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -""" - -from regrid2 import gsRegrid -from regrid2 import GenericRegrid - - -class LibCFRegrid(GenericRegrid): - """ - """ - - def __init__(self, srcGrid, dstGrid, srcGridMask=None, - srcBounds=None, **args): - """ - Constructor - @param srcGrid array - @param dstGrid array - @param srcBounds cell boundaries - @param **args keyword arguments, eg mkCyclic, handleCut, ... - to be passed to gsRegrid - """ - self.regridMethodStr = 'linear' - self.mkCyclic = args.get('mkCyclic', False) - self.handleCut = args.get('handleCut', False) - self.verbose = args.get('verbose', False) - self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, - src_bounds=srcBounds, - mkCyclic=self.mkCyclic, - handleCut=self.handleCut) - if srcGridMask is not None: - self.regridObj.setMask(srcGridMask) - - # min resolution, required in order to set the tolerance (tolpos) - self.delta = float('inf') - for i in range(len(dstGrid)): - coordMin = dstGrid[i].min() - coordMax = dstGrid[i].max() - n = max(dstGrid[i].shape) - self.delta = min(self.delta, (coordMax - coordMin) / float(n)) - - def computeWeights(self, **args): - """ - Compute interpolation weights - @param **args arguments to be passed to gsRegrid, e.g. - nitermax, tolpos, ... - """ - nitermax = args.get('nitermax', 20) - # make tolpos relative to the min cell size - tolpos = args.get('tolpos', 0.01) * self.delta - self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) - - def apply(self, srcData, dstData, missingValue=None, **args): - """ - Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param missingValue value that should be set for points falling outside - the src domain, pass None if these should not be - touched. - """ - - self.regridObj.apply(srcData, dstData, missingValue) - - def getSrcGrid(self): - """ - Get the grid of the src data (maybe larger than the - dst grid passed to the constructor due to column/row - padding) - @return grid - """ - return self.regridObj.getSrcGrid() - - def getDstGrid(self): - """ - Get the grid of the dst data - @return grid - """ - return self.regridObj.getDstGrid() - - def fillInDiagnosticData(self, diag, rootPe): - """ - Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'numDstPoints' and 'numValid' - @param rootPe not used - """ - for entry in 'numDstPoints', 'numValid': - if entry in diag: - meth = 'get' + entry[0].upper() + entry[1:] - diag[entry] = eval('self.regridObj.' + meth + '()') - diag['regridTool'] = 'libcf' - diag['regridMethod'] = self.regridMethodStr - diag['handleCut'] = self.handleCut - diag['mkCyclic'] = self.mkCyclic - diag['verbose'] = self.verbose diff --git a/regrid2/Lib/mytest.py b/regrid2/Lib/mytest.py deleted file mode 100644 index e91d1361..00000000 --- a/regrid2/Lib/mytest.py +++ /dev/null @@ -1,2 +0,0 @@ -import ESMF # noqa -from .mvESMFRegrid import ESMFRegrid # noqa diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py deleted file mode 100644 index fb79a9e2..00000000 --- a/regrid2/Lib/pressure.py +++ /dev/null @@ -1,490 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by -import cdms2 -import numpy -#from . import _regrid -import regrid2._regrid as _regrid -from .error import RegridError -import copy - - -class PressureRegridder: - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along - # the pressure dimension only. - # - # PROCEDURE: Step One: - # Make an instance of class PressureRegridder passing it input and output grid information - # Step Two: - # Pass the input data with some descriptive parameters and get the output data - # in return - # - #------------------------------------------------------------------------------------------------""" - - def __init__(self, axisIn, axisOut): - """ #----------------------------------------------------------------------------------------------- - # - # PURPOSE: To make an instance which entails setting up the input and output grids - # - # DEFINITION: - # - # def __init__(self, levIn, levOut): - # - # PROCEDURE: - # - # The user must assemble two pieces of information: - # - # axisIn - the input level axis - # - # axisOut - the output level axis - # - # USAGE: - # - # To make an instance preparing for a regrid along the level dimension pnly, type - # - # r = PressureRegridder(levIn, levOut) - # - #------------------------------------------------------------------------------------------------""" - - # --- set the instance grid data attributes used to describe input and output grid sizes - - self.axisIn = axisIn - self.axisOut = axisOut - self.nlevi = len(axisIn) - self.nlevo = len(axisOut) - - def __call__(self, ar, missing=None, order=None, method="log"): - """ - Call the pressure regridder function. - ar is the input array, a variable, masked array, or numpy array. - missing is the missing data value, if any. It defaults to the missing/fill value - defined for the input array, if any. - order is of the form "tzyx", "tyx", etc. - method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. - """ - - from cdms2.avariable import AbstractVariable - from cdms2.tvariable import TransientVariable - - # Save Variable metadata for output - if isinstance(ar, AbstractVariable): - attrs = copy.copy(ar.attributes) - varid = ar.id - axislist = ar.getAxisList() - inputIsVariable = 1 - if order is None: - order = ar.getOrder() - # this expects contiguous arrays - if isinstance( - ar, TransientVariable) and ar.iscontiguous() is False: - ar = ar.ascontiguous() - else: - inputIsVariable = 0 - - # Turn ar into a numpy array. - if numpy.ma.isMaskedArray(ar): - armiss = ar.fill_value - ar = numpy.ma.filled(ar) - elif isinstance(ar, AbstractVariable): - tempar = ar.getValue(squeeze=0) - armiss = ar.getMissing() - ar = numpy.ma.filled(tempar) - elif isinstance(ar, numpy.ndarray): - armiss = None - else: - raise RegridError( - "Input array is not a Variable, numpy.ma, or numpy array") - - # Set missing value - if missing is None: - missing = armiss - if isinstance(missing, numpy.ndarray): - missing = missing[0] - - rank = len(ar.shape) - assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank - - # Set the default order to match the input grid order - if order is None: - if rank == 3: - order = "zyx" - elif rank == 4: - order = "tzyx" - - assert rank == len( - order), 'Order must be same length as array rank: %i' % len(ar.shape) - - order = order.lower() - - # Map order to positionIn - positionIn = [None] * 4 - for i in range(len(order)): - if order[i] == 'x': - positionIn[0] = i - elif order[i] == 'y': - positionIn[1] = i - elif order[i] == 'z': - positionIn[2] = i - if inputIsVariable: - axislist[i] = self.axisOut - else: - positionIn[3] = i - - # Regrid - if method == 'log': - logYes = 'yes' - else: - logYes = 'no' - outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) - - # Reconstruct the same class as on input - if inputIsVariable == 1: - result = cdms2.createVariable(outar, fill_value=missing, - axes=axislist, attributes=attrs, id=varid) - else: - result = numpy.ma.masked_array(outar, fill_value=missing) - - return result - - def rgrd(self, dataIn, missingValueIn, missingMatch, - logYes='yes', positionIn=None, missingValueOut=None): - """ #--------------------------------------------------------------------------------- - # - # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, - # dataout along the level dimension only. - # - # DEFINITION: - # - # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): - # - # - # PASSED : dataIn -- data to regrid - # - # missingValueIn -- the missing data value to use in setting missing in the mask. It is required - # and there are two choices: - # None -- there is no missing data - # A number -- the value to use in the search for possible missing data. - # The presence of missing data at a grid point leads to recording 0.0 in the mask. - # - # missingMatch -- the comparison scheme used in searching for missing data in dataIn using - # the value passed in as missingValueIn. The choices are: - # None -- used if None is the entry for missingValueIn - # exact -- used if missingValue is the exact value from the file - # greater -- the missing data value is equal to or greater than missingValueIn - # less -- the missing data value is equal to or less than missingValueIn - # - # logYes -- choose the level regrid as linear in log of level or linear in level. Set to - # 'yes' for log. Anything else is linear in level. - # - # - # - # positionIn -- a tuple with the numerical position of the dimensions - # in C or Python order specified in the sequence longitude, - # latitude, level and time. Longitude, latitude and level are - # required. If time is missing submit None in its slot in the - # tuple. Notice that the length of the tuple is always four. - # - # Explicitly, in terms of the shape of dataIn as returned by Python's shape function - # - # positionIn[0] contains the position of longitude in dataIn - # positionIn[1] contains the position of latitude in dataIn - # positionIn[2] contains the position of level in dataIn or None - # positionIn[3] contains the position of time in dataIn or None - # - # As examples: - # If the C order shape of 4D data is - # (number of longitudes, number of times, number of levels, - # number of latitudes) - # submit - # (0, 3, 2, 1) - # - # If the C order shape of 3D data is - # (number of longitudes, number of times, number oflatitudes) - # submit - # (0, 2, 1, None) - # - # Send in None if the shape is a subset of (time, level, - # latitude, longitude) which is evaluated as follows: - # 3D -- code assumes (2,1,0,None) - # 4D -- code assumes (3,2,1,0) - # - # missingValueOut -- the value for the missing data used in writing the output data. If left at the - # default entry, None, the code uses missingValueIn if present or as a last - # resort - # 1.0e20 - # - # - # RETURNED : dataOut -- the regridded data - # - # - # USAGE: - # - # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no - # missing data. - # dataOut = x.rgrd(dataIn, None, None) - # - # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data - # - # dataOut = x.rgrd(dataIn, 1.e20, 'greater') - # - # ----------------------------------------------------------------------------------------------------------""" - - # check the required input -- dataIn, missingValueIn and missingMatch - - # make sure that dataIn is an array - - try: - len(dataIn) - except TypeError: - sendmsg('Error in calling the rgrd method -- dataIn must be an array') - raise TypeError - - # check the missingValueIn pass - - if missingValueIn is not None: - try: - abs(missingValueIn) - except TypeError: - sendmsg( - 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', - missingValueIn) - raise TypeError - - # check the missingMatch pass - - missingPossibilities = ['greater', 'equal', 'less', None] - if missingMatch not in missingPossibilities: - msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' - sendmsg(msg, missingMatch) - raise ValueError - - # --- Check data type and change to float if necessary ---- - - if dataIn.dtype.char != 'f': - dataIn = dataIn.astype(numpy.float32) - - dataShape = dataIn.shape - numberDim = len(dataShape) - - if numberDim < 2: - msg = 'Error in call to rgrd -- data must have at least 2 dimensions' - sendmsg(msg) - raise TypeError - - # --- evaluate positionIn ---- - - # --- make standard positionIn as a check---- - positionList = [] - for n in range(numberDim): # insert a sequence of numbers - positionList.append(n) - positionList.reverse() - - for n in range(numberDim, 4): # fill end of list with Nones - positionList.append(None) - - positionCheck = tuple(positionList) - - standardPosition = 0 # transpose required - - if positionIn is None: # construct the default positionIn tuple - positionIn = positionCheck - standardPosition = 1 # no need for a transpose with this data - else: - if positionIn == positionCheck: # compare to the standard - standardPosition = 1 # no need for a transpose with this data - - if len(positionIn) != 4: - msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' - sendmsg(msg) - raise TypeError - - # transpose data to the standard order (t,z,y,x) - if standardPosition == 0: - - newOrder, inverseOrder = checkorder(positionIn) - - # transpose data to standard order (t,z,y,x) - dataIn = numpy.transpose(dataIn, newOrder) - dataIn = numpy.array( - dataIn.astype( - numpy.float32), - numpy.float32) # make contiguous - - # set dimension sizes and check for consistency - - if positionIn[0] is not None: - self.nlon = (dataShape[positionIn[0]]) - else: - self.nlon = 0 - if positionIn[1] is not None: - self.nlat = (dataShape[positionIn[1]]) - else: - self.nlat = 0 - if positionIn[2] is not None: - if self.nlevi != (dataShape[positionIn[2]]): - msg = 'Level size is inconsistent with input data' - sendmsg(msg) - raise ValueError - if positionIn[3] is not None: - self.ntime = (dataShape[positionIn[3]]) - else: - self.ntime = 0 - - # allocate memory for dataOut -- the array with new number of levels - - outList = list(dataIn.shape) - - for i in range(len(outList)): - if outList[i] == self.nlevi: - outList[i] = self.nlevo - break - - dataOut = numpy.zeros( - tuple(outList), - numpy.float32) # memory for aout - - if missingMatch is None: # if no missing do not pass None - missingMatch = 'none' - - # if no missing do not pass None - if missingValueIn is None: - missingValueIn = 1.333e33 - - if logYes != 'yes': - logYes = 'no' - - levIn = self.axisIn[:].astype(numpy.float64) - levOut = self.axisOut[:].astype(numpy.float64) - _regrid.rgdpressure( - self.nlevi, - self.nlevo, - self.nlat, - self.nlon, - self.ntime, - missingValueIn, - missingMatch, - logYes, - levIn, - levOut, - dataIn, - dataOut) - - # if no missing do not pass None - if missingMatch == 'none': - missingMatch = None - if missingValueIn == 1.333e33: - missingValueIn = None - - if standardPosition == 0: - # transpose data to original order - dataOut = numpy.transpose(dataOut, inverseOrder) - dataOut = numpy.array( - dataOut.astype( - numpy.float32), - numpy.float32) # make contiguous - - if missingValueOut is not None: # set the missing value in data to missingValueOut - - if missingMatch == 'greater': - if missingValueIn > 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.greater( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'equal': - missing = missingValueIn - dataOut = numpy.where( - numpy.equal( - dataOut, - missing), - missingValueOut, - dataOut) - - elif missingMatch == 'less': - if missingValueIn < 0.0: - missing = 0.99 * missingValueIn - else: - missing = 1.01 * missingValueIn - - dataOut = numpy.where( - numpy.less( - dataOut, - missing), - missingValueOut, - dataOut) - - return dataOut - - -def checkorder(positionIn): - """ #----------------------------------------------------------------------------------------- - # - # purpose: construct the tuples for transposing the data to standard dimension order and the - # inverse for transposing it back to the original dimension order - # - # usage: newOrder, inverseOrder = checkorder(positionIn) - # - # passed: positionIn -- array with location of longitude, latitude. level and time respectively - # in the sense of the python shape of the data - # - # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) - # inverseOrder -- tuple to transpose data to back to the original order - # - #----------------------------------------------------------------------------------------------""" - - # remove the None values from positionIn and reverse the order - - reducedPosition = [] - for item in positionIn: - if item is not None: - reducedPosition.append(item) - reducedPosition.reverse() - - # make the newOrder tuple - - newOrder = tuple(reducedPosition) - - # ----- Determine the inverse to this new order for use in mathtogeo ----- - - xform = [] - for i in range(len(newOrder)): - xform.append([newOrder[i], i]) - xform.sort() - - inverse_shapelist = [] - for item in xform: - inverse_shapelist.append(item[1]) - inverseOrder = tuple(inverse_shapelist) - - return newOrder, inverseOrder - - -def sendmsg(msg, value1=None, value2=None): - """ #--------------------------------------------------------------------------------- - # - # purpose: send the same message to the screen - # - # passed : msg - the string - # value - the number associated with the string - # - # returned: return - # - #---------------------------------------------------------------------------------""" - - print('*******************************************************************') - if value1 is None: - print(msg) - elif value2 is None: - print((msg, value1)) - else: - print((msg, value1, value2)) - print('*******************************************************************') - - return None diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py deleted file mode 100644 index 5a052700..00000000 --- a/regrid2/Lib/scrip.py +++ /dev/null @@ -1,447 +0,0 @@ -# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by - -import cdms2 -#from . import _scrip -import regrid2._scrip as _scrip -from .error import RegridError -import numpy -from functools import reduce - -"""Regrid support for nonrectangular grids, based on the SCRIP package.""" - - -class ScripRegridder: - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - self.outputGrid = outputGrid - self.remapMatrix = remapMatrix - self.sourceAddress = sourceAddress - self.destAddress = destAddress - self.inputGrid = inputGrid - self.sourceFrac = sourceFrac - self.destFrac = destFrac - - def __call__(self, input): - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - # this expects contiguous arrays - if input.iscontiguous() is False: - input = input.ascontiguous() - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - - # Regrid - output = self.regrid(input) - - # Reshape output and restore input shape - input.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - def getOutputGrid(self): - return self.outputGrid - - def getInputGrid(self): - return self.inputGrid - - def getSourceFraction(self): - return self.sourceFrac - - def getDestinationFraction(self): - return self.destFrac - - -class ConservativeRegridder(ScripRegridder): - """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' - is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length - as the output grid size, with values: - 1.0 for normalize="fracarea", - grid_frac for normalize="destarea", or - grid_frac*grid_area for normalize="none". - sourceArea is the area of the source grid cells - destArea is the area of the destination grid cells - """ - - def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, - sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): - if normalize not in ["fracarea", "destarea", "none"]: - raise RegridError("Invalid normalization option: %s" % normalize) - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - self.normalize = normalize - self.normal = None - self.sourceArea = sourceArea - self.destArea = destArea - - def getSourceArea(self): - return self.sourceArea - - def getDestinationArea(self): - return self.destArea - - def regrid(self, input): - if self.normal is None: - # print "On input, num_links = %d"%(len(self.sourceAddress)) - # print "On input, nextra = %d"%(input.shape[0]) - # print "On input, ninput = %d"%(input.shape[1]) - # print "On input, noutput = %d"%(self.outputGrid.size()) - # print "On input, shape(input) = %s"%`input.shape` - # print "On input, shape(output) = %s"%`self.outputGrid.shape` - # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` - # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` - # print "On input, shape(dst_address) = - # %s"%`self.destAddress.shape` - result = _scrip.conserv_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - else: - result = _scrip.conserv_regrid_normal( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - self.normal) - return result - - -class BilinearRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.bilinear_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -class BicubicRegridder(ScripRegridder): - """Bicubic regrid.""" - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def __call__(self, input, gradLat, gradLon, gradLatlon): - """gradLat = df/di - gradLon = df/dj - gradLatlon = d(df)/(di)(dj) - """ - - import numpy.ma - from cdms2 import isVariable - from cdms2.tvariable import TransientVariable - - if (gradLat.shape != input.shape or - gradLon.shape != input.shape or - gradLatlon.shape != input.shape): - raise RegridError( - "All input arrays must have shape %s" % - repr( - input.shape)) - - if (not isinstance(gradLat, type(input)) or - not isinstance(gradLon, type(input)) or - not isinstance(gradLatlon, type(input))): - raise RegridError( - "All input arrays must have type %s" % - repr( - type(input))) - - # If input is a variable, make it a TV - if isVariable(input) and not isinstance(input, TransientVariable): - input = input.subSlice() - gradLat = gradLat.subSlice() - gradLon = gradLon.subSlice() - gradLatlon = gradLatlon.subSlice() - - isvar = isinstance(input, TransientVariable) - - if isvar: - domain = tuple(input.getAxisList()) - if self.inputGrid is not None: - ingrid = self.inputGrid - else: - ingrid = input.getGrid() - if ingrid is None: - raise RegridError( - "Input variable must have an associated grid.") - rank = len(ingrid.shape) - gridsize = ingrid.size() - outgridshape = self.outputGrid.shape - - # Check that the grid matches the last dimension(s) of input - if input.shape[-rank:] != ingrid.shape: - raise RegridError( - 'Last dimensions of input array must match grid shape: %s' % - repr( - ingrid.shape)) - - else: - rank = 1 # If not a TV, last dimension is the 'cell' dimension - gridsize = input.shape[-1] - outgridshape = ( - reduce( - lambda x, - y: x * y, - self.outputGrid.shape, - 1), - ) - - # If input is an numpy.ma, make it Numeric - if numpy.ma.isMaskedArray(input): - input = input.filled() - gradLat = gradLat.filled() - gradLon = gradLon.filled() - gradLatlon = gradLatlon.filled() - - restoreShape = input.shape[:-rank] - restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) - oldshape = input.shape - newshape = (restoreLen, gridsize) - input.shape = newshape - gradLat.shape = newshape - gradLon.shape = newshape - gradLatlon.shape = newshape - - # Regrid - output = _scrip.bicubic_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress, - gradLat, - gradLon, - gradLatlon) - - # Reshape output and restore input shape - input.shape = oldshape - gradLat.shape = oldshape - gradLon.shape = oldshape - gradLatlon.shape = oldshape - outshape = restoreShape + outgridshape - output.shape = outshape - - # If the input was a variable, so is the output - if isvar: - outdomain = domain[:-rank] + (self.outputGrid,) - output = TransientVariable(output, axes=outdomain) - - return output - - -class DistwgtRegridder(ScripRegridder): - - def __init__(self, outputGrid, remapMatrix, sourceAddress, - destAddress, inputGrid=None, sourceFrac=None, destFrac=None): - ScripRegridder.__init__( - self, - outputGrid, - remapMatrix, - sourceAddress, - destAddress, - inputGrid=inputGrid, - sourceFrac=sourceFrac, - destFrac=destFrac) - - def regrid(self, input): - result = _scrip.distwgt_regrid( - self.outputGrid.size(), - input, - self.remapMatrix, - self.sourceAddress, - self.destAddress) - return result - - -def readRegridder(fileobj, mapMethod=None, checkGrid=1): - """Read a regridder from an open fileobj. - mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method - defined in the file. - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. - """ - - if isinstance(fileobj, str): - fileobj = cdms2.open(fileobj) - elif not isinstance(fileobj, cdms2.dataset.CdmsFile): - raise RegridError( - "fileobj arguments must be a cdms2 file or a string pointing to a file") - - if mapMethod is None: - mapString = fileobj.map_method.strip().lower() - if mapString[0:12] == "conservative": - mapMethod = "conservative" - elif mapString[0:8] == "bilinear": - mapMethod = "bilinear" - elif mapString[0:7] == "bicubic": - mapMethod = "bicubic" - elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": - mapMethod = "distwgt" - else: - raise RegridError("Unrecognized map method: %s" % mapString) - - convention = 'SCRIP' - if list(fileobj.variables.keys()).count('S'): - convention = 'NCAR' - if convention == 'SCRIP': - remapMatrix = fileobj('remap_matrix').filled() - srcAddress = fileobj('src_address').filled() - dstAddress = fileobj('dst_address').filled() - srcfrac = fileobj('src_grid_frac') - dstfrac = fileobj('dst_grid_frac') - else: - remapMatrix = fileobj('S').filled() - srcAddress = fileobj('col').filled() - dstAddress = fileobj('row').filled() - srcfrac = fileobj('frac_a') - dstfrac = fileobj('frac_b') - ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) - outgrid = fileobj.readScripGrid( - whichGrid="destination", - checkGrid=checkGrid) - - if mapMethod == "conservative": - if convention == 'SCRIP': - srcarea = fileobj('src_grid_area') - dstarea = fileobj('dst_grid_area') - else: # NCAR stuff - if "S2" in list(fileobj.variables.keys()): - remapMatrix = fileobj("S2") - sh = list(remapMatrix.shape) - if len(sh) == 2 and sh[-1] == 2: - sh[-1] = 1 - S = fileobj("S").filled() - S.shape = sh - remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) - srcarea = fileobj('area_a') - dstarea = fileobj('area_b') - regridder = ConservativeRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac, - sourceArea=srcarea, - destArea=dstarea) - elif mapMethod == "bilinear": - regridder = BilinearRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "bicubic": - regridder = BicubicRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - elif mapMethod == "distwgt": - regridder = DistwgtRegridder( - outgrid, - remapMatrix, - srcAddress, - dstAddress, - inputGrid=ingrid, - sourceFrac=srcfrac, - destFrac=dstfrac) - else: - raise RegridError("Unrecognized map method: %s" % mapMethod) - - return regridder From 9275ecd1f6b2c9eaba6cdcd52ed9cabb92797f96 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:00:27 -0700 Subject: [PATCH 098/239] force git.py --- regrid2/Lib/Lib/PET0.ESMF_LogFile | 1 + regrid2/Lib/Lib/__init__.py | 36 + regrid2/Lib/Lib/crossSection.py | 1092 ++++++++++++++++++++++++ regrid2/Lib/Lib/crossSection.py.orig | 1095 ++++++++++++++++++++++++ regrid2/Lib/Lib/error.py | 3 + regrid2/Lib/Lib/esmf.py | 842 ++++++++++++++++++ regrid2/Lib/Lib/gsRegrid.py | 1179 ++++++++++++++++++++++++++ regrid2/Lib/Lib/gs_horizontal.py | 214 +++++ regrid2/Lib/Lib/horizontal.py | 422 +++++++++ regrid2/Lib/Lib/mvESMFRegrid.py | 483 +++++++++++ regrid2/Lib/Lib/mvGenericRegrid.py | 313 +++++++ regrid2/Lib/Lib/mvLibCFRegrid.py | 101 +++ regrid2/Lib/Lib/mytest.py | 2 + regrid2/Lib/Lib/pressure.py | 490 +++++++++++ regrid2/Lib/Lib/scrip.py | 447 ++++++++++ regrid2/Lib/PET0.ESMF_LogFile | 1 + regrid2/Lib/__init__.py | 36 + regrid2/Lib/crossSection.py | 1092 ++++++++++++++++++++++++ regrid2/Lib/crossSection.py.orig | 1095 ++++++++++++++++++++++++ regrid2/Lib/error.py | 3 + regrid2/Lib/esmf.py | 842 ++++++++++++++++++ regrid2/Lib/gsRegrid.py | 1179 ++++++++++++++++++++++++++ regrid2/Lib/gs_horizontal.py | 214 +++++ regrid2/Lib/horizontal.py | 422 +++++++++ regrid2/Lib/mvESMFRegrid.py | 483 +++++++++++ regrid2/Lib/mvGenericRegrid.py | 313 +++++++ regrid2/Lib/mvLibCFRegrid.py | 101 +++ regrid2/Lib/mytest.py | 2 + regrid2/Lib/pressure.py | 490 +++++++++++ regrid2/Lib/scrip.py | 447 ++++++++++ 30 files changed, 13440 insertions(+) create mode 100644 regrid2/Lib/Lib/PET0.ESMF_LogFile create mode 100644 regrid2/Lib/Lib/__init__.py create mode 100644 regrid2/Lib/Lib/crossSection.py create mode 100644 regrid2/Lib/Lib/crossSection.py.orig create mode 100644 regrid2/Lib/Lib/error.py create mode 100644 regrid2/Lib/Lib/esmf.py create mode 100644 regrid2/Lib/Lib/gsRegrid.py create mode 100644 regrid2/Lib/Lib/gs_horizontal.py create mode 100644 regrid2/Lib/Lib/horizontal.py create mode 100644 regrid2/Lib/Lib/mvESMFRegrid.py create mode 100644 regrid2/Lib/Lib/mvGenericRegrid.py create mode 100644 regrid2/Lib/Lib/mvLibCFRegrid.py create mode 100644 regrid2/Lib/Lib/mytest.py create mode 100644 regrid2/Lib/Lib/pressure.py create mode 100644 regrid2/Lib/Lib/scrip.py create mode 100644 regrid2/Lib/PET0.ESMF_LogFile create mode 100644 regrid2/Lib/__init__.py create mode 100644 regrid2/Lib/crossSection.py create mode 100644 regrid2/Lib/crossSection.py.orig create mode 100644 regrid2/Lib/error.py create mode 100644 regrid2/Lib/esmf.py create mode 100644 regrid2/Lib/gsRegrid.py create mode 100644 regrid2/Lib/gs_horizontal.py create mode 100644 regrid2/Lib/horizontal.py create mode 100644 regrid2/Lib/mvESMFRegrid.py create mode 100644 regrid2/Lib/mvGenericRegrid.py create mode 100644 regrid2/Lib/mvLibCFRegrid.py create mode 100644 regrid2/Lib/mytest.py create mode 100644 regrid2/Lib/pressure.py create mode 100644 regrid2/Lib/scrip.py diff --git a/regrid2/Lib/Lib/PET0.ESMF_LogFile b/regrid2/Lib/Lib/PET0.ESMF_LogFile new file mode 100644 index 00000000..3494c8e2 --- /dev/null +++ b/regrid2/Lib/Lib/PET0.ESMF_LogFile @@ -0,0 +1 @@ +20170308 152041.534 INFO PET0 Running with ESMF Version 7.0.0 diff --git a/regrid2/Lib/Lib/__init__.py b/regrid2/Lib/Lib/__init__.py new file mode 100644 index 00000000..36b7f9e2 --- /dev/null +++ b/regrid2/Lib/Lib/__init__.py @@ -0,0 +1,36 @@ +"""Interface to regridding facilities +""" + +__all__ = ["horizontal", "pressure", "crossSection", "scrip", + "error", "mvGenericRegrid", ] + +from .error import RegridError # noqa +from .horizontal import Horizontal, Regridder # noqa +from .pressure import PressureRegridder # noqa +from .crossSection import CrossSectionRegridder # noqa +from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa +from .scrip import DistwgtRegridder, readRegridder # noqa +from regrid2 import gsRegrid # noqa +from .mvGenericRegrid import GenericRegrid # noqa +from .mvLibCFRegrid import LibCFRegrid # noqa +try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + from .mvESMFRegrid import ESMFRegrid # noqa +except BaseException: + pass + +from . import git # noqa + +ESMF_HAS_BEEN_INITIALIZED = False +if not ESMF_HAS_BEEN_INITIALIZED: + try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + ESMF.Manager(debug=False) + # this turns off the PET file logs + ESMF_HAS_BEEN_INITIALIZED = True + except BaseException: + pass diff --git a/regrid2/Lib/Lib/crossSection.py b/regrid2/Lib/Lib/crossSection.py new file mode 100644 index 00000000..cf23b45d --- /dev/null +++ b/regrid2/Lib/Lib/crossSection.py @@ -0,0 +1,1092 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklatpass) + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/Lib/crossSection.py.orig b/regrid2/Lib/Lib/crossSection.py.orig new file mode 100644 index 00000000..c06eae4a --- /dev/null +++ b/regrid2/Lib/Lib/crossSection.py.orig @@ -0,0 +1,1095 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +from . import _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + print("INPUT IS VAR:", inputIsVariable) + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklat) + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print('calculated cross section test case rms error = ', error) diff --git a/regrid2/Lib/Lib/error.py b/regrid2/Lib/Lib/error.py new file mode 100644 index 00000000..327dff22 --- /dev/null +++ b/regrid2/Lib/Lib/error.py @@ -0,0 +1,3 @@ +class RegridError (Exception): + def __init__(self, args="Unspecified error from regrid package"): + self.args = (args,) diff --git a/regrid2/Lib/Lib/esmf.py b/regrid2/Lib/Lib/esmf.py new file mode 100644 index 00000000..830910a1 --- /dev/null +++ b/regrid2/Lib/Lib/esmf.py @@ -0,0 +1,842 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2008-2012, Tech-X Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the conditions +specified in the license file 'license.txt' are met. + +Authors: David Kindig and Alex Pletzer +""" +import re +import time +import numpy +from regrid2 import RegridError +import ESMF +from functools import reduce + +# constants +R8 = ESMF.TypeKind.R8 +R4 = ESMF.TypeKind.R4 +I8 = ESMF.TypeKind.I8 +I4 = ESMF.TypeKind.I4 +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER +CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class EsmfUnstructGrid: + """ + Unstructured grid + """ + + def __init__(self, numTopoDims, numSpaceDims): + """Constructor + + Parameters + ---------- + + numTopoDims + number of topological dimensions + + numSpaceDims + number of space dimensions + """ + # handle to the grid object + self.grid = None + # whether or not nodes were added + self.nodesAdded = False + # whether or not cells were added + self.cellsAdded = False + # the local processor rank + self.pe = 0 + # number of processors + self.nprocs = 1 + # communicator + self.comm = None + + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + self.grid = ESMF.Mesh( + parametric_dim=numTopoDims, + spatial_dim=numSpaceDims) + + def setCells(self, cellIndices, cellTypes, connectivity, + cellMask=None, cellAreas=None): + """ + Set Cell connectivity + + Parameters + ---------- + + cell indices (0-based) + + cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + + connectivity node connectivity array, see below for node ordering + + cellMask + + cellAreas area (volume) of each cell + + Note + ---- + + 3 + / \ + / \ + / \ + / \ + / \ + 1 --------- 2 + + + + + 4------------3 + | | + | | + | | + | | + | | + 1 ---------- 2 + + + + 3 8---------------7 + /|\ /| /| + / | \ / | / | + / | \ / | / | + / | \ / | / | + / | \ 5---------------6 | + 4-----|-----2 | | | | + \ | / | 4----------|----3 + \ | / | / | / + \ | / | / | / + \ | / | / | / + \|/ |/ |/ + 1 1---------------2 + + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX + + """ + n = len(cellIndices) + if not self.cellsAdded: + # node/cell indices are 1-based in ESMF + cellIndices += 1 + self.grid.add_elements(n, cellIndices, cellTypes, + connectivity, elementMask=cellMask, + elementArea=cellAreas) + self.cellsAdded = True + + def setNodes(self, indices, coords, peOwners=None): + """ + Set the nodal coordinates + + Parameters + ---------- + + indices Ids of the nodes (0-based) + + coords nodal coordinates + + peOwners processor ranks where the coordinates reside (0-based) + """ + n = len(indices) + if not self.nodesAdded: + if peOwners is None: + peOwners = numpy.ones((n,), numpy.int32) * self.pe + # node indices are 1-based + indices += 1 + self.grid.add_nodes(n, indices, coords, peOwners) + self.nodesAdded = True + + def toVTK(self, filename): + """ + Write grid to VTK file format + + Parameters + ---------- + + filename VTK file name + _: None + + """ + self.grid.write(filename) + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructGrid: + """ + Structured grid + """ + + def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, + periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, + hasBounds=False): + """ + Constructor + + Parameters + ---------- + + shape Tuple of cell sizes along each axis + + coordSys coordinate system + ESMF.CoordSys.CART Cartesian + ESMF.CoordSys.SPH_DEG (default) Degrees + ESMF.CoordSys.SPH_RAD Radians + + periodicity Does the grid have a periodic coordinate + 0 No periodicity + 1 Periodic in x (1st) axis + 2 Periodic in x, y axes + + staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX + The stagger constants are listed at the top + + hasBounds If the grid has bounds, Run AddCoords for the bounds + """ + # ESMF grid object + self.grid = None + # number of cells in [z,] y, x on all processors + self.shape = shape[::-1] + # number of dimensions + self.ndims = len(self.shape) + # whether or not cell areas were set + self.cellAreasSet = False + # whether or not nodal coords were set + self.nodesSet = False + # whether or not cell centered coordinates were set + self.centersSet = False + + # assume last 2 dimensions are Y,X + # For esmf reverse to X, Y + maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) + + self.centersSet = False + periodic_dim = 0 + pole_dim = 1 + if periodicity == 0: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], + coord_sys=coordSys) + elif periodicity == 1: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, + periodic_dim=periodic_dim, pole_dim=pole_dim, + staggerloc=[staggerloc], coord_sys=coordSys) + else: + msg = """ +esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. + """ % periodicity + raise RegridError(msg) + + # Grid add coordinates call must go here for parallel runs + # This occur before the fields are created, making the fields + # parallel aware. + if ((staggerloc == CENTER) and (not self.centersSet)): + self.centersSet = True + elif (staggerloc == CORNER) and (not self.nodesSet): + self.nodesSet = True + + if hasBounds is not None: + if self.ndims == 2: + self.grid.add_coords([CORNER], coord_dim=None, from_file=False) + if self.ndims == 3: + self.grid.add_coords( + [VCORNER], coord_dim=None, from_file=False) + + def getLocalSlab(self, staggerloc): + """ + Get the local slab (ellipsis). You can use this to grab + the data local to this processor + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple of slices + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([slice(lo[i], hi[i], None) + for i in range(self.ndims)])[::-1] + + def getLoHiBounds(self, staggerloc): + """ + Get the local lo/hi index values for the coordinates (per processor) + (hi is not inclusive, lo <= index < hi) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + lo, hi lists + """ + lo = self.grid.lower_bounds[staggerloc] + hi = self.grid.upper_bounds[staggerloc] + return lo, hi + + def getCoordShape(self, staggerloc): + """ + Get the local coordinate shape (may be different on each processor) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] + + def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): + """ + Populate the grid with staggered coordinates (e.g. corner or center). + + + Parameters + ---------- + + coords + The curvilinear coordinates of the grid. + List of numpy arrays. Must exist on all procs. + + staggerloc + The stagger location + ESMF.StaggerLoc.CENTER (default) + ESMF.StaggerLoc.CORNER + + globalIndexing + if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + + Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, + hence the dimensions are reversed here. + """ + # allocate space for coordinates, can only add coordinates once + for i in range(self.ndims): + ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) + if globalIndexing: + slab = self.getLocalSlab(staggerloc)[::-1] + # Populate self.grid with coordinates or the bounds as needed + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] + else: + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] + + def getCoords(self, dim, staggerloc): + """ + Return the coordinates for a dimension + + Parameters + --------- + + dim desired dimension (zero based indexing) + + staggerloc Stagger location + """ + gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) + shp = self.getCoordShape(staggerloc)[::-1] + return numpy.reshape(gridPtr, shp).T + + def setCellAreas(self, areas): + """ + Set the cell areas + + Parameters + --------- + + areas numpy array + + _: None + + """ + self.grid.add_item(item=ESMF.GridItem.Area) + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + areaPtr[:] = areas.T.flat + self.cellAreasSet = True + + def getCellAreas(self): + """ + + Returns + ------- + + cell areas or None if setCellAreas was not called + """ + if self.cellAreasSet: + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + return numpy.reshape(areaPtr, self.shape).T + else: + return None + + def getMask(self, staggerloc=CENTER): + """ + Get mask array. In ESMF, the mask is applied to cells. + + Returns + ------- + + mask numpy array. 1 is invalid by default. This array exists on all procs + """ + try: + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, staggerloc=staggerloc) + except BaseException: + maskPtr = None + return maskPtr.T + + def setMask(self, mask, staggerloc=CENTER): + """ + Set mask array. In ESMF, the mask is applied to cells. + + Parameters + ---------- + + mask numpy array. 1 is invalid by default. This array exists + on all procs + + _: None + """ + self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, + staggerloc=staggerloc) + slab = self.getLocalSlab(CENTER)[::-1] + maskPtr[:] = mask.T[slab] + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructField: + """ + Structured field. + """ + + def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): + """ + Creator for structured ESMF Field + + Parameters + ---------- + + esmfGrid + instance of an ESMF + + name field + name (must be unique) + + datatype + data type, one of 'float64', 'float32', 'int64', or 'int32' + (or equivalent numpy dtype) + + staggerloc + ESMF.StaggerLoc.CENTER + ESMF.StaggerLoc.CORNER + """ + # field object + self.field = None + # the local processor rank + self.pe = 0 + # the number of processors + self.nprocs = 1 + # associated grid + self.grid = esmfGrid + # staggering + self.staggerloc = staggerloc + # communicator + self.comm = None + + try: + from mpi4py import MPI + self.comm = MPI.COMM_WORLD + except BaseException: + pass + + etype = None + sdatatype = str(datatype) # in case user passes a numpy dtype + if re.search('float64', sdatatype): + etype = R8 + elif re.search('float32', sdatatype): + etype = R4 + elif re.search('int64', sdatatype): + etype = I8 + elif re.search('int32', sdatatype): + etype = I4 + else: + msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype + raise RegridError(msg) + + self.field = ESMF.Field( + grid=esmfGrid.grid, + name=name, + typekind=etype, + staggerloc=staggerloc) + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + def getPointer(self): + """ + Get field data as a flat array + + Returns + ------- + + pointer + """ + return numpy.ravel(self.field.data) + + def getData(self, rootPe): + """ + Get field data as a numpy array + + Parameters + ---------- + + rootPe if None then local data will be fetched, otherwise + gather the data on processor "rootPe" (all other + procs will return None). + + _: None + + Returns + ------- + + numpy array or None + """ + ptr = self.getPointer() + if rootPe is None: + shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] + # local data, copy + return numpy.reshape(ptr, shp).T + else: + # gather the data on rootPe + lo, hi = self.grid.getLoHiBounds(self.staggerloc) + los = [lo] + his = [hi] + ptrs = [ptr] + ptr = numpy.reshape(ptr, hi) + if self.comm is not None: + los = self.comm.gather(lo) # Local + his = self.comm.gather(hi) # Local + ptrs = self.comm.gather(ptr, root=rootPe) + + if self.pe == rootPe: # Local + # reassemble, find the largest hi indices to set + # the shape of the data container + bigHi = [0 for i in range(self.grid.ndims)] + for i in range(self.grid.ndims): + bigHi[i] = reduce(lambda x, y: max(x, y), + [his[p][i] for p in range(self.nprocs)]) + # allocate space to retrieve the data + bigData = numpy.empty(bigHi, ptr.dtype) + bigData[:] = 0.0 + + # populate the data + for p in range(self.nprocs): + slab = tuple([slice(los[p][i], his[p][i], None) for + i in range(self.grid.ndims)]) + # copy + bigData[slab].flat = ptrs[p] + return bigData.T # Local + + # rootPe is not None and self.pe != rootPe + return None + + def setLocalData(self, data, staggerloc, globalIndexing=False): + """ + Set local field data + + Parameters + ---------- + + data full numpy array, this method will take care of setting a + the subset of the data that reside on the local processor + + staggerloc stagger location of the data + + + globalIndexing if True array was allocated over global index + space, array was allocated over local index + space (on this processor) + """ + ptr = self.field.data + if globalIndexing: + slab = self.grid.getLocalSlab(staggerloc)[::-1] + ptr[:] = data.T[slab] + else: + ptr[:] = data.T + + +########################################################################## + +class EsmfRegrid: + """ + Regrid source grid data to destination grid data + """ + + def __init__(self, srcField, dstField, + srcFrac=None, + dstFrac=None, + srcMaskValues=None, + dstMaskValues=None, + regridMethod=BILINEAR, + ignoreDegenerate=False, + unMappedAction=IGNORE): + """ + Constuct regrid object + + Parameters + ---------- + + srcField + the source field object of type EsmfStructField + + dstField + the destination field object of type EsmfStructField + + srcMaskValues + Value of masked cells in source + + dstMaskValues + Value of masked cells in destination + + srcFrac + Cell fractions on source grid (type EsmfStructField) + + dstFrac + Cell fractions on destination grid (type EsmfStructField) + + regridMethod + ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + + unMappedAction + ESMF.UnmappedAction.{IGNORE,ERROR} + + ignoreDegenerate + Ignore degenerate cells when checking inputs + """ + self.srcField = srcField + self.dstField = dstField + self.regridMethod = regridMethod + self.srcAreaField = None + self.dstAreaField = None + self.srcFracField = srcFrac + self.dstFracField = dstFrac + self.regridHandle = None + self.ignoreDegenerate = ignoreDegenerate + + timeStamp = re.sub('\.', '', str(time.time())) + + # create and initialize the cell areas to zero + if regridMethod == CONSERVE: + self.srcAreaField = EsmfStructField(self.srcField.grid, + name='src_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcAreaField.getPointer() + dataPtr[:] = 0.0 + self.dstAreaField = EsmfStructField(self.dstField.grid, + name='dst_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstAreaField.getPointer() + dataPtr[:] = 0.0 + + # initialize fractional areas to 1 (unless supplied) + if srcFrac is None: + self.srcFracField = EsmfStructField(self.srcField.grid, + name='src_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcFracField.getPointer() + dataPtr[:] = 1.0 + + if dstFrac is None: + self.dstFracField = EsmfStructField(self.dstField.grid, + name='dst_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstFracField.getPointer() + dataPtr[:] = 1.0 + + srcMaskValueArr = None + if srcMaskValues is not None: + srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) + + dstMaskValueArr = None + if dstMaskValues is not None: + dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) + + self.regridHandle = ESMF.Regrid( + srcField.field, + dstField.field, + src_frac_field=self.srcFracField.field, + dst_frac_field=self.dstFracField.field, + src_mask_values=srcMaskValueArr, + dst_mask_values=dstMaskValueArr, + regrid_method=regridMethod, + unmapped_action=unMappedAction, + ignore_degenerate=self.ignoreDegenerate) + + def getSrcAreas(self, rootPe): + """ + Get the src grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.srcAreaField.data.T + return None + + def getDstAreas(self, rootPe): + """ + Get the dst grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.dstAreaField.data.T + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.srcFracField is not None: + # self.srcFracField.get_area() + return self.srcFracField.data.T + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.dstFracField is not None: + # self.dstFracField.get_area() + return self.dstFracField.data.T + return None + + def __call__(self, srcField=None, dstField=None, zero_region=None): + """ + Apply interpolation weights + + Parameters + ---------- + + srcField source field (or None if src field passed to + constructor is to be used) + + dstField destination field (or None if dst field passed + to constructor is to be used) + + zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) + """ + if srcField is None: + srcField = self.srcField + if dstField is None: + dstField = self.dstField + + # default is keep the masked values intact + zeroregion = ESMF.Region.SELECT + if self.regridMethod == CONSERVE: + zeroregion = None # will initalize to zero + + self.regridHandle( + srcfield=srcField.field, + dstfield=dstField.field, + zero_region=zeroregion) + + def __del__(self): + if self.regridHandle is not None: + self.regridHandle.destroy() diff --git a/regrid2/Lib/Lib/gsRegrid.py b/regrid2/Lib/Lib/gsRegrid.py new file mode 100644 index 00000000..de150dba --- /dev/null +++ b/regrid2/Lib/Lib/gsRegrid.py @@ -0,0 +1,1179 @@ +#!/usr/bin/env python + +""" +Regridding of curvilinear structured grids +Alex Pletzer and Dave Kindig, Tech-X (2011) +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. +""" +# standard python includes +# from re import search, sub +from ctypes import c_double, c_float, c_int, \ + c_wchar_p, CDLL, byref, POINTER +# import ctypes +import operator +import sys +import os +import copy +import numpy +import warnings +from regrid2 import RegridError +from functools import reduce +import fnmatch + +C_DOUBLE_P = POINTER(c_double) + +# libcf +try: + from pycf import libCFConfig, __path__ +except BaseException: + raise ImportError('Error: could not import pycf') + +LIBCFDIR = __path__[0] + "/pylibcf" + +__FILE__ = sys._getframe().f_code.co_filename + + +def catchError(status, lineno): + if status != 0: + raise RegridError("ERROR in %s: status = %d at line %d" + % (__FILE__, status, lineno)) + + +def getTensorProduct(axis, dim, dims): + """ + Convert an axis into a curvilinear coordinate by applying + a tensor product + + Parameters + ---------- + + axis 1D array of coordinates + + dim dimensional index of the above coordinate + + dims sizes of all coordinates + + Returns + ------- + + coordinate values obtained by tensor product + """ + return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), + numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) + + +def makeCurvilinear(coords): + """ + Turn a mixture of axes and curvilinear coordinates into + full curvilinear coordinates + + Parameters + ---------- + + coords list of coordinates + + Returns + ------- + + new list of coordinates and associated dimensions + """ + rank = len(coords) + + count1DAxes = 0 + dims = [] + for i in range(rank): + coord = coords[i] + if len(coord.shape) == 1: + # axis + dims.append(len(coord)) + count1DAxes += 1 + elif len(coord.shape) == rank: + # fully curvilinear + dims.append(coord.shape[i]) + else: + # assumption: all 1D axes preceed curvilinear + # coordinates!!! + dims.append(coord.shape[i - count1DAxes]) + + for i in range(rank): + nd = len(coords[i].shape) + if nd == rank: + # already in curvilinear form, keep as is + pass + elif nd == 1: + # it's an axis + coords[i] = getTensorProduct(coords[i][:], i, dims) + elif rank == 3 and nd == 2 and i > 0: + # assume leading coordinate is an axis + o1 = numpy.ones((len(coords[0]),), coords[i].dtype) + coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) + else: + raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" + % (__FILE__, str([x.shape for x in coords]))) + return coords, dims + + +def makeCoordsCyclic(coords, dims): + """ + Make coordinates cyclic + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + new, extended coordinates such that the longitudes cover the sphere + and new dimensions + """ + # assume lon is the last coordinate!! + + # check if already extended + eps = 1.e-3 + + # some models already overlap + diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # some models are already periodic + diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # make cyclic by appending a column to the coordinates + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-1] += 1 # append to the right + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:-1] = coords[i][...] + newCoords[i][..., -1] = coords[i][..., 0] + + # add modulo term, want deltas ~ order of dlon otherwise add + # or subtract a periodicity length + nlon = dims[-1] + dlon = 360.0 / float(nlon) # average resolution + tol = 360.0 - min(5, nlon) * dlon + mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) + mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) + newCoords[-1][..., -1] += 360.0 * mask1 + newCoords[-1][..., -1] -= 360.0 * mask2 + + return newCoords, newDims + + +def checkForCoordCut(coords, dims): + """ + Look for a cut in a coordinate system (e.g. tri-polar grid) + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + True for cut found + False for no cut + """ + + # Assume latitude is next to last coordinate and longitude is last + # coordinate!!! + + rank = len(dims) + if rank < 2: + # print 'no cut: dims < 2' + return False + if len(coords[-2].shape) < 2: + # Is the 'lat' coordinate an axis? + return False + + nlat, nlon = dims[-2], dims[-1] + lat = coords[-2] + eps = 1.e-7 + + # Check to see if the top row has already be dealt with by the modeling + # agency. Last row is repeated in reverse. + + topRow = coords[-2][..., nlat - 1, :] + revTop = coords[-2][..., nlat - 1, ::-1] + nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow + diffs = abs(revTop - nextRow) + + # If already accounted for all diffs are 0. + if numpy.all(diffs < eps): + # print "no cut: reversed" + return False + + # Lon of max latitude -- Looking for a rotated pole + maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) + inTopRow = False + if len(maxLats[0] > 0): + inTopRow = numpy.all(maxLats[-2] == nlat - 1) + if not inTopRow: + # The max lats are not in the top row. The cut may already be handled + # print 'no cut: max lat not in top row.' + \ + # 'Either: it is a funky grid or rotated pole' + return False + + # Only in top row. + maxLatInd = lat[..., nlat - 1, :].argmax() + maxLonInd = lat[..., maxLatInd].argmax() + rowOfMaxLat = lat[..., maxLonInd, :] + diffs = rowOfMaxLat - topRow + + if diffs.max() != 0: + # Rotated Pole + # print "no cut: rotated pole" + return False + + # Find locale minima. + # A rotated pole grid has only one minimum. A tripolar grid should + # have two, though they may not be at the same latitude + + minInds = numpy.where(abs(topRow - topRow.min()) < eps) + if len(minInds[0]) > 2: + # Account for the end points matching + # Multiple minima in the top row + return True + + # Now if we have an offset tri-pole. The extra poles are not at the same + # latitude + minCount = 0 + firstInd = topRow.argmin() + diffs = numpy.diff(topRow) + if firstInd == 0: + if revTop.argmin() == 0: + if topRow[firstInd] == revTop[0]: + minCount += 1 + else: + minCount += 1 + # Look for next Minima + index = firstInd + 1 + while diffs[index] > 0: + index += 1 + if index == nlon: + break + nextIndex = topRow[index + 1:].argmin() + index + 1 + if nextIndex != index + 1 and nextIndex != nlon - 1: + minCount += 1 + if minCount == 1: + # print "no cut: one pole" + return False + + return True + + +def handleCoordsCut(coords, dims, bounds): + """ + Generate connectivity across a cut. e.g. from a tri-polar grid. + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates list of rank + + dims input dimensions + + bounds boundaries for each coordinate + + Returns + ------- + + extended coordinates such that there is an extra row containing + connectivity information across the cut + """ + + # Assume latitude is next to last coordinate and longitude is + # last coordinate!!! + + dims = coords[-2].shape + + # Add row to top with connectivity information. This means rearranging + # the top row + def getIndices(array, nlon, newI): + """ + Find indices where a cell edge matches for two cells + + Parameters + ---------- + + array Array of booleans + + nlon number of longitudes + + newI index row with connectivity to be updated + + Returns + ------- + + new coordinates, new dimensions, index row + """ + for i in range(len(array)): + # An edge + if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa + if newI[i] < 0: + newI[i] = (nlon - 1) - i + if newI[(nlon - 1) - i] < 0: + newI[(nlon - 1) - i] = i + + # Assume mkCyclic == True + newI = numpy.arange(nlon - 1, -1, -1) - 1 + newI[nlon - 1] = 0 # Complete the rotation + + # Build new coordinate array and adjust dims + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-2] += 1 + + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:dims[-2], :] = coords[i][...] + newCoords[i][..., dims[-2], + :] = coords[i][..., dims[-2] - 1, newI] + + return newCoords, newDims, newI + + +class Regrid: + + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, + handleCut=False, verbose=False): + """ + Constructor + + Parameters + ---------- + + src_grid source grid, a list of [x, y, ...] coordinates + or a cdms2.grid.Transient + + dst_grid destination grid, a list of [x, y, ...] coordinates + + src_bounds list of cell bounding coordinates (to be used when + handling a cut in coordinates) + + mkCyclic Add a column to the right side of the grid to complete + a cyclic grid + + handleCut Add a row to the top of grid to handle a cut for + grids such as the tri-polar grid + + verbose print diagnostic messages + + + Note: the grid coordinates can either be axes (rectilinear grid) or + n-dimensional for curvilinear grids. Rectilinear grids will + be converted to curvilinear grids. + """ + self.regridid = c_int(-1) + self.src_gridid = c_int(-1) + self.dst_gridid = c_int(-1) + self.rank = 0 + self.src_dims = [] + self.dst_dims = [] + self.src_coords = [] + self.dst_coords = [] + self.lib = None + self.extendedGrid = False + self.handleCut = False + self.dst_Index = [] + self.verbose = verbose + self.weightsComputed = False + self.maskSet = False + + # Open the shaped library + dynLibFound = False + for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': + if os.path.exists(LIBCFDIR + sosuffix): + dynLibFound = True + CFfile = self.find('pylibcf.*', __path__[0]) + if os.path.exists(CFfile): + try: + self.lib = CDLL(CFfile) + except BaseException: + pass +# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': +# if os.path.exists(LIBCFDIR + sosuffix): +# dynLibFound = True +# try: +# self.lib = CDLL(LIBCFDIR + sosuffix) +# break +# except: +# pass + if self.lib is None: + if not dynLibFound: + raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + + # Number of space dimensions + self.rank = len(src_grid) + + if len(dst_grid) != self.rank: + raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" + % (__FILE__, len(dst_grid), self.rank)) + + if self.rank <= 0: + raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" + % (__FILE__, self.rank)) + + # Convert src_grid/dst_grid to curvilinear grid, if need be + if self.rank > 1: + src_grid, src_dims = makeCurvilinear(src_grid) + dst_grid, dst_dims = makeCurvilinear(dst_grid) + + # Make sure coordinates wrap around if mkCyclic is True + if mkCyclic: + src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + for i in range(self.rank): + print(('...... src_gridNew[%d].shape = %s' + % (i, str(src_gridNew[i].shape)))) + # flag indicating that the grid was extended + if reduce(lambda x, y: x + y, + [src_dimsNew[i] - src_dims[i] + for i in range(self.rank)]) > 0: + self.extendedGrid = True + # reset + src_grid = src_gridNew + src_dims = src_dimsNew + + # Handle a cut in the coordinate system. Run after mkCyclic. + # e.g. a tri-polar grid + if handleCut and src_bounds is not None: + # Test for the presence of a cut. + isCut = checkForCoordCut(src_grid, src_dims) + if isCut: + # No cut + src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, + src_dims, src_bounds) + if dst_Index is not None: + self.handleCut = True + self.extendedGrid = self.extendedGrid + else: + self.handleCut = False + self.extendedGrid = self.extendedGrid + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + src_grid = src_gridNew + src_dims = src_dimsNew + self.dst_Index = dst_Index + + self.src_dims = (c_int * self.rank)() + self.dst_dims = (c_int * self.rank)() + + # Build coordinate objects + src_dimnames = (c_wchar_p * self.rank)() + dst_dimnames = (c_wchar_p * self.rank)() + for i in range(self.rank): + src_dimnames[i] = 'src_n%d' % i + dst_dimnames[i] = 'dst_n%d' % i + self.src_dims[i] = src_dims[i] + self.dst_dims[i] = dst_dims[i] + self.src_coordids = (c_int * self.rank)() + self.dst_coordids = (c_int * self.rank)() + save = 0 + standard_name = "" + units = "" + coordid = c_int(-1) + for i in range(self.rank): + data = numpy.array(src_grid[i], numpy.float64) + self.src_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "src_coord%d" % i + # assume [lev,] lat, lon ordering + if i == self.rank - 2: + standard_name = 'latitude' + units = 'degrees_north' + elif i == self.rank - 1: + standard_name = 'longitude' + units = 'degrees_east' + status = self.lib.nccf_def_coord(self.rank, self.src_dims, + src_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.src_coordids[i] = coordid + + data = numpy.array(dst_grid[i], numpy.float64) + self.dst_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "dst_coord%d" % i + status = self.lib.nccf_def_coord(self.rank, self.dst_dims, + dst_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.dst_coordids[i] = coordid + + # Build grid objects + status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", + byref(self.src_gridid)) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", + byref(self.dst_gridid)) + catchError(status, sys._getframe().f_lineno) + + # Create regrid object + status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, + byref(self.regridid)) + catchError(status, sys._getframe().f_lineno) + + def getPeriodicities(self): + """ + Get the periodicity lengths of the coordinates + + Returns + ------- + + numpy array, values inf indicate no periodicity + """ + coord_periodicity = numpy.zeros((self.rank,), numpy.float64) + status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, + coord_periodicity.ctypes.data_as(C_DOUBLE_P)) + catchError(status, sys._getframe().f_lineno) + return coord_periodicity + + def __del__(self): + """ + Destructor, will be called automatically + """ + status = self.lib.nccf_free_regrid(self.regridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.src_gridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.dst_gridid) + catchError(status, sys._getframe().f_lineno) + + for i in range(self.rank): + + status = self.lib.nccf_free_coord(self.src_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_coord(self.dst_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + def find(self, pattern, path): + result = "" + for root, dirs, files in os.walk(path): + for name in files: + if fnmatch.fnmatch(name, pattern): + result = os.path.join(root, name) + return result + + def setValidMask(self, inMask): + """ + Set valid mask array for the grid + + Parameters + ---------- + + inMask flat numpy array of type numpy.int32 or a valid cdms2 variable + with its mask set. + 0 - invalid, 1 - valid data + + Note: This must be invoked before computing the weights, the + mask is a property of the grid (not the data). + """ + if self.weightsComputed: + raise RegridError('Must set mask before computing weights') + + mask = numpy.array(inMask, dtype=numpy.int32) + + # extend src data if grid was made cyclic and or had a cut accounted + # for + newMask = self._extend(mask) + c_intmask = newMask.ctypes.data_as(POINTER(c_int)) + status = self.lib.nccf_set_grid_validmask(self.src_gridid, + c_intmask) + catchError(status, sys._getframe().f_lineno) + self.maskSet = True + + def setMask(self, inDataOrMask): + """ + Set mask array. The mask is defined for nodes + + Parameters + ---------- + + inDataOrMask cdms2 array or flat mask array, + 0 - valid data + 1 - invalid data + + Note: this definition is compatible with the numpy masked arrays + + Note: note see setValidMask for the opposite definition + + Note: should be called before computing the weights + """ + mask = None + if hasattr(inDataOrMask, 'getmask'): + # cdms2 variable + mask = inDataOrMask.getmask() + else: + # flat mask array + mask = inDataOrMask + # reversing the meaning 1 == valid, 0 == invalid + mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) + # now calling our own mask setter + self.setValidMask(mask) + + def computeWeights(self, nitermax=100, tolpos=1.e-2): + """ + Compute the the interpolation weights + + Parameters + ---------- + + nitermax max number of iterations + + tolpos max tolerance when locating destination positions in + index space + """ + status = self.lib.nccf_compute_regrid_weights(self.regridid, + nitermax, + c_double(tolpos)) + catchError(status, sys._getframe().f_lineno) + self.weightsComputed = True + + def apply(self, src_data_in, dst_data, missingValue=None): + """ + Apply interpolation + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + if not self.weightsComputed: + raise RegridError('Weights must be set before applying the regrid') + # extend src data if grid was made cyclic and or had a cut accounted + # for + src_data = self._extend(src_data_in) + + # Check + if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + + "%s != %s") % (__FILE__, str(src_data.shape), + str(tuple([d for d in self.src_dims])))) + if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + + "%s != %s") % (__FILE__, str(dst_data.shape), + str(tuple([d for d in self.dst_dims])))) + + # Create temporary data objects + src_dataid = c_int(-1) + dst_dataid = c_int(-1) + save = 0 + standard_name = "" + units = "" + time_dimname = "" + + status = self.lib.nccf_def_data(self.src_gridid, "src_data", + standard_name, units, time_dimname, + byref(src_dataid)) + catchError(status, sys._getframe().f_lineno) + + if src_data.dtype != dst_data.dtype: + try: # try recasting + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" + % (src_data.dtype, dst_data.dtype)) + src_data = src_data.astype(dst_data.dtype) + except BaseException: + try: + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" + % (src_data.dtype, dst_data.dtype)) + dst_data = dst_data.astype(src_data.dtype) + except BaseException: + raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" + % (__FILE__, src_data.dtype, dst_data.dtype)) + + # only float64 and float32 data types are supported for interpolation + if src_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif src_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" + % (__FILE__, src_data.dtype)) + + status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", + standard_name, units, time_dimname, + byref(dst_dataid)) + catchError(status, sys._getframe().f_lineno) + if dst_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif dst_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid dst_data type = %s" + % (__FILE__, dst_data.dtype)) + + # Now apply weights + status = self.lib.nccf_apply_regrid( + self.regridid, src_dataid, dst_dataid) + catchError(status, sys._getframe().f_lineno) + + # Clean up + status = self.lib.nccf_free_data(src_dataid) + catchError(status, sys._getframe().f_lineno) + status = self.lib.nccf_free_data(dst_dataid) + catchError(status, sys._getframe().f_lineno) + + return dst_data + + def __call__(self, src_data, dst_data, missingValue=None): + """ + Apply interpolation (synonymous to apply method) + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + self.apply(src_data, dst_data, missingValue) + + def getNumValid(self): + """ + Return the number of valid destination points. Destination points + falling outside the source domain, more gnerally, points which + could not be located on the source grid, reduce the number of + valid points. + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_nvalid(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getNumDstPoints(self): + """ + Return the number of points on the destination grid + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_ntargets(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getSrcGrid(self): + """ + Return the source grid + + Returns + ------- + + grid + """ + return self.src_coords + + def getDstGrid(self): + """ + Return the destination grid + + Returns + ------- + + grid + """ + return self.dst_coords + + def getIndicesAndWeights(self, dst_indices): + """ + Get the indices and weights for a single target location + + Parameters + ---------- + + dst_indices index set on the target grid + + Returns + ------- + + [index sets on original grid, weights] + """ + dinds = numpy.array(dst_indices) + sinds = (c_int * 2**self.rank)() + weights = numpy.zeros((2**self.rank,), numpy.float64) + status = self.lib.nccf_inq_regrid_weights(self.regridid, + dinds.ctypes.data_as( + POINTER(c_double)), + sinds, + weights.ctypes.data_as(POINTER(c_double))) + catchError(status, sys._getframe().f_lineno) + # convert the flat indices to index sets + ori_inds = [] + for i in range(2**self.rank): + inx = numpy.zeros((self.rank,), numpy.int32) + self.lib.nccf_get_multi_index(self.rank, self.src_dims, + sinds[i], + inx.ctypes.data_as(POINTER(c_int))) + ori_inds.append(inx) + + return ori_inds, weights + + def _extend(self, src_data): + """ + Extend the data by padding a column and a row, depending on whether the + grid was made cyclic and a fold was added or not + + Parameters + ---------- + + src_data input source data + + Returns + ------- + + extended source data (or source input data of no padding was applied) + """ + + # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] + # original dimensions, before extension + # assuming ..., lat, lon ordering + nlat, nlon = src_data.shape[-2:] + + # no cut and no cyclic extension + src_dataNew = src_data + + if self.handleCut or self.extendedGrid: + # copy data into new, extended container + src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) + # start filling in... + src_dataNew[..., :nlat, :nlon] = src_data[...] + + if self.handleCut: + # fill in polar cut (e.g. tripolar cut), top row + # self.dst_Index[i] knows how to fold + for i in range(nlon): + src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] + + if self.extendedGrid: + # make data periodic in longitudes + src_dataNew[..., -1] = src_dataNew[..., 0] + + return src_dataNew + + def _findIndices(self, targetPos, nitermax, tolpos, + dindicesGuess): + """ + Find the floating point indices + + Parameters + ---------- + + targetPos numpy array of target positions + + nitermax max number of iterations + + tolpos max toelrance in positions + + dindicesGuess guess for the floating point indices + + Returns + ------- + + indices, number of iterations, achieved tolerance + """ + posPtr = targetPos.ctypes.data_as(POINTER(c_double)) + adjustFunc = None + hit_bounds = numpy.zeros((self.rank), + dtype=int).ctypes.data_as(POINTER(c_int)) + # no periodicity + coord_periodicity = float( + 'inf') * numpy.ones((self.rank), targetPos.dtype) + coord_periodicity_ptr = coord_periodicity.ctypes.data_as( + POINTER(c_double)) + res = copy.copy(dindicesGuess) + resPtr = res.ctypes.data_as(POINTER(c_double)) + src_coords = (POINTER(c_double) * self.rank)() + niter = c_int(nitermax) + tol = c_double(tolpos) + for i in range(self.rank): + ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) + src_coords[i] = ptr + status = self.lib.nccf_find_indices_double(self.rank, + self.src_dims, + src_coords, + coord_periodicity_ptr, + posPtr, + byref(niter), + byref(tol), + adjustFunc, + resPtr, + hit_bounds) + catchError(status, sys._getframe().f_lineno) + return resPtr.contents.value, niter.value, tol.value + +###################################################################### + + +def testMakeCyclic(): + + y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) + x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) + yy = getTensorProduct(y, 0, [len(y), len(x)]) + xx = getTensorProduct(x, 1, [len(y), len(x)]) + coords = [yy, xx] + dims = [len(y), len(x)] + newCoords, newDims = makeCoordsCyclic(coords, dims) +# print 'cyclic lats' +# print newCoords[0] +# print 'cyclic lons' +# print newCoords[1] + + +def testHandleCut(): + + import cdms2 + # Need tripolar grid + filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" + f = cdms2.open(filename) + if not f: + return + + # so = f.variables['so'][0, 0, :, :] + if 'lon' in list(f.variables.keys()): + alllat = f.variables['lat'] + alllon = f.variables['lon'] + else: + alllat = f.getAxis("lat").getData() + alllon = f.getAxis("lon").getData() + + bounds = [f.variables['bounds_lon'][:].data, + f.variables['bounds_lat'][:].data] + coords = [alllat[:].data, alllon[:].data] + dims = alllat.shape + newCoords, newDims = makeCoordsCyclic(coords, dims) + newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) + + +# def testOuterProduct(): + + # 2d + # x = numpy.array([1, 2, 3, 4]) + # y = numpy.array([10, 20, 30]) + # xx = getTensorProduct(x, 0, [len(x), len(y)]) + # yy = getTensorProduct(y, 1, [len(x), len(y)]) + + # z = numpy.array([100, 200]) + # Mixed coordinates and axes + # aa = makeCurvilinear([z, yy, xx]) + # for g in aa: + # print g + +def test(): + def func1(coords): + return coords[0] * coords[1] + coords[2] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = numpy.array([1, 2, 3, 4, 5, 6]) + src_y = numpy.array([10, 20, 30, 40, 50]) + src_z = numpy.array([100, 200]) + + # destination grid, product of axes + dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) + dst_y = numpy.array([15., 20., 25., 30., 40.]) + dst_z = numpy.array([120.0, 180.0, 240.]) + + # regridding constructor + rg = Regrid([src_x, src_y, src_z], + [dst_x, dst_y, dst_z]) +# rg = Regrid([src_x, src_y], +# [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + maxNumIters = 20 + posTol = 1.e-3 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data = ', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +def testMasking(): + import numpy.ma as ma + + def func1(coords): + return coords[0] * coords[1] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) + src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) + + # destination grid, product of axes + dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, + 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) + dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) + + # regridding constructor + rg = Regrid([src_x, src_y], + [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + # Mask needs to be set before weights are computed + mask = rg.getSrcGrid()[0] == 3 + mask[:, 3] = True + rg.setValidMask(mask) + rg.setMask(mask) + maxNumIters = 20 + posTol = 1.e-2 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data =\n', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +if __name__ == '__main__': + # testOuterProduct() + test() + testMasking() + # testMakeCyclic() + # testHandleCut() diff --git a/regrid2/Lib/Lib/gs_horizontal.py b/regrid2/Lib/Lib/gs_horizontal.py new file mode 100644 index 00000000..20cfa4a6 --- /dev/null +++ b/regrid2/Lib/Lib/gs_horizontal.py @@ -0,0 +1,214 @@ +import sys +import os +import os.path +# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer +from ctypes import CDLL, c_double, c_uint +import cdms2 +import time +import config +sys.path.append("/home/painter1/libcf/") +libcf = CDLL(config.prefix + '/lib/libcf.so') + + +class GS_Regridder: + + def __init__(self, ingrid, outgrid, + infile=None, outfile=None, remapfile=None): + # Save the grids, make and save a Gridspec remap file. + # For now, we are using the libCF/Gridspec API which operates only on files; + # thus temporary files are written out and read back in. That requires the + # input grids to support a "write_gridspec" method. + # If a path is provided, it prefixes whatever filenames were input. + # If there is no path provided, each filename must include its path. + # Note: it's a bit messy to keep filenames and paths separate internally, + # but the presnet Gridspec function expects lots of directories. + + self.ingrid = ingrid + self.outgrid = outgrid + if (not hasattr(ingrid, "gsfile")): + ingrid.gsfile = None + ingrid.gspath = None + if (infile is None): + self.infile = ingrid.gsfile + self.inpath = ingrid.gspath + else: + self.infile = os.path.basename(infile) + self.inpath = os.path.dirname(infile) + if (not os.path.isfile(self.inpath + "/" + self.infile)): + raise OSError( + "cannot open infile " + + self.inpath + + "/" + + self.infile) + + if (not hasattr(outgrid, "gsfile")): + outgrid.gsfile = None + outgrid.gspath = None + if (outfile is None): + self.outfile = outgrid.gsfile + self.outpath = outgrid.gspath + else: + self.outfile = os.path.basename(outfile) + self.outpath = os.path.dirname(outfile) + if (not os.path.isfile(self.outpath + "/" + self.outfile)): + raise OSError( + "cannot open outfile " + + self.outpath + + "/" + + self.outfile) + + if (remapfile is None): + timestr = str(int(time.time())) + self.remapfile = "remap" + timestr + self.remappath = "/tmp" + else: + self.remapfile = os.path.basename(remapfile) + self.remappath = os.path.dirname(remapfile) + if (not os.path.isdir(self.remappath + "/")): + raise OSError( + "cannot open remapfile directory " + + self.remappath + + "/") + + ingrid.write_gridspec(self.inpath + "/" + self.infile) + outgrid.write_gridspec(self.outpath + "/" + self.outfile) + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + # No variables to interpolate; the gs_fregrid call will be just to + # make a remap file... + dir_in = 256 * "\x00" + dir_out = 256 * "\x00" + input_file = 256 * "\x00" + nfiles = 0 + output_file = 256 * "\x00" + nfiles_out = 0 + scalar_name = 256 * "\x00" + nscalar = 0 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + # For a call which only writes the remap files, gs_fregrid + # expects remapfile to be a full path. For a call in which + # remapping takes place, gs_fregrid expects remapfile to be + # a pure filename, in a path it gets from elsewhere, maybe dir_in. + # (ARRGH - but with the API slated to be replaced, I'll live with it) + remapf = os.path.abspath( + self.remappath + "/" + self.remapfile) + "\0" * 256 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + remapf, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + def __call__(self, ar): + # Interpolate the input variable to the new grid using the Gridspec + # remap file generated when this GS_Remapper object was initialized. + # >>>for now, ar is required to be a variable (MV) <<< + + # Here, convert ar into a file for gs_fregrid + # There's no special Gridspec way to write a variable; you write to any + # *.nc file. The tough part is making sure you have there exactly what's + # needed for the gs_fregrid call, especially because the grids are + # supposedly supergrids and you just have some keywords to use to figure + # out what goes where. And note that we'll need to check whether ar + # really lives on self.ingrid . Supposedly a future API will work + # better in this respect + + # Write the variable to a temporary file, as required by gs_fregrid. + # The remap path should be suitable. + # >>> this should be done more carefully, e.g. deal with failures; + # >>> more worth doing when we have mosaic variables. + timestr = str(int(time.time())) + varfile = cdms2.open( + self.inpath + + "/" + + "invvar" + + timestr + + ".nc", + 'w') + varfile.write(ar) + varfile.close() + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + dir_in = 256 * "\x00" # path is already encoded in input_file + dir_out = 256 * "\x00" # path is already encoded in output_file + input_file = varfile.id + 256 * "\x00" + nfiles = 1 + output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" + nfiles_out = 1 + scalar_name = ar.id + 256 * "\x00" + nscalar = 1 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + print(("__call__ remapfile=", self.remapfile)) + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + self.remapfile, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + # Read the output_file into a variable, and return the variable + f = cdms2.open(self.outpath + "/" + output_file) + vout = f(scalar_name) + f.close() + return vout diff --git a/regrid2/Lib/Lib/horizontal.py b/regrid2/Lib/Lib/horizontal.py new file mode 100644 index 00000000..67d673f4 --- /dev/null +++ b/regrid2/Lib/Lib/horizontal.py @@ -0,0 +1,422 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import warnings +import cdms2 + +_debug = 0 # Set to 1 for debug + +# Map (n,2) boundary arrays to individual boundary arrays. Returns +# (lowerBounds, upperBounds) + + +def extractBounds(bounds): + if bounds[0, 0] < bounds[0, 1]: + lower = bounds[:, 0] + upper = bounds[:, 1] + else: + lower = bounds[:, 1] + upper = bounds[:, 0] + + return (lower.astype(numpy.float32), upper.astype(numpy.float32)) + +# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid +# objects. + + +class Horizontal: + + def __init__(self, ingrid, outgrid): + """ + Constructor for regridding class + + Parameters + ---------- + + ingrid cdms2, ndarray variable + + outgrid cdms2, ndarray variable + """ + + inlat = ingrid.getLatitude() + outlat = outgrid.getLatitude() + inlon = ingrid.getLongitude() + outlon = outgrid.getLongitude() + inlatBounds, inlonBounds = ingrid.getBounds() + outlatBounds, outlonBounds = outgrid.getBounds() + + self.nlati = len(inlat) + self.nlato = len(outlat) + self.nloni = len(inlon) + self.nlono = len(outlon) + self.inmask = ingrid.getMask() + self.outmask = outgrid.getMask() + # Make grid masks consistent with 'internal' convention: + # 0 == invalid + if self.inmask is not None: + self.inmask = 1. - self.inmask + if self.outmask is not None: + self.outmask = 1. - self.outmask + self.inshape = ingrid.shape + self.inorder = ingrid.getOrder() + self.outlat = outgrid.getLatitude().clone() + self.outlon = outgrid.getLongitude().clone() + + bsin, bnin = extractBounds(inlatBounds) + bwin, bein = extractBounds(inlonBounds) + bsout, bnout = extractBounds(outlatBounds) + bwout, beout = extractBounds(outlonBounds) + + if _debug == 1: + import sys + sys.stdout = open('debug_regrid.txt', 'w') + print(("bsin = ", numpy.array2string(bsin, precision=3))) + print(("bnin = ", numpy.array2string(bnin, precision=3))) + print(("bwin = ", numpy.array2string(bwin, precision=3))) + print(("bein = ", numpy.array2string(bein, precision=3))) + print(("bsout = ", numpy.array2string(bsout, precision=3))) + print(("bnout = ", numpy.array2string(bnout, precision=3))) + print(("bwout = ", numpy.array2string(bwout, precision=3))) + print(("beout = ", numpy.array2string(beout, precision=3))) + + self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( + self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) + + def __call__(self, ar, missing=None, order=None, + mask=None, returnTuple=0, **args): + """ + Call the regridder function. + @param ar is the input array. + @param order is of the form "tzyx", "tyx", etc. + @param missing is the missing data value, if any. + @param mask is either 2-D or the same shape as ar. + @param returnTuple If true, return the tuple (outArray, outWeights) where + outWeights is the fraction of each zone of the output grid + which overlaps non-missing zones of the input grid; it has + the same shape as the output array. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Compatibility + if mask is numpy.ma.nomask: + mask = None + + if ar.dtype.type is numpy.bool_: + ar = numpy.asarray(ar, numpy.float32) + + # Make sense of mask consistent with 'internal' convention (0 == + # invalid) + if mask is not None: + mask = 1. - mask + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + armask = ar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + armask = tempar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armask = armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if mask is None and missing is None: + missing = armiss + mask = armask + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = self.inorder + elif rank == 3: + order = "t" + self.inorder + else: + order = "tz" + self.inorder + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to ilon, ilat ... + itim1 = itim2 = 0 + ilon = ilat = -1 + idim = 0 + for i in range(rank - 1, -1, -1): + c = order[i] + if c == 'x': + ilon = idim + elif c == 'y': + ilat = idim + elif c == 'z': + itim1 = idim + elif c == 't': + if rank == 3: + itim1 = idim + else: + itim2 = idim + idim = idim + 1 + + # Map array shape to nloni, nlati, ... + ntim1 = ntim2 = 0 + shape = ar.shape + if ilon == -1: + raise RegridError("Input grid does not have a longitude axis") + if ilat == -1: + raise RegridError("Input grid does not have a latitude axis") + nlati = shape[rank - ilat - 1] + nloni = shape[rank - ilon - 1] + if nlati != self.nlati or nloni != self.nloni: + raise ( + 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % + (nlati, nloni, self.nlati, self.nloni)) + + if itim1 != 0: + ntim1 = shape[rank - itim1 - 1] + if itim2 != 0: + ntim2 = shape[rank - itim2 - 1] + + # Construct the input mask: + # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask + # if no user mask is specified) + # with the 'implicit mask' generated from the missing data, if any + if (mask is None) or len(mask.shape) == 2: + flag2D = 1 + if mask is not None: + assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' + inmask = mask + elif self.inmask is None: + inmask = numpy.ones(self.inshape) + else: + inmask = self.inmask + + if missing is not None: + if rank == 2: + firstslice = ar + elif rank == 3: + firstslice = ar[0] + else: + firstslice = ar[0, 0] + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + firstslice - + missing), + numpy.absolute( + 0.001 * + missing)), + inmask, + 0) + + # If the user mask was specified and is > 2-D, it overrides the grid + # mask + else: + assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' + inmask = mask + flag2D = 0 # 2-D user masks are handled above + # If armask is derived from the input array, it is probably consistent + # with the missing value - don't bother recalculating it + if missing is not None and armask is None: + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + ar - missing), + numpy.absolute( + 0.001 * missing)), + inmask, + 0) + # Cast the mask to float + inmask = inmask.astype(numpy.float32) + if missing is None: + missing = 1.0e20 + + # Cast the input array to 32-bit floats, if necessary + if ar.dtype.char != numpy.float32: + ar = ar.astype(numpy.float32) + + # Malloc return array + outshape = list(shape) + outshape[rank - ilat - 1] = self.nlato + outshape[rank - ilon - 1] = self.nlono + outar = numpy.zeros(tuple(outshape), numpy.float32) + + # Perform the regridding. The return array has the same shape + # as the output array, and is the fraction of the zone which overlaps + # a non-masked zone of the input grid. + amskout = _regrid.rgdarea( + ilon, + ilat, + itim1, + itim2, + ntim1, + ntim2, + nloni, + self.nlono, + nlati, + self.nlato, + flag2D, + missing, + self.londx, + self.lonpt, + self.wtlon, + self.latdx, + self.latpt, + self.wtlat, + inmask, + ar, + outar) + + # Correct the shape of output weights + amskout.shape = outar.shape + + # Set the missing data mask of the output array, if any. + hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) + if hasMissing: + slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) + else: + slabMask = None + + # Combine missing data mask and output grid mask + # Note: slabMask and outmask are Boolean here + if self.outmask is not None: + outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) + if hasMissing: + outmask = numpy.ma.logical_or(outmask, slabMask) + else: + outmask = slabMask + + # Create the result TransientVariable (if input ar is an AbstractVariable) + # or masked array + if inputIsVariable == 1: + for i in range(len(order)): + if order[i] == 'x': + axislist[i] = self.outlon + elif order[i] == 'y': + axislist[i] = self.outlat + result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array( + outar, mask=outmask, fill_value=missing) + + if returnTuple == 0: + return result + else: + return result, amskout + + +class Regridder(Horizontal): + def __init__(self, ingrid, outgrid): + warnings.warn( + "While this will work for now, please note that the Regridder class has been " + + "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + + "Please edit your code accordingly", + Warning) + Horizontal.__init__(self, ingrid, outgrid) + + +def input_mask(ain, type, mask, missing=None): + """ #------------------------------------------------------------------- + # + # purpose: set up the input mask including missing from ain + # + # usage: + # + # passed : + # + # returned: + # + # + #------------------------------------------------------------------------""" + if type != 'h' and type != 'v': + raise ValueError('Mask type must be h or v') + return + + if missing is None: + try: + omit = ain.missing_value + except AttributeError: + omit = 1.0e20 + else: + omit = missing + + # ----- insert 0.0 in mask where array has missing data ------- + + mask_size = len(mask.shape) + data_size = len(ain.shape) + + if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a + + if data_size == 3: # caution: assuming standard order lat-lon varying the fastest + if type == 'h': + reduced = ain[0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[:, :, 0] + elif data_size == 4: + if type == 'h': + reduced = ain[0, 0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[0, :, :, 0] + else: + raise IndexError('Data size is out of range') + return + + amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + else: # 0.0 -> missing in passed mask + + amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + return omit, amskin diff --git a/regrid2/Lib/Lib/mvESMFRegrid.py b/regrid2/Lib/Lib/mvESMFRegrid.py new file mode 100644 index 00000000..235e1fd5 --- /dev/null +++ b/regrid2/Lib/Lib/mvESMFRegrid.py @@ -0,0 +1,483 @@ +""" +ESMF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import re +import numpy + +import ESMF +from . import esmf +from . import RegridError +from .mvGenericRegrid import GenericRegrid + +ESMF.Manager(debug=False) +HAVE_MPI = False +try: + from mpi4py import MPI + HAVE_MPI = True +except BaseException: + pass + +# constants +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class ESMFRegrid(GenericRegrid): + """ + Regrid class for ESMF + """ + + def __init__(self, srcGridshape, dstGridshape, dtype, + regridMethod, staggerLoc, periodicity, coordSys, + srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, + dstGridMask=None, hasDstBounds=False, dstGridAreas=None, + ignoreDegenerate=False, + **args): + """ + Constructor + @param srcGridShape tuple source grid shape + @param dstGridShape tuple destination grid shape + @param dtype a valid numpy data type for the src/dst data + @param regridMethod 'linear', 'conserve', or 'patch' + @param staggerLoc the staggering of the field, 'center' or 'corner' + @param periodicity 0 (no periodicity), + 1 (last coordinate is periodic, + 2 (both coordinates are periodic) + @param coordSys 'deg', 'cart', or 'rad' + @param hasSrcBounds tuple source bounds shape + @param hasDstBounds tuple destination bounds shape + @param ignoreDegenerate Ignore degenerate celss when checking inputs + """ + + # esmf grid objects (tobe constructed) + self.srcGrid = None + self.dstGrid = None + self.dtype = dtype + + self.srcGridShape = srcGridshape + self.dstGridShape = dstGridshape + self.ignoreDegenerate = ignoreDegenerate + self.ndims = len(self.srcGridShape) + + self.hasSrcBounds = hasSrcBounds + self.hasDstBounds = hasDstBounds + + self.regridMethod = BILINEAR + self.regridMethodStr = 'linear' + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.regridMethod = CONSERVE + self.regridMethodStr = 'conserve' + elif re.search('patch', regridMethod.lower()): + self.regridMethod = PATCH + self.regridMethodStr = 'patch' + + # data stagger + self.staggerloc = CENTER + self.staggerlocStr = 'center' + if isinstance(staggerLoc, str): + if re.search('vface', staggerLoc.lower(), re.I): + self.staggerloc = VFACE + self.staggerlocStr = 'vcorner' + # there are other staggers we could test here + elif re.search('corner', staggerLoc.lower(), re.I) or \ + re.search('node', staggerLoc.lower(), re.I): + self.staggerloc = CORNER + self.staggerlocStr = 'corner' + # there are other staggers we could test here + + # good for now + unMappedAction = args.get('unmappedaction', 'ignore') + self.unMappedAction = ESMF.UnmappedAction.IGNORE + if re.search('error', unMappedAction.lower()): + self.unMappedAction = ESMF.UnmappedAction.ERROR + + self.coordSys = ESMF.CoordSys.SPH_DEG + self.coordSysStr = 'deg' + if re.search('cart', coordSys.lower()): + self.coordSys = ESMF.CoordSys.CART + self.coordSysStr = 'cart' + elif re.search('rad', coordSys.lower()): + self.coordSys = ESMF.CoordSys.SPH_RAD + self.coordSysStr = 'rad' + + self.periodicity = periodicity + + # masks can take several values in ESMF, we'll have just one + # value (1) which means invalid +# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) +# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) + + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.srcMaskValues = numpy.array([1], dtype=numpy.int32) + self.dstMaskValues = numpy.array([1], dtype=numpy.int32) + else: + self.srcMaskValues = srcGridMask + self.dstMaskValues = dstGridMask + + # provided by user or None + self.srcGridAreas = srcGridAreas + self.dstGridAreas = dstGridAreas + self.maskPtr = None + + # MPI stuff + self.pe = 0 + self.nprocs = 1 + self.comm = None + if HAVE_MPI: + self.comm = MPI.COMM_WORLD + self.pe = self.comm.Get_rank() + self.nprocs = self.comm.Get_size() + + # checks + if self.ndims != len(self.dstGridShape): + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological +dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ + (self.ndims, len(self.dstGridShape)) + raise RegridError(msg) + + # Initialize the grids without data. + self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasSrcBounds) + self.dstGrid = esmf.EsmfStructGrid(dstGridshape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasDstBounds) + + # Initialize the fields with data. + self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.srcFld.field.data[:] = -1 + self.dstFld.field.data[:] = -1 + self.srcAreaField.field.data[:] = 0.0 + self.dstAreaField.field.data[:] = 0.0 + self.srcFracField.field.data[:] = 1.0 + self.dstFracField.field.data[:] = 1.0 + + def setCoords(self, srcGrid, dstGrid, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + globalIndexing=False, **args): + """ + Populator of grids, bounds and masks + @param srcGrid list [[z], y, x] of source grid arrays + @param dstGrid list [[z], y, x] of dstination grid arrays + @param srcGridMask list [[z], y, x] of arrays + @param srcBounds list [[z], y, x] of arrays + @param srcGridAreas list [[z], y, x] of arrays + @param dstGridMask list [[z], y, x] of arrays + @param dstBounds list [[z], y, x] of arrays + @param dstGridAreas list [[z], y, x] of arrays + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + """ + + # create esmf source Grid + self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + + if srcGridMask is not None: + self.srcGrid.setMask(srcGridMask, self.staggerloc) + + if srcBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + # VCORNER for 3D + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + # create destination Grid + self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + if dstGridMask is not None: + self.dstGrid.setMask(dstGridMask) + + if dstBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args (not used) + """ + self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, + dstfield=self.dstFld.field, + src_mask_values=self.srcMaskValues, + dst_mask_values=self.dstMaskValues, + regrid_method=self.regridMethod, + unmapped_action=self.unMappedAction, + ignore_degenerate=True) + + def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): + """ + Regrid source to destination. + When used in parallel, if the processor is not the root processor, + the dstData returns None. + + Source data mask: + + . If you provide srcDataMask in args the source grid will + be masked and weights will be recomputed. + + . Subsequently, if you do not provide a srcDataMask the last + weights will be used to regrid the source data array. + + . By default, only the data are masked, but not the grid. + + @param srcData array source data, shape should + cover entire global index space + @param dstData array destination data, shape should + cover entire global index space + @param rootPe if other than None, then data will be MPI gathered + on the specified rootPe processor + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + @param **args + """ + +# if args.has_key('srcDataMask'): +# srcDataMask=args.get('srcDataMask') + # Make sure with have a mask intialized for this grid. + +# if(self.maskPtr is None): +# if(self.srcFld.field.grid.mask[self.staggerloc] is None): +# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) +# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, +# staggerloc=self.staggerloc) + # Recompute weights only if masks are different. +# if(not numpy.array_equal(self.maskPtr, srcDataMask)): +# self.maskPtr[:] = srcDataMask[:] +# self.computeWeights(**args) + + zero_region = ESMF.Region.SELECT + if 'zero_region' in args.keys(): + zero_region=args.get('zero_region') + + self.srcFld.field.data[:] = srcData.T + self.dstFld.field.data[:] = dstData.T + # regrid + + self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) + + # fill in dstData + if rootPe is None and globalIndexing: + # only fill in the relevant portion of the data + slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) + dstData[slab] = self.dstFld.getData(rootPe=rootPe) + else: + tmp = self.dstFld.field.data.T + if tmp is None: + dstData = None + else: + dstData[:] = tmp + + def getDstGrid(self): + """ + Get the destination grid on this processor + @return grid + """ + return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) + for i in range(self.ndims)] + + def getSrcAreas(self, rootPe): + """ + Get the source grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.srcAreaField.field.get_area() + return self.srcAreaField.field.data + else: + return None + + def getDstAreas(self, rootPe): + """ + Get the destination grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.dstAreaField.field.get_area() + return self.dstAreaField.field.data + else: + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.srcFracField.field.data + else: + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.dstFracField.field.data + else: + return + + def getSrcLocalShape(self, staggerLoc): + """ + Get the local source coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getCoordShape(stgloc) + + def getDstLocalShape(self, staggerLoc): + """ + Get the local destination coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getCoordShape(stgloc) + + def getSrcLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center'): + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getLocalSlab(stgloc) + + def getDstLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center') + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getLocalSlab(stgloc) + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'srcAreaFractions', 'dstAreaFractions', + 'srcAreas', 'dstAreas' + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + oldMethods = {} + oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' + oldMethods['dstAreaFractions'] = 'getDstAreaFractions' + oldMethods['srcAreas'] = 'getSrcAreas' + oldMethods['dstAreas'] = 'getDstAreas' + for entry in 'srcAreaFractions', 'dstAreaFractions', \ + 'srcAreas', 'dstAreas': + if entry in diag: + diag[entry] = eval( + 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T + diag['regridTool'] = 'esmf' + diag['regridMethod'] = self.regridMethodStr + diag['periodicity'] = self.periodicity + diag['coordSys'] = self.coordSysStr + diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/Lib/mvGenericRegrid.py b/regrid2/Lib/Lib/mvGenericRegrid.py new file mode 100644 index 00000000..2452e9c4 --- /dev/null +++ b/regrid2/Lib/Lib/mvGenericRegrid.py @@ -0,0 +1,313 @@ +""" +Generic interface to multiple regrid classes. No dependence on cdms2 variables. + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import operator +import numpy + +import regrid2 +import re +from distarray import MultiArrayIter +from functools import reduce + +# used to locate fully masked cells +EPS = 10 * 1.19209e-07 + + +def guessPeriodicity(srcBounds): + """ + Guess if a src grid is periodic + @param srcBounds the nodal src set of coordinates + @return 1 if periodic, warp around, 0 otherwise + """ + res = 0 + if srcBounds is not None: + res = 1 + # assume longitude to be the last coordinate + lonsb = srcBounds[-1] + nlon = lonsb.shape[-1] + dlon = (lonsb.max() - lonsb.min()) / float(nlon) + tol = 1.e-2 * dlon + if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] + ).sum() / float(lonsb.size)) > tol: + # looks like a regional model + res = 0 + return res + + +class GenericRegrid: + """ + Generic Regrid class. + """ + + def __init__(self, srcGrid, dstGrid, + dtype, + regridMethod, + regridTool, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + **args): + """ + Constructor. + @param srcGrid list of numpy arrays, source horizontal coordinates + @param dstGrid list of numpy arrays, destination horizontal coordinate + @param dtype numpy data type for src/dst data + @param regridMethod linear (bi, tri,...) default or conservative + @param regridTool currently either 'libcf' or 'esmf' + @param srcGridMask array of same shape as srcGrid + @param srcBounds list of numpy arrays of same shape as srcGrid + @param srcGridAreas array of same shape as srcGrid + @param dstGridMask array of same shape as dstGrid + @param dstBounds list of numpy arrays of same shape as dstGrid + @param dstGridAreas array of same shape as dstGrid + @param **args additional arguments to be passed to the + specific tool + 'libcf': mkCyclic={True, False}, handleCut={True,False} + 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... + """ + + self.nGridDims = len(srcGrid) + self.regridMethod = regridMethod + + if len(srcGrid) != len(dstGrid): + msg = 'mvGenericRegrid.__init__: mismatch in number of dims' + msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ + (self.nGridDims, len(dstGrid)) + raise regrid2.RegridError(msg) + + # parse the options + if re.search('libcf', regridTool.lower()) or \ + re.search('gsreg', regridTool.lower()): + # LibCF + self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + **args) + elif re.search('esm', regridTool.lower()): + # ESMF + staggerLoc = args.get('staggerLoc', 'center') + if 'staggerLoc' in args: + del args['staggerLoc'] + periodicity = args.get('periodicity', + guessPeriodicity(srcBounds)) + if 'periodicity' in args: + del args['periodicity'] + coordSys = args.get('coordSys', 'deg') + if 'coordSys' in args: + del args['coordSys'] + + # Get the shapes + self.srcGridShape = srcGrid[0].shape + self.dstGridShape = dstGrid[0].shape + self.hasSrcBounds = False + self.hasDstBounds = False + + if srcBounds is not None: + self.hasSrcBounds = True + + if dstBounds is not None: + self.hasDstBounds = True + + self.srcGridAreasShape = None + self.dstGridAreasShape = None + + if srcGridAreas is not None: + self.srcGridAreasShape = srcGridAreas[0].shape + + if dstGridAreas is not None: + self.dstGridAreasShape = dstGridAreas[0].shape + + # Initialize + self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, + dtype=dtype, + regridMethod=regridMethod, + staggerLoc=staggerLoc, + periodicity=periodicity, + coordSys=coordSys, + hasSrcBounds=self.hasSrcBounds, + hasDstBounds=self.hasDstBounds, + srcGridAreasShape=self.srcGridAreasShape, + dstGridAreasShape=self.dstGridAreasShape, + **args) + + self.tool.setCoords(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + srcGridAreas=srcGridAreas, + dstGridMask=dstGridMask, + dstBounds=dstBounds, + dstGridAreas=dstGridAreas, + globalIndexing=True, + **args) + else: + msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, +valid choices are: 'libcf', 'esmf'""" % regridTool + raise regrid2.RegridError(msg) + + def computeWeights(self, **args): + """ + Compute Weights + """ + self.tool.computeWeights(**args) + + def apply(self, srcData, dstData, + rootPe=None, + missingValue=None, + **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param rootPe if other than None, then results will be MPI + gathered + @param missingValue if not None, then data mask will be interpolated + and data value set to missingValue when masked + """ + + # assuming the axes are the slowly varying indices + srcHorizShape = srcData.shape[-self.nGridDims:] + dstHorizShape = dstData.shape[-self.nGridDims:] + + srcDataMaskFloat = None + dstDataMaskFloat = None + dstMask = None + if missingValue is not None: + srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) + dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) + + nonHorizShape = srcData.shape[: -self.nGridDims] + + if len(nonHorizShape) == 0: + + # + # no axis... just call apply + # + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (srcData == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later + indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), + dtype=srcData.dtype) + + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, **args) + if re.search('conserv', self.regridMethod.lower(), re.I): + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) + + # Initialize output to missin_value + dstData[:] = missingValue + # interpolate the data + self.tool.apply(indata, dstData, rootPe=rootPe, + globalIndexing=True, **args) + + # add missing values + dstData *= (1 - dstMask) + dstData += dstMask * missingValue + + else: + # no masking, just interpolate the data + self.tool.apply(srcData, dstData, rootPe=rootPe, + globalIndexing=True, **args) + else: + + nonHorizShape2 = dstData.shape[: -self.nGridDims] + if not numpy.all(nonHorizShape2 == nonHorizShape): + msg = 'mvGenericRegrid.apply: axes detected ' + msg += 'but %s != %s ' % (str(nonHorizShape2), + str(nonHorizShape)) + raise regrid2.RegridError(msg) + + # + # iterate over all axes + # + + # create containers to hold input/output values + # (a copy is essential here) + zros = '[' + ('0,' * len(nonHorizShape)) + '...]' + indata = numpy.array(eval('srcData' + zros)) + outdata = numpy.array(eval('dstData' + zros)) + + # now iterate over all non lat/lon coordinates + for it in MultiArrayIter(nonHorizShape): + + indices = it.getIndices() + slce = '[' + slce += reduce(operator.add, ['%d,' % i for i in indices]) + slce += '...]' + indata = eval('srcData' + slce) + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (indata == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later +# indata *= (1 - (srcDataMaskFloat == 1)) + +# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, + srcDataMask=(1 - srcDataMaskFloat), **args) + + if re.search('conserv', self.regridMethod.lower(), re.I): + # cell interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + # nodal interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 0), numpy.int32) + + # interpolate the data, using the appropriate tool + self.tool.apply(indata, outdata, rootPe=rootPe, + globalIndexing=True, + srcDataMask=srcDataMaskFloat, **args) + +# import vcs +# pp = vcs.init() +# pp.plot(indata) +# pp.interact() +# pp.clear() +# pp.plot(outdata) +# pp.interact() +# pp.clear() + # apply missing value contribution + if missingValue is not None: + # add mask contribution + outdata *= (1 - dstMask) + outdata += dstMask * missingValue + + # fill in dstData + exec('dstData' + slce + ' = outdata') + + def getDstGrid(self): + """ + Return the destination grid, may be different from the dst grid provided + to the constructor due to domain decomposition + @return local grid on this processor + """ + return self.tool.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe=None): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + entries are tool dependent + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/Lib/mvLibCFRegrid.py b/regrid2/Lib/Lib/mvLibCFRegrid.py new file mode 100644 index 00000000..30c5f4bf --- /dev/null +++ b/regrid2/Lib/Lib/mvLibCFRegrid.py @@ -0,0 +1,101 @@ +""" +LibCF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" + +from regrid2 import gsRegrid +from regrid2 import GenericRegrid + + +class LibCFRegrid(GenericRegrid): + """ + """ + + def __init__(self, srcGrid, dstGrid, srcGridMask=None, + srcBounds=None, **args): + """ + Constructor + @param srcGrid array + @param dstGrid array + @param srcBounds cell boundaries + @param **args keyword arguments, eg mkCyclic, handleCut, ... + to be passed to gsRegrid + """ + self.regridMethodStr = 'linear' + self.mkCyclic = args.get('mkCyclic', False) + self.handleCut = args.get('handleCut', False) + self.verbose = args.get('verbose', False) + self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, + src_bounds=srcBounds, + mkCyclic=self.mkCyclic, + handleCut=self.handleCut) + if srcGridMask is not None: + self.regridObj.setMask(srcGridMask) + + # min resolution, required in order to set the tolerance (tolpos) + self.delta = float('inf') + for i in range(len(dstGrid)): + coordMin = dstGrid[i].min() + coordMax = dstGrid[i].max() + n = max(dstGrid[i].shape) + self.delta = min(self.delta, (coordMax - coordMin) / float(n)) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args arguments to be passed to gsRegrid, e.g. + nitermax, tolpos, ... + """ + nitermax = args.get('nitermax', 20) + # make tolpos relative to the min cell size + tolpos = args.get('tolpos', 0.01) * self.delta + self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) + + def apply(self, srcData, dstData, missingValue=None, **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param missingValue value that should be set for points falling outside + the src domain, pass None if these should not be + touched. + """ + + self.regridObj.apply(srcData, dstData, missingValue) + + def getSrcGrid(self): + """ + Get the grid of the src data (maybe larger than the + dst grid passed to the constructor due to column/row + padding) + @return grid + """ + return self.regridObj.getSrcGrid() + + def getDstGrid(self): + """ + Get the grid of the dst data + @return grid + """ + return self.regridObj.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'numDstPoints' and 'numValid' + @param rootPe not used + """ + for entry in 'numDstPoints', 'numValid': + if entry in diag: + meth = 'get' + entry[0].upper() + entry[1:] + diag[entry] = eval('self.regridObj.' + meth + '()') + diag['regridTool'] = 'libcf' + diag['regridMethod'] = self.regridMethodStr + diag['handleCut'] = self.handleCut + diag['mkCyclic'] = self.mkCyclic + diag['verbose'] = self.verbose diff --git a/regrid2/Lib/Lib/mytest.py b/regrid2/Lib/Lib/mytest.py new file mode 100644 index 00000000..e91d1361 --- /dev/null +++ b/regrid2/Lib/Lib/mytest.py @@ -0,0 +1,2 @@ +import ESMF # noqa +from .mvESMFRegrid import ESMFRegrid # noqa diff --git a/regrid2/Lib/Lib/pressure.py b/regrid2/Lib/Lib/pressure.py new file mode 100644 index 00000000..fb79a9e2 --- /dev/null +++ b/regrid2/Lib/Lib/pressure.py @@ -0,0 +1,490 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by +import cdms2 +import numpy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import copy + + +class PressureRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along + # the pressure dimension only. + # + # PROCEDURE: Step One: + # Make an instance of class PressureRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, axisIn, axisOut): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, levIn, levOut): + # + # PROCEDURE: + # + # The user must assemble two pieces of information: + # + # axisIn - the input level axis + # + # axisOut - the output level axis + # + # USAGE: + # + # To make an instance preparing for a regrid along the level dimension pnly, type + # + # r = PressureRegridder(levIn, levOut) + # + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.axisIn = axisIn + self.axisOut = axisOut + self.nlevi = len(axisIn) + self.nlevo = len(axisOut) + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the pressure regridder function. + ar is the input array, a variable, masked array, or numpy array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = ar.getAxisList() + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # Set missing value + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 3: + order = "zyx" + elif rank == 4: + order = "tzyx" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to positionIn + positionIn = [None] * 4 + for i in range(len(order)): + if order[i] == 'x': + positionIn[0] = i + elif order[i] == 'y': + positionIn[1] = i + elif order[i] == 'z': + positionIn[2] = i + if inputIsVariable: + axislist[i] = self.axisOut + else: + positionIn[3] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + if inputIsVariable == 1: + result = cdms2.createVariable(outar, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, + logYes='yes', positionIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, + # dataout along the level dimension only. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using + # the value passed in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence longitude, + # latitude, level and time. Longitude, latitude and level are + # required. If time is missing submit None in its slot in the + # tuple. Notice that the length of the tuple is always four. + # + # Explicitly, in terms of the shape of dataIn as returned by Python's shape function + # + # positionIn[0] contains the position of longitude in dataIn + # positionIn[1] contains the position of latitude in dataIn + # positionIn[2] contains the position of level in dataIn or None + # positionIn[3] contains the position of time in dataIn or None + # + # As examples: + # If the C order shape of 4D data is + # (number of longitudes, number of times, number of levels, + # number of latitudes) + # submit + # (0, 3, 2, 1) + # + # If the C order shape of 3D data is + # (number of longitudes, number of times, number oflatitudes) + # submit + # (0, 2, 1, None) + # + # Send in None if the shape is a subset of (time, level, + # latitude, longitude) which is evaluated as follows: + # 3D -- code assumes (2,1,0,None) + # 4D -- code assumes (3,2,1,0) + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last + # resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # ----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + # --- evaluate positionIn ---- + + # --- make standard positionIn as a check---- + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + for n in range(numberDim, 4): # fill end of list with Nones + positionList.append(None) + + positionCheck = tuple(positionList) + + standardPosition = 0 # transpose required + + if positionIn is None: # construct the default positionIn tuple + positionIn = positionCheck + standardPosition = 1 # no need for a transpose with this data + else: + if positionIn == positionCheck: # compare to the standard + standardPosition = 1 # no need for a transpose with this data + + if len(positionIn) != 4: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' + sendmsg(msg) + raise TypeError + + # transpose data to the standard order (t,z,y,x) + if standardPosition == 0: + + newOrder, inverseOrder = checkorder(positionIn) + + # transpose data to standard order (t,z,y,x) + dataIn = numpy.transpose(dataIn, newOrder) + dataIn = numpy.array( + dataIn.astype( + numpy.float32), + numpy.float32) # make contiguous + + # set dimension sizes and check for consistency + + if positionIn[0] is not None: + self.nlon = (dataShape[positionIn[0]]) + else: + self.nlon = 0 + if positionIn[1] is not None: + self.nlat = (dataShape[positionIn[1]]) + else: + self.nlat = 0 + if positionIn[2] is not None: + if self.nlevi != (dataShape[positionIn[2]]): + msg = 'Level size is inconsistent with input data' + sendmsg(msg) + raise ValueError + if positionIn[3] is not None: + self.ntime = (dataShape[positionIn[3]]) + else: + self.ntime = 0 + + # allocate memory for dataOut -- the array with new number of levels + + outList = list(dataIn.shape) + + for i in range(len(outList)): + if outList[i] == self.nlevi: + outList[i] = self.nlevo + break + + dataOut = numpy.zeros( + tuple(outList), + numpy.float32) # memory for aout + + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.axisIn[:].astype(numpy.float64) + levOut = self.axisOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlat, + self.nlon, + self.ntime, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + dataIn, + dataOut) + + # if no missing do not pass None + if missingMatch == 'none': + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + if standardPosition == 0: + # transpose data to original order + dataOut = numpy.transpose(dataOut, inverseOrder) + dataOut = numpy.array( + dataOut.astype( + numpy.float32), + numpy.float32) # make contiguous + + if missingValueOut is not None: # set the missing value in data to missingValueOut + + if missingMatch == 'greater': + if missingValueIn > 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.greater( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'equal': + missing = missingValueIn + dataOut = numpy.where( + numpy.equal( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'less': + if missingValueIn < 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.less( + dataOut, + missing), + missingValueOut, + dataOut) + + return dataOut + + +def checkorder(positionIn): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the tuples for transposing the data to standard dimension order and the + # inverse for transposing it back to the original dimension order + # + # usage: newOrder, inverseOrder = checkorder(positionIn) + # + # passed: positionIn -- array with location of longitude, latitude. level and time respectively + # in the sense of the python shape of the data + # + # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) + # inverseOrder -- tuple to transpose data to back to the original order + # + #----------------------------------------------------------------------------------------------""" + + # remove the None values from positionIn and reverse the order + + reducedPosition = [] + for item in positionIn: + if item is not None: + reducedPosition.append(item) + reducedPosition.reverse() + + # make the newOrder tuple + + newOrder = tuple(reducedPosition) + + # ----- Determine the inverse to this new order for use in mathtogeo ----- + + xform = [] + for i in range(len(newOrder)): + xform.append([newOrder[i], i]) + xform.sort() + + inverse_shapelist = [] + for item in xform: + inverse_shapelist.append(item[1]) + inverseOrder = tuple(inverse_shapelist) + + return newOrder, inverseOrder + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None diff --git a/regrid2/Lib/Lib/scrip.py b/regrid2/Lib/Lib/scrip.py new file mode 100644 index 00000000..5a052700 --- /dev/null +++ b/regrid2/Lib/Lib/scrip.py @@ -0,0 +1,447 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +#from . import _scrip +import regrid2._scrip as _scrip +from .error import RegridError +import numpy +from functools import reduce + +"""Regrid support for nonrectangular grids, based on the SCRIP package.""" + + +class ScripRegridder: + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + self.outputGrid = outputGrid + self.remapMatrix = remapMatrix + self.sourceAddress = sourceAddress + self.destAddress = destAddress + self.inputGrid = inputGrid + self.sourceFrac = sourceFrac + self.destFrac = destFrac + + def __call__(self, input): + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + # this expects contiguous arrays + if input.iscontiguous() is False: + input = input.ascontiguous() + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + + # Regrid + output = self.regrid(input) + + # Reshape output and restore input shape + input.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + def getOutputGrid(self): + return self.outputGrid + + def getInputGrid(self): + return self.inputGrid + + def getSourceFraction(self): + return self.sourceFrac + + def getDestinationFraction(self): + return self.destFrac + + +class ConservativeRegridder(ScripRegridder): + """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' + is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length + as the output grid size, with values: + 1.0 for normalize="fracarea", + grid_frac for normalize="destarea", or + grid_frac*grid_area for normalize="none". + sourceArea is the area of the source grid cells + destArea is the area of the destination grid cells + """ + + def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, + sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): + if normalize not in ["fracarea", "destarea", "none"]: + raise RegridError("Invalid normalization option: %s" % normalize) + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + self.normalize = normalize + self.normal = None + self.sourceArea = sourceArea + self.destArea = destArea + + def getSourceArea(self): + return self.sourceArea + + def getDestinationArea(self): + return self.destArea + + def regrid(self, input): + if self.normal is None: + # print "On input, num_links = %d"%(len(self.sourceAddress)) + # print "On input, nextra = %d"%(input.shape[0]) + # print "On input, ninput = %d"%(input.shape[1]) + # print "On input, noutput = %d"%(self.outputGrid.size()) + # print "On input, shape(input) = %s"%`input.shape` + # print "On input, shape(output) = %s"%`self.outputGrid.shape` + # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` + # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` + # print "On input, shape(dst_address) = + # %s"%`self.destAddress.shape` + result = _scrip.conserv_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + else: + result = _scrip.conserv_regrid_normal( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + self.normal) + return result + + +class BilinearRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.bilinear_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +class BicubicRegridder(ScripRegridder): + """Bicubic regrid.""" + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def __call__(self, input, gradLat, gradLon, gradLatlon): + """gradLat = df/di + gradLon = df/dj + gradLatlon = d(df)/(di)(dj) + """ + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + if (gradLat.shape != input.shape or + gradLon.shape != input.shape or + gradLatlon.shape != input.shape): + raise RegridError( + "All input arrays must have shape %s" % + repr( + input.shape)) + + if (not isinstance(gradLat, type(input)) or + not isinstance(gradLon, type(input)) or + not isinstance(gradLatlon, type(input))): + raise RegridError( + "All input arrays must have type %s" % + repr( + type(input))) + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + gradLat = gradLat.subSlice() + gradLon = gradLon.subSlice() + gradLatlon = gradLatlon.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + gradLat = gradLat.filled() + gradLon = gradLon.filled() + gradLatlon = gradLatlon.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + gradLat.shape = newshape + gradLon.shape = newshape + gradLatlon.shape = newshape + + # Regrid + output = _scrip.bicubic_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + gradLat, + gradLon, + gradLatlon) + + # Reshape output and restore input shape + input.shape = oldshape + gradLat.shape = oldshape + gradLon.shape = oldshape + gradLatlon.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + +class DistwgtRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.distwgt_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +def readRegridder(fileobj, mapMethod=None, checkGrid=1): + """Read a regridder from an open fileobj. + mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method + defined in the file. + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, + and 'repaired' if necessary. + """ + + if isinstance(fileobj, str): + fileobj = cdms2.open(fileobj) + elif not isinstance(fileobj, cdms2.dataset.CdmsFile): + raise RegridError( + "fileobj arguments must be a cdms2 file or a string pointing to a file") + + if mapMethod is None: + mapString = fileobj.map_method.strip().lower() + if mapString[0:12] == "conservative": + mapMethod = "conservative" + elif mapString[0:8] == "bilinear": + mapMethod = "bilinear" + elif mapString[0:7] == "bicubic": + mapMethod = "bicubic" + elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": + mapMethod = "distwgt" + else: + raise RegridError("Unrecognized map method: %s" % mapString) + + convention = 'SCRIP' + if list(fileobj.variables.keys()).count('S'): + convention = 'NCAR' + if convention == 'SCRIP': + remapMatrix = fileobj('remap_matrix').filled() + srcAddress = fileobj('src_address').filled() + dstAddress = fileobj('dst_address').filled() + srcfrac = fileobj('src_grid_frac') + dstfrac = fileobj('dst_grid_frac') + else: + remapMatrix = fileobj('S').filled() + srcAddress = fileobj('col').filled() + dstAddress = fileobj('row').filled() + srcfrac = fileobj('frac_a') + dstfrac = fileobj('frac_b') + ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) + outgrid = fileobj.readScripGrid( + whichGrid="destination", + checkGrid=checkGrid) + + if mapMethod == "conservative": + if convention == 'SCRIP': + srcarea = fileobj('src_grid_area') + dstarea = fileobj('dst_grid_area') + else: # NCAR stuff + if "S2" in list(fileobj.variables.keys()): + remapMatrix = fileobj("S2") + sh = list(remapMatrix.shape) + if len(sh) == 2 and sh[-1] == 2: + sh[-1] = 1 + S = fileobj("S").filled() + S.shape = sh + remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) + srcarea = fileobj('area_a') + dstarea = fileobj('area_b') + regridder = ConservativeRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac, + sourceArea=srcarea, + destArea=dstarea) + elif mapMethod == "bilinear": + regridder = BilinearRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "bicubic": + regridder = BicubicRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "distwgt": + regridder = DistwgtRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + else: + raise RegridError("Unrecognized map method: %s" % mapMethod) + + return regridder diff --git a/regrid2/Lib/PET0.ESMF_LogFile b/regrid2/Lib/PET0.ESMF_LogFile new file mode 100644 index 00000000..3494c8e2 --- /dev/null +++ b/regrid2/Lib/PET0.ESMF_LogFile @@ -0,0 +1 @@ +20170308 152041.534 INFO PET0 Running with ESMF Version 7.0.0 diff --git a/regrid2/Lib/__init__.py b/regrid2/Lib/__init__.py new file mode 100644 index 00000000..36b7f9e2 --- /dev/null +++ b/regrid2/Lib/__init__.py @@ -0,0 +1,36 @@ +"""Interface to regridding facilities +""" + +__all__ = ["horizontal", "pressure", "crossSection", "scrip", + "error", "mvGenericRegrid", ] + +from .error import RegridError # noqa +from .horizontal import Horizontal, Regridder # noqa +from .pressure import PressureRegridder # noqa +from .crossSection import CrossSectionRegridder # noqa +from .scrip import ConservativeRegridder, BilinearRegridder, BicubicRegridder # noqa +from .scrip import DistwgtRegridder, readRegridder # noqa +from regrid2 import gsRegrid # noqa +from .mvGenericRegrid import GenericRegrid # noqa +from .mvLibCFRegrid import LibCFRegrid # noqa +try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + from .mvESMFRegrid import ESMFRegrid # noqa +except BaseException: + pass + +from . import git # noqa + +ESMF_HAS_BEEN_INITIALIZED = False +if not ESMF_HAS_BEEN_INITIALIZED: + try: + import ESMF + ESMF.deprecated.__globals__[ + 'warnings'].warn_explicit = ESMF.deprecated.__globals__['warnings'].formatwarning + ESMF.Manager(debug=False) + # this turns off the PET file logs + ESMF_HAS_BEEN_INITIALIZED = True + except BaseException: + pass diff --git a/regrid2/Lib/crossSection.py b/regrid2/Lib/crossSection.py new file mode 100644 index 00000000..cf23b45d --- /dev/null +++ b/regrid2/Lib/crossSection.py @@ -0,0 +1,1092 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklatpass) + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print(('calculated cross section test case rms error = ', error)) diff --git a/regrid2/Lib/crossSection.py.orig b/regrid2/Lib/crossSection.py.orig new file mode 100644 index 00000000..c06eae4a --- /dev/null +++ b/regrid2/Lib/crossSection.py.orig @@ -0,0 +1,1095 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +import numpy +import copy +from . import _regrid +from .error import RegridError + + +class CrossSectionRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data in the + # latitude-level plane for all times + # + # PROCEDURE: Step One: + # Make an instance of class CrossSectionRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, latIn, latOut, levIn, levOut, latTypeIn=None, latSizeIn=None, + latTypeOut=None, latSizeOut=None): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, latIn, latOut, levIn, levOut, latTypeIn = None, latSizeIn = None, + # latTypeOut = None, latSizeOut = None): + # + # PROCEDURE: + # + # The user must assemble at least the following four pieces of information: + # + # latIn - the axis specifying the latitude grid for the input data + # + # latOut - the axis specifying the latitude grid for the output data + # + # levIn - the axis specifying the pressure grid for the input data + # + # levOut - the axis specifying the pressure grid for the output data + # + # + # Additional information is required if a latitude grid is not global. It may be generic. + # Otherwise it is a subset of one of the standard global grids. Correspondingly, the choice + # for the grid type must be 'gaussian', 'equalarea', 'uniform' or 'generic'. In addition, the + # computation requires the size of the global grid from which the subset was choosen. Consequently, + # the user must assemble: + # + # latTypeIn -- for input latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeIn -- for input latitude, the size of the goblal grid used in selecting the region + # + # latTypeOut -- for output latitude, one of the following: + # 'gaussian' + # 'equalarea' + # 'uniform' + # 'generic' + # + # latSizeOut -- for output latitude, the size of the goblal grid used in selecting the region + # + # USAGE: + # + # To make an instance preparing for a global to global regrid, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut) + # + # To make an instance preparing for a global to a regional grid which, for example, is a subset of + # a global gaussian grid of size 64, type + # + # r = CrossSectionRegridder(latIn, latOut, levIn, levOut, latTypeOut = 'gaussian', latSizeOut = 64) + # + # where the latOut axis must have been selected from the global 64 length gaussian grid + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.latOut = latOut + self.levIn = levIn + self.levOut = levOut + self.nlevi = len(levIn) + self.nlevo = len(levOut) + + latIn, self.nlati = checkdimension(latIn, 'input latitude') + latOut, self.nlato = checkdimension(latOut, 'output latitude') + + # --- check for a single grid point in the latitude-level plane + + if self.nlevo == 1 and self.nlato != 1: + sendmsg( + 'Error in output grid - a single level value requires a single latitude value') + raise ValueError + if self.nlevo != 1 and self.nlato == 1: + sendmsg( + 'Error in output grid - a single latitude value requires a single longitude value') + raise ValueError + if self.nlevo == 1 and self.nlato == 1: + calculateMean = 1 + msg = 'Warning -- regridding a cross section to a single point does not produce the global mean' + sendmsg(msg) + else: + calculateMean = 0 + + # --- get the latitude coordinate grid boundaries for the input grid + + if latTypeIn is None: # global latIn + lat_wts_bndsIn = get_latitude_wts_bnds(latIn) + else: + lat_wts_bndsIn = get_region_latitude_wts_bnds( + latIn, latTypeIn, latSizeIn) + + lat_bndsIn = lat_wts_bndsIn[1] + bnin, bsin = latitude_bounds(lat_bndsIn) + + if calculateMean == 0: # meaningful grid + + # --- get the latitude coordinate grid boundaries for the output grid + + if latTypeOut is None: # global latOut + lat_wts_bndsOut = get_latitude_wts_bnds(latOut) + else: + lat_wts_bndsOut = get_region_latitude_wts_bnds( + latOut, latTypeOut, latSizeOut) + + lat_bndsOut = lat_wts_bndsOut[1] + bnout, bsout = latitude_bounds(lat_bndsOut) + + else: + bnout = numpy.array([90.0], numpy.float32) + bsout = numpy.array([-90.0], numpy.float32) + + # --- call maplength to get the rest of the self data needed by rgrdlength + + t = _regrid.maplength(self.nlati, self.nlato, bnin, bnout, bsin, bsout) + + self.latdx, self.latpt, self.wtlat = t + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the regridder function. + ar is the input array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 3, 'Array rank is %i, must be 2, or 3' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = "zy" + else: + order = "tzy" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = str.lower(order) + + # Map order to positionIn + positionIn = [None] * 3 + for i in range(len(order)): + if order[i] == 'y': + positionIn[0] = i + if inputIsVariable: + axislist[i] = self.latOut + elif order[i] == 'z': + positionIn[1] = i + if inputIsVariable: + axislist[i] = self.levOut + else: + positionIn[2] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + # Mask fill_value and return results + print("INPUT IS VAR:", inputIsVariable) + if inputIsVariable == 1: + result = numpy.ma.masked_values(outar, missing) + result = cdms2.createVariable(result, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + result = numpy.ma.masked_values(result, missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, logYes='yes', + positionIn=None, maskIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, dataout in + # the latitude-level plane. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, maskIn = None, + # missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using the value passed + # in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence latitude, + # level and time. Latitude and level are required. If time is missing submit None in its + # slot in the tuple. Notice that the length of the tuple is + # always three. + # + # Explicitly, in terms of the shape of dataIn as returned by python's shape function + # + # positionIn[0] contains the position of latitude in dataIn + # positionIn[1] contains the position of level in dataIn or None + # positionIn[2] contains the position of time in dataIn or None + # + # As examples: + # If the c order shape of 3D data is + # (number of times, number of levels, number of latitudes) + # submit + # (2, 1, 0). + # + # If the c order shape of 2D data is + # (number of times, number of latitudes) + # submit + # (1, None, 0). + # + # Send in None if the shape is a subset of (time, level, latitude) which is evaluated + # as follows: + # 2D -- code assumes (1,0,None) + # 3D -- code assumes (2,1,0) + # + # maskIn -- an array of 1.0 and 0.0 values where the 0.0 value is used to mask the input data. This + # mask only works on the latitude grid. It is not possible to mask out a region in the level + # plane. The 0.0 value removes the data from correponding grid point. The user can supply the + # following choices: + # + # None -- an array of 1.0s is created followed by substituting 0.0s for grid points with missing + # data in the input data array, dataIn + # + # array -- an array of 1.0s or 0.0s which must be either 2D or the actual size of the input data, + # dataIn. This user supplied mask might be used to mask a latitude region. It is not + # required to account for missing data in the input data. The code uses missingValueIn + # and missingMatch to supply the 0.0s for grid points with missing data in the input + # data array, dataIn. + # + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # WARNING: This code does not regrid cross sections which have a single dummy longitude value! + # + # + #-----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # try to identify a single dummy longitude + + dataShape = dataIn.shape + + if len(dataShape) > 3: + msg = 'Error in call to rgrd -- cross section data can not have more than 3 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is not None: + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # set missing value to be used in dataOut + + if missingValueOut is None: + if missingValueIn is not None: + # default + omit = missingValueIn + else: + # default + omit = 1.0e20 + else: + # user choice + omit = missingValueOut + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + # produce the input for rgdlength not generated by maplength + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + if positionIn is None: # construct the default positionIn tuple + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + if numberDim == 2: # fill end of list with a None + positionList.append(None) + + positionIn = tuple(positionList) + + if len(positionIn) != 3: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 3' + sendmsg(msg) + raise TypeError + + # set ilon, ilat in Fortran order except that the first index is 0 - + # not 1 + ilat = numberDim - 1 - positionIn[0] + + itim1 = itim2 = -1 + ntim1 = ntim2 = 0 + + if numberDim == 2: # lat and level field + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + + if numberDim == 3: # lon_lat field + level + time + itim1 = numberDim - 1 - positionIn[1] + ntim1 = dataShape[positionIn[1]] + itim2 = numberDim - 1 - positionIn[2] + ntim2 = dataShape[positionIn[2]] + + # check for consistency between the grid axiss and the dataIn shape + + if self.nlati != (dataShape[positionIn[0]]): + msg = 'Latitude vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + if self.nlevi != (dataShape[positionIn[1]]): + msg = 'Level vector is inconsistent with input data' + sendmsg(msg) + raise ValueError + + # allocate memory for aout -- the array with original number of levels + # but the new number of latitudes + + aoutList = list(dataIn.shape) + aoutList[positionIn[0]] = self.nlato + # memory for aout + aout = numpy.zeros(tuple(aoutList), numpy.float32) + + # generate the mask + + amskin = sectionmask( + dataIn, + positionIn, + maskIn, + missingValueIn, + missingMatch) + + # ------------- call rgdlength to regrid latitude --------------- + + _regrid.rgdlength( + ilat, + itim1, + itim2, + ntim1, + ntim2, + self.nlati, + self.nlato, + omit, + self.latdx, + self.latpt, + self.wtlat, + amskin, + dataIn, + aout) + + # ------------- call rgdpressure to regrid pressure ------------- + + # allocate memory for ap -- the array with new number of levels and the + # new number of latitudes + + apList = list(dataIn.shape) + apList[positionIn[0]] = self.nlato + apList[positionIn[1]] = self.nlevo + # memory for ap + ap = numpy.zeros(tuple(apList), numpy.float32) + + nlon = 0 + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.levIn[:].astype(numpy.float64) + levOut = self.levOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlato, + nlon, + ntim2, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + aout, + ap) + + if missingMatch == 'none': # if no missing do not pass None + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + return ap + + +def checkdimension(x, name): + """ #--------------------------------------------------------------------------------- + # + # purpose: dimension checks + # 1. has a len method + # 2. data type is float32 + # 3. monotonically increasing vectors + # + # passed : x - coordinate vector + # name - coordinate vector ID + # + # returned: x, xsize -- dimension vector and its size + # + #---------------------------------------------------------------------------------""" + + data = x[:] + try: + xsize = len(x) + except TypeError: + sendmsg('Hgrid instance error -- instance requires a ' + name) + raise TypeError + + if data.dtype.char != 'f': + x[:] = x[:].astype(numpy.float32) + + # ----- check for consistency ----- + + if x[0] > x[xsize - 1]: + for n in range(1, xsize): + if x[n] > x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + else: + for n in range(1, xsize): + if x[n] < x[n - 1]: + sendmsg('Hgrid instance error -- ' + name + 'not monotonic') + raise ValueError + return + + return x, xsize + + +def generic_wts_bnds(lat): + try: + bnds = lat.getBounds() + if bnds is None: # No bounds defined + newLat = lat.clone() + newLat.setBounds(None) + bnds = lat.getBounds() + except BaseException: # just an array.... + newLat = cdms2.createAxis(lat) + newLat.setBounds(None) + bnds = newLat.getBounds() + outBnds = bnds[:, 0].tolist() + outBnds.append(bnds[-1][-1]) + outBnds = numpy.array(outBnds) + wts = [outBnds[i + 1] - outBnds[i] for i in range(len(lat))] + wts = numpy.array(wts) / numpy.sum(wts) + return wts, outBnds + + +def get_latitude_wts_bnds(checklatpass): + """ #------------------------------------------------------------------- + # + # routine: get_latitude_wts_bnds + # + # purpose: compare the passed checklatpass with the correct geophysical + # ones calculated here. After finding a match call the function + # to get the bounds. + # + # usage: wts,bnds = get_latitude_wts_bnds(checklatpass) + # where checklatpass is the grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + small = 0.001 # use as tolerance in checking values + + nlat = len(checklatpass) + + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if checklatpass[0] < checklatpass[nlat - + 1]: # need a copy? + checklat = numpy.array(checklatpass, numpy.float64) + checklat = checklat[::-1] + reverse_latitude = 'yes' + else: + checklat = checklatpass + + # ------ check the pass for evenly spaced latitudes ------- + + firstdelta = abs(checklat[0] - checklat[1]) + maxdiff = 0.0 + for i in range(1, nlat - 1): + diff = abs(firstdelta - (checklat[i] - checklat[i + 1])) + if diff > maxdiff: + maxdiff = diff + + if maxdiff < small: + # if abs(90. - checklat[0]) > small or abs(-90. - + # checklat[nlat - 1]) > small: + # grid_type = 'even' # evenly spaced without poles + # wts, bnds = generic_wts_bnds(checklat) + # if reverse_latitude == 'yes': + # wts = wts[::-1] + # bnds = bnds[::-1] + # return (wts, bnds) + # else: + grid_type = 'uniform' # evenly spaced with poles + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for gaussian latitudes ------- + + grid_type = 'gaussian' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ check the pass for equalarea latitudes ------- + + grid_type = 'equalarea' + pts_wts_bnds = _regrid.gridattr(nlat, grid_type) + latvals = pts_wts_bnds[0] + laterror = max(abs(latvals - checklat)) + if laterror < small: + wts = pts_wts_bnds[1] + bnds = pts_wts_bnds[2] + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + # ------ must be generic latitude ------- + wts, bnds = generic_wts_bnds(checklat) + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + return (wts, bnds) + + +def latitude_bounds(lat_bnds): + """ #------------------------------------------------------------------- + # + # purpose: set up the shape and bounds for use by maparea + # + # usage: + # + # returned: tuple ( bn,bs ) + # + #------------------------------------------------------------------------""" + + latbnds = lat_bnds.astype(numpy.float32) + + if latbnds[0] > latbnds[len(latbnds) - 1]: + bn = latbnds[:-1] + bs = latbnds[1:] + else: + bn = latbnds[1:] + bs = latbnds[:-1] + + return (bn, bs) + + +def get_region_latitude_wts_bnds(latRegionpass, latType, latSize): + """ #------------------------------------------------------------------- + # + # routine: get_region_latitude_wts_bnds + # + # purpose: compare the passed latitudes, latRegion, with the global + # ones calculated here and extract the wts and bounds for + # the region + # + # usage: wts,bnds = get_region_latitude_wts_bnds(latRegion, latType, latSize) + # where latRegion is the regional grid to check + # + # return: wts, bnds - tuple with weights and bounds + # + #-------------------------------------------------------------------------""" + + latTypeList = ['gaussian', 'equalarea', 'uniform', 'generic'] + + if latType not in latTypeList: + sendmsg( + "Error in latType -- it must be 'gaussian', 'equalarea', 'even' or 'generic' and not ", + latType) + raise ValueError + return + + if latSize is None: + sendmsg('Error in latSize -- it must be a number') + raise ValueError + return + + nlat = len(latRegionpass) + reverse_latitude = 'no' + + # ------ set latitude direction to n to s for comparisons ------- + + if latRegionpass[0] < latRegionpass[nlat - + 1]: # need a copy? + latRegion = numpy.array(latRegionpass, numpy.float64) + latRegion = latRegion[::-1] + reverse_latitude = 'yes' + else: + latRegion = latRegionpass + + small = 0.001 # use as tolerance in checking values + + # ------ check the pass for gaussian latitudes ------- + + if latType != 'generic': + # n to s global pts, wts and bnds + pts_wts_bnds = _regrid.gridattr(latSize, latType) + latvals = pts_wts_bnds[0] + + imatch = -1 + i = 0 + while(imatch == -1): + if abs(latvals[i] - latRegion[0]) < small: # first index found + startIndex = i + imatch = 0 + i = i + 1 + imatch = -1 + while(imatch == -1): + if abs(latvals[i] - latRegion[nlat - 1] + ) < small: # last index found + lastIndex = i + imatch = 0 + i = i + 1 + + wts = pts_wts_bnds[1][startIndex:lastIndex + 1] + bnds = pts_wts_bnds[2][startIndex:lastIndex + 2] + + if reverse_latitude == 'yes': + wts = wts[::-1] + bnds = bnds[::-1] + + return (wts, bnds) + +# else: # must be generic latitude ------- +# +# wts, bnds = generic_wts_bnds(latIn) +# if reverse_latitude == 'yes': +# wts = wts[::-1] +# bnds = bnds[::-1] +# return (wts, bnds) + + +def sectionmask(dataIn, positionIn, maskIn, missingValueIn, missingMatch): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the mask for the input data for use by rgdlength + # + # usage: amskin = mask(dataIn, positionIn, maskIn, missingValueIn, missingValueOut, flag2D) + # + # returned: amskin + # + #----------------------------------------------------------------------------------------------""" + # Logic outline + # START NO USER MASK SECTION ? + # + # START USER MASK SECTION ? + # USER SUPPLIED MASK IS 2D ? + # USER SUPPLIED MASK IS FULL SIZE ? + + # ---- check the missingMatch pass -------- + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less' + sendmsg(msg) + raise ValueError + + # ----- Check for missing data in dataIn, set missingFlag and miss, the va + + # missingFlag = 0 if there is no missing data + # missingFlag = 1 if there is missing data found using greater than missingValueIn + # missingFlag = 1 if there is missing data found using the default 1.0e20 + # missingFlag = 2 if there is missing data found using equal to missingValueIn + # missingFlag = 3 if there is missing data found using less than + # missingValueIn + + missingFlag = 0 + + # use value from the file + if missingValueIn is not None: + + if missingMatch == 'greater': + if missingValueIn > 0: + miss = 0.99 * missingValueIn + else: + miss = 1.01 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.greater( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 1 + + elif missingMatch == 'equal': + miss = missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.equal( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 2 + + elif missingMatch == 'less': + if missingValueIn > 0: + miss = 1.01 * missingValueIn + else: + miss = 0.99 * missingValueIn + n = numpy.add.reduce( + numpy.where( + numpy.less( + numpy.ravel(dataIn), + miss), + 1, + 0)) + if n > 0: + missingFlag = 3 + + # ----- get the shape of dataIn and set the number of dimensions in the da + + dataShape = dataIn.shape + # set size and check against positionIn + numberDataDim = len(dataShape) + + # remove the None fillers + reducedPositionIn = [] + for i in range(len(positionIn)): + if positionIn[i] is not None: + reducedPositionIn.append(positionIn[i]) + + if numberDataDim != len(reducedPositionIn): + msg = 'positionIn does not describe the number of dimensions in the data' + sendmsg(msg) + raise ValueError + + # ----- Determine the order of latitude and level in the data ------- + + # sequence is standard (lat,lon) + if positionIn[0] > positionIn[1]: + levlatFlag = 1 + else: + levlatFlag = 0 + + # ------------------------------------------------------------------------------------------------------ + # ----------------------------------------- Generate the mask ----------- + # ------------------------------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------------------------------ + # ---------- START NO USER MASK SECTION + + if maskIn is None: # ---- need to generate the mask from scratch ---- + + # allocate memory + amskin = numpy.ones(dataShape, numpy.float32) + + # ---------- START USER MASK SECTION + + else: # ---- use the users supplied mask ---- + + numberMaskDim = len(maskIn.shape) + + if numberMaskDim == 2: # ----------------------- USER SUPPLIED MASK IS 2D + + # mask shape is (lat,lon) + if levlatFlag == 1: + checkmaskShape = ( + dataShape[positionIn[1]], dataShape[positionIn[0]]) + # mask shape is (lon,lat) + else: + checkmaskShape = ( + dataShape[positionIn[0]], dataShape[positionIn[1]]) + + if maskIn.shape != checkmaskShape: # check the mask shape + msg = 'Error -- 2D mask supplied mask must have the same shape as corresponding slice in the input data' + sendmsg(msg) + raise IndexError + + # FINAL MASK IS FULL SIZED WITH USERS 2D MASK REPLICATED + + if numberDataDim > 2: + # replicate the mask to size of dataIn + amskin = numpy.resize(maskIn, dataShape) + + else: # ---------------------- USER SUPPLIED MASK IS FULL SIZE + + amskin = maskIn + + if numberMaskDim != numberDataDim: + msg = 'Error -- user supplied mask must be 2D or the size of the data' + sendmsg(msg) + raise IndexError + + if amskin.shape != dataIn.shape: + msg = 'Error -- full size mask supplied must have the same shape as the input data' + sendmsg(msg) + raise IndexError + + # there is missing data in dataIn to add to amskin + if missingFlag != 0: + if missingFlag == 1: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + elif missingFlag == 2: + amskin = numpy.where(numpy.equal(dataIn, miss), 0.0, amskin) + elif missingFlag == 3: + amskin = numpy.where(numpy.greater(dataIn, miss), 0.0, amskin) + + amskin = amskin.astype(numpy.float32) + + return amskin + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None + + +def section(latvals, levvals): + """ #--------------------------------------------------------------------------------- + # + # purpose: make the crossi section analytical test case + # + # passed : the grid coordinate vectors + # + # returned: xsection -- a temerature like cross section + # + #---------------------------------------------------------------------------------""" + + nlev = len(levvals) + + nlat = len(latvals) + theta = (math.pi / 180.) * latvals + + xsection = numpy.zeros((nlev, nlat), numpy.float32) # memory + + t0 = 60. + p0 = 1000. + + for j in range(nlat): + for i in range(nlev): + x = math.cos(theta[j])**2 + y = t0 * ((levvals[i] / p0)**.3) + xsection[i, j] = x * y - 30. + + return xsection + + +def rmserror(data1, data2): + """ #--------------------------------------------------------------------------------- + # + # purpose: compute the rms error for two data sets having the same shape + # + # passed : the two data sets + # + # returned: rms error + # + #---------------------------------------------------------------------------------""" + + if data1.shape != data2.shape: + print('Error in shape in rmserror') + print(('data1 shape = ', data1.shape)) + print(('data2 shape = ', data2.shape)) + raise ValueError + + d1 = numpy.ravel(data1) + d2 = numpy.ravel(data2) + + sq = (d1 - d2) * (d1 - d2) + error = numpy.sum(sq) / len(d1) + rmserror = numpy.sqrt(error) + + return rmserror + + +if __name__ == '__main__': + import math + + latIn = cdms2.createUniformLatitudeAxis(90.0, 46, -4.0) + levList = [10., 40., 75., 100., 150., 250., 350., 500., + 650., 850., 1000.] # pick some levels + levIn = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + latOut = cdms2.createGaussianAxis(64) + levList = [10., 30., 50., 70., 100., 200., 300., 400., + 500., 700., 850., 1000.] # pick some levels + levOut = cdms2.createAxis(numpy.array(levList, numpy.float64), id='level') + + xregridf = CrossSectionRegridder(latIn, latOut, levIn, levOut) + + # make some artificial data + dataIn = section(latIn[:], levIn[:]) + var = cdms2.createVariable( + dataIn, axes=( + levIn, latIn), attributes={ + 'units': 'N/A'}, id='test') + + dataOut = xregridf(dataIn) + + # make the exact answer + dataCheck = section(latOut[:], levOut[:]) + # find the rms error + error = rmserror(dataOut, dataCheck) + + print('expected cross section test case rms error = 0.18581882') + # print 'expected cross section test case rms error = 0.23062' + print('calculated cross section test case rms error = ', error) diff --git a/regrid2/Lib/error.py b/regrid2/Lib/error.py new file mode 100644 index 00000000..327dff22 --- /dev/null +++ b/regrid2/Lib/error.py @@ -0,0 +1,3 @@ +class RegridError (Exception): + def __init__(self, args="Unspecified error from regrid package"): + self.args = (args,) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py new file mode 100644 index 00000000..830910a1 --- /dev/null +++ b/regrid2/Lib/esmf.py @@ -0,0 +1,842 @@ +#!/usr/bin/env python + +""" +Copyright (c) 2008-2012, Tech-X Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the conditions +specified in the license file 'license.txt' are met. + +Authors: David Kindig and Alex Pletzer +""" +import re +import time +import numpy +from regrid2 import RegridError +import ESMF +from functools import reduce + +# constants +R8 = ESMF.TypeKind.R8 +R4 = ESMF.TypeKind.R4 +I8 = ESMF.TypeKind.I8 +I4 = ESMF.TypeKind.I4 +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF.StaggerLoc.CENTER_VCENTER +CENTER_VCENTER = ESMF.StaggerLoc.CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class EsmfUnstructGrid: + """ + Unstructured grid + """ + + def __init__(self, numTopoDims, numSpaceDims): + """Constructor + + Parameters + ---------- + + numTopoDims + number of topological dimensions + + numSpaceDims + number of space dimensions + """ + # handle to the grid object + self.grid = None + # whether or not nodes were added + self.nodesAdded = False + # whether or not cells were added + self.cellsAdded = False + # the local processor rank + self.pe = 0 + # number of processors + self.nprocs = 1 + # communicator + self.comm = None + + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + self.grid = ESMF.Mesh( + parametric_dim=numTopoDims, + spatial_dim=numSpaceDims) + + def setCells(self, cellIndices, cellTypes, connectivity, + cellMask=None, cellAreas=None): + """ + Set Cell connectivity + + Parameters + ---------- + + cell indices (0-based) + + cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + + connectivity node connectivity array, see below for node ordering + + cellMask + + cellAreas area (volume) of each cell + + Note + ---- + + 3 + / \ + / \ + / \ + / \ + / \ + 1 --------- 2 + + + + + 4------------3 + | | + | | + | | + | | + | | + 1 ---------- 2 + + + + 3 8---------------7 + /|\ /| /| + / | \ / | / | + / | \ / | / | + / | \ / | / | + / | \ 5---------------6 | + 4-----|-----2 | | | | + \ | / | 4----------|----3 + \ | / | / | / + \ | / | / | / + \ | / | / | / + \|/ |/ |/ + 1 1---------------2 + + ESMF_MESHELEMTYPE_TETRA ESMF.MESHELEMTYPE_HEX + + """ + n = len(cellIndices) + if not self.cellsAdded: + # node/cell indices are 1-based in ESMF + cellIndices += 1 + self.grid.add_elements(n, cellIndices, cellTypes, + connectivity, elementMask=cellMask, + elementArea=cellAreas) + self.cellsAdded = True + + def setNodes(self, indices, coords, peOwners=None): + """ + Set the nodal coordinates + + Parameters + ---------- + + indices Ids of the nodes (0-based) + + coords nodal coordinates + + peOwners processor ranks where the coordinates reside (0-based) + """ + n = len(indices) + if not self.nodesAdded: + if peOwners is None: + peOwners = numpy.ones((n,), numpy.int32) * self.pe + # node indices are 1-based + indices += 1 + self.grid.add_nodes(n, indices, coords, peOwners) + self.nodesAdded = True + + def toVTK(self, filename): + """ + Write grid to VTK file format + + Parameters + ---------- + + filename VTK file name + _: None + + """ + self.grid.write(filename) + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructGrid: + """ + Structured grid + """ + + def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, + periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, + hasBounds=False): + """ + Constructor + + Parameters + ---------- + + shape Tuple of cell sizes along each axis + + coordSys coordinate system + ESMF.CoordSys.CART Cartesian + ESMF.CoordSys.SPH_DEG (default) Degrees + ESMF.CoordSys.SPH_RAD Radians + + periodicity Does the grid have a periodic coordinate + 0 No periodicity + 1 Periodic in x (1st) axis + 2 Periodic in x, y axes + + staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX + The stagger constants are listed at the top + + hasBounds If the grid has bounds, Run AddCoords for the bounds + """ + # ESMF grid object + self.grid = None + # number of cells in [z,] y, x on all processors + self.shape = shape[::-1] + # number of dimensions + self.ndims = len(self.shape) + # whether or not cell areas were set + self.cellAreasSet = False + # whether or not nodal coords were set + self.nodesSet = False + # whether or not cell centered coordinates were set + self.centersSet = False + + # assume last 2 dimensions are Y,X + # For esmf reverse to X, Y + maxIndex = numpy.array(shape[::-1], dtype=numpy.int32) + + self.centersSet = False + periodic_dim = 0 + pole_dim = 1 + if periodicity == 0: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=0, staggerloc=[staggerloc], + coord_sys=coordSys) + elif periodicity == 1: + self.grid = ESMF.Grid(max_index=maxIndex, num_peri_dims=1, + periodic_dim=periodic_dim, pole_dim=pole_dim, + staggerloc=[staggerloc], coord_sys=coordSys) + else: + msg = """ +esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted. + """ % periodicity + raise RegridError(msg) + + # Grid add coordinates call must go here for parallel runs + # This occur before the fields are created, making the fields + # parallel aware. + if ((staggerloc == CENTER) and (not self.centersSet)): + self.centersSet = True + elif (staggerloc == CORNER) and (not self.nodesSet): + self.nodesSet = True + + if hasBounds is not None: + if self.ndims == 2: + self.grid.add_coords([CORNER], coord_dim=None, from_file=False) + if self.ndims == 3: + self.grid.add_coords( + [VCORNER], coord_dim=None, from_file=False) + + def getLocalSlab(self, staggerloc): + """ + Get the local slab (ellipsis). You can use this to grab + the data local to this processor + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple of slices + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([slice(lo[i], hi[i], None) + for i in range(self.ndims)])[::-1] + + def getLoHiBounds(self, staggerloc): + """ + Get the local lo/hi index values for the coordinates (per processor) + (hi is not inclusive, lo <= index < hi) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + lo, hi lists + """ + lo = self.grid.lower_bounds[staggerloc] + hi = self.grid.upper_bounds[staggerloc] + return lo, hi + + def getCoordShape(self, staggerloc): + """ + Get the local coordinate shape (may be different on each processor) + + Parameters + ---------- + + staggerloc + (e.g. ESMF.StaggerLoc.CENTER) + + _: None + + Returns + ------- + + tuple + """ + lo, hi = self.getLoHiBounds(staggerloc) + return tuple([hi[i] - lo[i] for i in range(self.ndims)])[::-1] + + def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): + """ + Populate the grid with staggered coordinates (e.g. corner or center). + + + Parameters + ---------- + + coords + The curvilinear coordinates of the grid. + List of numpy arrays. Must exist on all procs. + + staggerloc + The stagger location + ESMF.StaggerLoc.CENTER (default) + ESMF.StaggerLoc.CORNER + + globalIndexing + if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + + Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, + hence the dimensions are reversed here. + """ + # allocate space for coordinates, can only add coordinates once + for i in range(self.ndims): + ptr = self.grid.get_coords(coord_dim=i, staggerloc=staggerloc) + if globalIndexing: + slab = self.getLocalSlab(staggerloc)[::-1] + # Populate self.grid with coordinates or the bounds as needed + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[slab] + else: + ptr[:] = numpy.array(coords[self.ndims - i - 1]).T[:] + + def getCoords(self, dim, staggerloc): + """ + Return the coordinates for a dimension + + Parameters + --------- + + dim desired dimension (zero based indexing) + + staggerloc Stagger location + """ + gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) + shp = self.getCoordShape(staggerloc)[::-1] + return numpy.reshape(gridPtr, shp).T + + def setCellAreas(self, areas): + """ + Set the cell areas + + Parameters + --------- + + areas numpy array + + _: None + + """ + self.grid.add_item(item=ESMF.GridItem.Area) + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + areaPtr[:] = areas.T.flat + self.cellAreasSet = True + + def getCellAreas(self): + """ + + Returns + ------- + + cell areas or None if setCellAreas was not called + """ + if self.cellAreasSet: + areaPtr = self.grid.get_item( + item=ESMF.GridItem.AREA, + staggerloc=self.staggerloc) + return numpy.reshape(areaPtr, self.shape).T + else: + return None + + def getMask(self, staggerloc=CENTER): + """ + Get mask array. In ESMF, the mask is applied to cells. + + Returns + ------- + + mask numpy array. 1 is invalid by default. This array exists on all procs + """ + try: + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, staggerloc=staggerloc) + except BaseException: + maskPtr = None + return maskPtr.T + + def setMask(self, mask, staggerloc=CENTER): + """ + Set mask array. In ESMF, the mask is applied to cells. + + Parameters + ---------- + + mask numpy array. 1 is invalid by default. This array exists + on all procs + + _: None + """ + self.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=staggerloc) + maskPtr = self.grid.get_item( + item=ESMF.GridItem.MASK, + staggerloc=staggerloc) + slab = self.getLocalSlab(CENTER)[::-1] + maskPtr[:] = mask.T[slab] + + def __del__(self): + self.grid.destroy() + +########################################################################## + + +class EsmfStructField: + """ + Structured field. + """ + + def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): + """ + Creator for structured ESMF Field + + Parameters + ---------- + + esmfGrid + instance of an ESMF + + name field + name (must be unique) + + datatype + data type, one of 'float64', 'float32', 'int64', or 'int32' + (or equivalent numpy dtype) + + staggerloc + ESMF.StaggerLoc.CENTER + ESMF.StaggerLoc.CORNER + """ + # field object + self.field = None + # the local processor rank + self.pe = 0 + # the number of processors + self.nprocs = 1 + # associated grid + self.grid = esmfGrid + # staggering + self.staggerloc = staggerloc + # communicator + self.comm = None + + try: + from mpi4py import MPI + self.comm = MPI.COMM_WORLD + except BaseException: + pass + + etype = None + sdatatype = str(datatype) # in case user passes a numpy dtype + if re.search('float64', sdatatype): + etype = R8 + elif re.search('float32', sdatatype): + etype = R4 + elif re.search('int64', sdatatype): + etype = I8 + elif re.search('int32', sdatatype): + etype = I4 + else: + msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype + raise RegridError(msg) + + self.field = ESMF.Field( + grid=esmfGrid.grid, + name=name, + typekind=etype, + staggerloc=staggerloc) + vm = ESMF.ESMP_VMGetGlobal() + self.pe, self.nprocs = ESMF.ESMP_VMGet(vm) + + def getPointer(self): + """ + Get field data as a flat array + + Returns + ------- + + pointer + """ + return numpy.ravel(self.field.data) + + def getData(self, rootPe): + """ + Get field data as a numpy array + + Parameters + ---------- + + rootPe if None then local data will be fetched, otherwise + gather the data on processor "rootPe" (all other + procs will return None). + + _: None + + Returns + ------- + + numpy array or None + """ + ptr = self.getPointer() + if rootPe is None: + shp = self.grid.getCoordShape(staggerloc=self.staggerloc)[::-1] + # local data, copy + return numpy.reshape(ptr, shp).T + else: + # gather the data on rootPe + lo, hi = self.grid.getLoHiBounds(self.staggerloc) + los = [lo] + his = [hi] + ptrs = [ptr] + ptr = numpy.reshape(ptr, hi) + if self.comm is not None: + los = self.comm.gather(lo) # Local + his = self.comm.gather(hi) # Local + ptrs = self.comm.gather(ptr, root=rootPe) + + if self.pe == rootPe: # Local + # reassemble, find the largest hi indices to set + # the shape of the data container + bigHi = [0 for i in range(self.grid.ndims)] + for i in range(self.grid.ndims): + bigHi[i] = reduce(lambda x, y: max(x, y), + [his[p][i] for p in range(self.nprocs)]) + # allocate space to retrieve the data + bigData = numpy.empty(bigHi, ptr.dtype) + bigData[:] = 0.0 + + # populate the data + for p in range(self.nprocs): + slab = tuple([slice(los[p][i], his[p][i], None) for + i in range(self.grid.ndims)]) + # copy + bigData[slab].flat = ptrs[p] + return bigData.T # Local + + # rootPe is not None and self.pe != rootPe + return None + + def setLocalData(self, data, staggerloc, globalIndexing=False): + """ + Set local field data + + Parameters + ---------- + + data full numpy array, this method will take care of setting a + the subset of the data that reside on the local processor + + staggerloc stagger location of the data + + + globalIndexing if True array was allocated over global index + space, array was allocated over local index + space (on this processor) + """ + ptr = self.field.data + if globalIndexing: + slab = self.grid.getLocalSlab(staggerloc)[::-1] + ptr[:] = data.T[slab] + else: + ptr[:] = data.T + + +########################################################################## + +class EsmfRegrid: + """ + Regrid source grid data to destination grid data + """ + + def __init__(self, srcField, dstField, + srcFrac=None, + dstFrac=None, + srcMaskValues=None, + dstMaskValues=None, + regridMethod=BILINEAR, + ignoreDegenerate=False, + unMappedAction=IGNORE): + """ + Constuct regrid object + + Parameters + ---------- + + srcField + the source field object of type EsmfStructField + + dstField + the destination field object of type EsmfStructField + + srcMaskValues + Value of masked cells in source + + dstMaskValues + Value of masked cells in destination + + srcFrac + Cell fractions on source grid (type EsmfStructField) + + dstFrac + Cell fractions on destination grid (type EsmfStructField) + + regridMethod + ESMF.RegridMethod.{BILINEAR,CONSERVE,PATCH} + + unMappedAction + ESMF.UnmappedAction.{IGNORE,ERROR} + + ignoreDegenerate + Ignore degenerate cells when checking inputs + """ + self.srcField = srcField + self.dstField = dstField + self.regridMethod = regridMethod + self.srcAreaField = None + self.dstAreaField = None + self.srcFracField = srcFrac + self.dstFracField = dstFrac + self.regridHandle = None + self.ignoreDegenerate = ignoreDegenerate + + timeStamp = re.sub('\.', '', str(time.time())) + + # create and initialize the cell areas to zero + if regridMethod == CONSERVE: + self.srcAreaField = EsmfStructField(self.srcField.grid, + name='src_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcAreaField.getPointer() + dataPtr[:] = 0.0 + self.dstAreaField = EsmfStructField(self.dstField.grid, + name='dst_areas_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstAreaField.getPointer() + dataPtr[:] = 0.0 + + # initialize fractional areas to 1 (unless supplied) + if srcFrac is None: + self.srcFracField = EsmfStructField(self.srcField.grid, + name='src_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.srcFracField.getPointer() + dataPtr[:] = 1.0 + + if dstFrac is None: + self.dstFracField = EsmfStructField(self.dstField.grid, + name='dst_cell_area_fractions_%s' % timeStamp, + datatype='float64', + staggerloc=CENTER) + dataPtr = self.dstFracField.getPointer() + dataPtr[:] = 1.0 + + srcMaskValueArr = None + if srcMaskValues is not None: + srcMaskValueArr = numpy.array(srcMaskValues, dtype=numpy.int32) + + dstMaskValueArr = None + if dstMaskValues is not None: + dstMaskValueArr = numpy.array(dstMaskValues, dtype=numpy.int32) + + self.regridHandle = ESMF.Regrid( + srcField.field, + dstField.field, + src_frac_field=self.srcFracField.field, + dst_frac_field=self.dstFracField.field, + src_mask_values=srcMaskValueArr, + dst_mask_values=dstMaskValueArr, + regrid_method=regridMethod, + unmapped_action=unMappedAction, + ignore_degenerate=self.ignoreDegenerate) + + def getSrcAreas(self, rootPe): + """ + Get the src grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.srcAreaField.data.T + return None + + def getDstAreas(self, rootPe): + """ + Get the dst grid areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array or None if interpolation is not conservative + """ + if self.srcAreaField is not None: + return self.dstAreaField.data.T + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.srcFracField is not None: + # self.srcFracField.get_area() + return self.srcFracField.data.T + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid fraction areas as used by conservative interpolation + + Parameters + ---------- + + rootPe None is local areas are returned, otherwise + provide rootPe and the data will be gathered + + _: None + + Returns + ------- + + numpy array + """ + if self.dstFracField is not None: + # self.dstFracField.get_area() + return self.dstFracField.data.T + return None + + def __call__(self, srcField=None, dstField=None, zero_region=None): + """ + Apply interpolation weights + + Parameters + ---------- + + srcField source field (or None if src field passed to + constructor is to be used) + + dstField destination field (or None if dst field passed + to constructor is to be used) + + zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) + """ + if srcField is None: + srcField = self.srcField + if dstField is None: + dstField = self.dstField + + # default is keep the masked values intact + zeroregion = ESMF.Region.SELECT + if self.regridMethod == CONSERVE: + zeroregion = None # will initalize to zero + + self.regridHandle( + srcfield=srcField.field, + dstfield=dstField.field, + zero_region=zeroregion) + + def __del__(self): + if self.regridHandle is not None: + self.regridHandle.destroy() diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py new file mode 100644 index 00000000..de150dba --- /dev/null +++ b/regrid2/Lib/gsRegrid.py @@ -0,0 +1,1179 @@ +#!/usr/bin/env python + +""" +Regridding of curvilinear structured grids +Alex Pletzer and Dave Kindig, Tech-X (2011) +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. +""" +# standard python includes +# from re import search, sub +from ctypes import c_double, c_float, c_int, \ + c_wchar_p, CDLL, byref, POINTER +# import ctypes +import operator +import sys +import os +import copy +import numpy +import warnings +from regrid2 import RegridError +from functools import reduce +import fnmatch + +C_DOUBLE_P = POINTER(c_double) + +# libcf +try: + from pycf import libCFConfig, __path__ +except BaseException: + raise ImportError('Error: could not import pycf') + +LIBCFDIR = __path__[0] + "/pylibcf" + +__FILE__ = sys._getframe().f_code.co_filename + + +def catchError(status, lineno): + if status != 0: + raise RegridError("ERROR in %s: status = %d at line %d" + % (__FILE__, status, lineno)) + + +def getTensorProduct(axis, dim, dims): + """ + Convert an axis into a curvilinear coordinate by applying + a tensor product + + Parameters + ---------- + + axis 1D array of coordinates + + dim dimensional index of the above coordinate + + dims sizes of all coordinates + + Returns + ------- + + coordinate values obtained by tensor product + """ + return numpy.outer(numpy.outer(numpy.ones(dims[:dim], axis.dtype), axis), + numpy.ones(dims[dim + 1:], axis.dtype)).reshape(dims) + + +def makeCurvilinear(coords): + """ + Turn a mixture of axes and curvilinear coordinates into + full curvilinear coordinates + + Parameters + ---------- + + coords list of coordinates + + Returns + ------- + + new list of coordinates and associated dimensions + """ + rank = len(coords) + + count1DAxes = 0 + dims = [] + for i in range(rank): + coord = coords[i] + if len(coord.shape) == 1: + # axis + dims.append(len(coord)) + count1DAxes += 1 + elif len(coord.shape) == rank: + # fully curvilinear + dims.append(coord.shape[i]) + else: + # assumption: all 1D axes preceed curvilinear + # coordinates!!! + dims.append(coord.shape[i - count1DAxes]) + + for i in range(rank): + nd = len(coords[i].shape) + if nd == rank: + # already in curvilinear form, keep as is + pass + elif nd == 1: + # it's an axis + coords[i] = getTensorProduct(coords[i][:], i, dims) + elif rank == 3 and nd == 2 and i > 0: + # assume leading coordinate is an axis + o1 = numpy.ones((len(coords[0]),), coords[i].dtype) + coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims) + else: + raise RegridError("ERROR in %s: funky mixture of axes and curvilinear coords %s" + % (__FILE__, str([x.shape for x in coords]))) + return coords, dims + + +def makeCoordsCyclic(coords, dims): + """ + Make coordinates cyclic + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + new, extended coordinates such that the longitudes cover the sphere + and new dimensions + """ + # assume lon is the last coordinate!! + + # check if already extended + eps = 1.e-3 + + # some models already overlap + diff1 = abs(coords[-1][..., -2] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -2] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -2] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # some models are already periodic + diff1 = abs(coords[-1][..., -1] - coords[-1][..., 0]) + diff2 = abs(coords[-1][..., -1] - coords[-1][..., 0] - 360.0) + diff3 = abs(coords[-1][..., -1] - coords[-1][..., 0] + 360.0) + adiff = numpy.sum(numpy.minimum(diff1, numpy.minimum(diff2, diff3))) \ + / float(dims[-1]) + if adiff < eps: + # cyclic, return input coordinates unchanged + return coords, dims + + # make cyclic by appending a column to the coordinates + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-1] += 1 # append to the right + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:-1] = coords[i][...] + newCoords[i][..., -1] = coords[i][..., 0] + + # add modulo term, want deltas ~ order of dlon otherwise add + # or subtract a periodicity length + nlon = dims[-1] + dlon = 360.0 / float(nlon) # average resolution + tol = 360.0 - min(5, nlon) * dlon + mask1 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] < -tol) + mask2 = (newCoords[-1][..., -1] - newCoords[-1][..., -2] > +tol) + newCoords[-1][..., -1] += 360.0 * mask1 + newCoords[-1][..., -1] -= 360.0 * mask2 + + return newCoords, newDims + + +def checkForCoordCut(coords, dims): + """ + Look for a cut in a coordinate system (e.g. tri-polar grid) + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates + + dims input dimensions + + Returns + ------- + + True for cut found + False for no cut + """ + + # Assume latitude is next to last coordinate and longitude is last + # coordinate!!! + + rank = len(dims) + if rank < 2: + # print 'no cut: dims < 2' + return False + if len(coords[-2].shape) < 2: + # Is the 'lat' coordinate an axis? + return False + + nlat, nlon = dims[-2], dims[-1] + lat = coords[-2] + eps = 1.e-7 + + # Check to see if the top row has already be dealt with by the modeling + # agency. Last row is repeated in reverse. + + topRow = coords[-2][..., nlat - 1, :] + revTop = coords[-2][..., nlat - 1, ::-1] + nextRow = coords[-2][..., nlat - 2, :] # Reverse nextRow + diffs = abs(revTop - nextRow) + + # If already accounted for all diffs are 0. + if numpy.all(diffs < eps): + # print "no cut: reversed" + return False + + # Lon of max latitude -- Looking for a rotated pole + maxLats = numpy.where(abs(lat - numpy.max(lat)) < eps) + inTopRow = False + if len(maxLats[0] > 0): + inTopRow = numpy.all(maxLats[-2] == nlat - 1) + if not inTopRow: + # The max lats are not in the top row. The cut may already be handled + # print 'no cut: max lat not in top row.' + \ + # 'Either: it is a funky grid or rotated pole' + return False + + # Only in top row. + maxLatInd = lat[..., nlat - 1, :].argmax() + maxLonInd = lat[..., maxLatInd].argmax() + rowOfMaxLat = lat[..., maxLonInd, :] + diffs = rowOfMaxLat - topRow + + if diffs.max() != 0: + # Rotated Pole + # print "no cut: rotated pole" + return False + + # Find locale minima. + # A rotated pole grid has only one minimum. A tripolar grid should + # have two, though they may not be at the same latitude + + minInds = numpy.where(abs(topRow - topRow.min()) < eps) + if len(minInds[0]) > 2: + # Account for the end points matching + # Multiple minima in the top row + return True + + # Now if we have an offset tri-pole. The extra poles are not at the same + # latitude + minCount = 0 + firstInd = topRow.argmin() + diffs = numpy.diff(topRow) + if firstInd == 0: + if revTop.argmin() == 0: + if topRow[firstInd] == revTop[0]: + minCount += 1 + else: + minCount += 1 + # Look for next Minima + index = firstInd + 1 + while diffs[index] > 0: + index += 1 + if index == nlon: + break + nextIndex = topRow[index + 1:].argmin() + index + 1 + if nextIndex != index + 1 and nextIndex != nlon - 1: + minCount += 1 + if minCount == 1: + # print "no cut: one pole" + return False + + return True + + +def handleCoordsCut(coords, dims, bounds): + """ + Generate connectivity across a cut. e.g. from a tri-polar grid. + Assume latitude is next to last coordinate and longitude is last coordinate!!! + + Parameters + ---------- + + coords input coordinates list of rank + + dims input dimensions + + bounds boundaries for each coordinate + + Returns + ------- + + extended coordinates such that there is an extra row containing + connectivity information across the cut + """ + + # Assume latitude is next to last coordinate and longitude is + # last coordinate!!! + + dims = coords[-2].shape + + # Add row to top with connectivity information. This means rearranging + # the top row + def getIndices(array, nlon, newI): + """ + Find indices where a cell edge matches for two cells + + Parameters + ---------- + + array Array of booleans + + nlon number of longitudes + + newI index row with connectivity to be updated + + Returns + ------- + + new coordinates, new dimensions, index row + """ + for i in range(len(array)): + # An edge + if len(numpy.where(array[i, :] == True)[0]) >= 2: # noqa + if newI[i] < 0: + newI[i] = (nlon - 1) - i + if newI[(nlon - 1) - i] < 0: + newI[(nlon - 1) - i] = i + + # Assume mkCyclic == True + newI = numpy.arange(nlon - 1, -1, -1) - 1 + newI[nlon - 1] = 0 # Complete the rotation + + # Build new coordinate array and adjust dims + newCoords = [] + newDims = list(copy.copy(dims)) + newDims[-2] += 1 + + for i in range(len(coords)): + newCoords.append(numpy.zeros(newDims, coords[i].dtype)) + newCoords[i][..., 0:dims[-2], :] = coords[i][...] + newCoords[i][..., dims[-2], + :] = coords[i][..., dims[-2] - 1, newI] + + return newCoords, newDims, newI + + +class Regrid: + + def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, + handleCut=False, verbose=False): + """ + Constructor + + Parameters + ---------- + + src_grid source grid, a list of [x, y, ...] coordinates + or a cdms2.grid.Transient + + dst_grid destination grid, a list of [x, y, ...] coordinates + + src_bounds list of cell bounding coordinates (to be used when + handling a cut in coordinates) + + mkCyclic Add a column to the right side of the grid to complete + a cyclic grid + + handleCut Add a row to the top of grid to handle a cut for + grids such as the tri-polar grid + + verbose print diagnostic messages + + + Note: the grid coordinates can either be axes (rectilinear grid) or + n-dimensional for curvilinear grids. Rectilinear grids will + be converted to curvilinear grids. + """ + self.regridid = c_int(-1) + self.src_gridid = c_int(-1) + self.dst_gridid = c_int(-1) + self.rank = 0 + self.src_dims = [] + self.dst_dims = [] + self.src_coords = [] + self.dst_coords = [] + self.lib = None + self.extendedGrid = False + self.handleCut = False + self.dst_Index = [] + self.verbose = verbose + self.weightsComputed = False + self.maskSet = False + + # Open the shaped library + dynLibFound = False + for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': + if os.path.exists(LIBCFDIR + sosuffix): + dynLibFound = True + CFfile = self.find('pylibcf.*', __path__[0]) + if os.path.exists(CFfile): + try: + self.lib = CDLL(CFfile) + except BaseException: + pass +# for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a': +# if os.path.exists(LIBCFDIR + sosuffix): +# dynLibFound = True +# try: +# self.lib = CDLL(LIBCFDIR + sosuffix) +# break +# except: +# pass + if self.lib is None: + if not dynLibFound: + raise RegridError("ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + raise RegridError("ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}" + % (__FILE__, LIBCFDIR)) + + # Number of space dimensions + self.rank = len(src_grid) + + if len(dst_grid) != self.rank: + raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" + % (__FILE__, len(dst_grid), self.rank)) + + if self.rank <= 0: + raise RegridError("ERROR in %s: must have at least one dimension, rank = %d" + % (__FILE__, self.rank)) + + # Convert src_grid/dst_grid to curvilinear grid, if need be + if self.rank > 1: + src_grid, src_dims = makeCurvilinear(src_grid) + dst_grid, dst_dims = makeCurvilinear(dst_grid) + + # Make sure coordinates wrap around if mkCyclic is True + if mkCyclic: + src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims) + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + for i in range(self.rank): + print(('...... src_gridNew[%d].shape = %s' + % (i, str(src_gridNew[i].shape)))) + # flag indicating that the grid was extended + if reduce(lambda x, y: x + y, + [src_dimsNew[i] - src_dims[i] + for i in range(self.rank)]) > 0: + self.extendedGrid = True + # reset + src_grid = src_gridNew + src_dims = src_dimsNew + + # Handle a cut in the coordinate system. Run after mkCyclic. + # e.g. a tri-polar grid + if handleCut and src_bounds is not None: + # Test for the presence of a cut. + isCut = checkForCoordCut(src_grid, src_dims) + if isCut: + # No cut + src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(src_grid, + src_dims, src_bounds) + if dst_Index is not None: + self.handleCut = True + self.extendedGrid = self.extendedGrid + else: + self.handleCut = False + self.extendedGrid = self.extendedGrid + if self.verbose: + aa, bb = str(src_dims), str(src_dimsNew) + print(('... src_dims = %s, after making cyclic src_dimsNew = %s' + % (aa, bb))) + src_grid = src_gridNew + src_dims = src_dimsNew + self.dst_Index = dst_Index + + self.src_dims = (c_int * self.rank)() + self.dst_dims = (c_int * self.rank)() + + # Build coordinate objects + src_dimnames = (c_wchar_p * self.rank)() + dst_dimnames = (c_wchar_p * self.rank)() + for i in range(self.rank): + src_dimnames[i] = 'src_n%d' % i + dst_dimnames[i] = 'dst_n%d' % i + self.src_dims[i] = src_dims[i] + self.dst_dims[i] = dst_dims[i] + self.src_coordids = (c_int * self.rank)() + self.dst_coordids = (c_int * self.rank)() + save = 0 + standard_name = "" + units = "" + coordid = c_int(-1) + for i in range(self.rank): + data = numpy.array(src_grid[i], numpy.float64) + self.src_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "src_coord%d" % i + # assume [lev,] lat, lon ordering + if i == self.rank - 2: + standard_name = 'latitude' + units = 'degrees_north' + elif i == self.rank - 1: + standard_name = 'longitude' + units = 'degrees_east' + status = self.lib.nccf_def_coord(self.rank, self.src_dims, + src_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.src_coordids[i] = coordid + + data = numpy.array(dst_grid[i], numpy.float64) + self.dst_coords.append(data) + dataPtr = data.ctypes.data_as(C_DOUBLE_P) + name = "dst_coord%d" % i + status = self.lib.nccf_def_coord(self.rank, self.dst_dims, + dst_dimnames, + dataPtr, save, name, + standard_name, units, + byref(coordid)) + catchError(status, sys._getframe().f_lineno) + self.dst_coordids[i] = coordid + + # Build grid objects + status = self.lib.nccf_def_grid(self.src_coordids, "src_grid", + byref(self.src_gridid)) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid", + byref(self.dst_gridid)) + catchError(status, sys._getframe().f_lineno) + + # Create regrid object + status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid, + byref(self.regridid)) + catchError(status, sys._getframe().f_lineno) + + def getPeriodicities(self): + """ + Get the periodicity lengths of the coordinates + + Returns + ------- + + numpy array, values inf indicate no periodicity + """ + coord_periodicity = numpy.zeros((self.rank,), numpy.float64) + status = self.lib.nccf_inq_grid_periodicity(self.src_gridid, + coord_periodicity.ctypes.data_as(C_DOUBLE_P)) + catchError(status, sys._getframe().f_lineno) + return coord_periodicity + + def __del__(self): + """ + Destructor, will be called automatically + """ + status = self.lib.nccf_free_regrid(self.regridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.src_gridid) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_grid(self.dst_gridid) + catchError(status, sys._getframe().f_lineno) + + for i in range(self.rank): + + status = self.lib.nccf_free_coord(self.src_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + status = self.lib.nccf_free_coord(self.dst_coordids[i]) + catchError(status, sys._getframe().f_lineno) + + def find(self, pattern, path): + result = "" + for root, dirs, files in os.walk(path): + for name in files: + if fnmatch.fnmatch(name, pattern): + result = os.path.join(root, name) + return result + + def setValidMask(self, inMask): + """ + Set valid mask array for the grid + + Parameters + ---------- + + inMask flat numpy array of type numpy.int32 or a valid cdms2 variable + with its mask set. + 0 - invalid, 1 - valid data + + Note: This must be invoked before computing the weights, the + mask is a property of the grid (not the data). + """ + if self.weightsComputed: + raise RegridError('Must set mask before computing weights') + + mask = numpy.array(inMask, dtype=numpy.int32) + + # extend src data if grid was made cyclic and or had a cut accounted + # for + newMask = self._extend(mask) + c_intmask = newMask.ctypes.data_as(POINTER(c_int)) + status = self.lib.nccf_set_grid_validmask(self.src_gridid, + c_intmask) + catchError(status, sys._getframe().f_lineno) + self.maskSet = True + + def setMask(self, inDataOrMask): + """ + Set mask array. The mask is defined for nodes + + Parameters + ---------- + + inDataOrMask cdms2 array or flat mask array, + 0 - valid data + 1 - invalid data + + Note: this definition is compatible with the numpy masked arrays + + Note: note see setValidMask for the opposite definition + + Note: should be called before computing the weights + """ + mask = None + if hasattr(inDataOrMask, 'getmask'): + # cdms2 variable + mask = inDataOrMask.getmask() + else: + # flat mask array + mask = inDataOrMask + # reversing the meaning 1 == valid, 0 == invalid + mask = 1 - numpy.array(inDataOrMask, dtype=numpy.int32) + # now calling our own mask setter + self.setValidMask(mask) + + def computeWeights(self, nitermax=100, tolpos=1.e-2): + """ + Compute the the interpolation weights + + Parameters + ---------- + + nitermax max number of iterations + + tolpos max tolerance when locating destination positions in + index space + """ + status = self.lib.nccf_compute_regrid_weights(self.regridid, + nitermax, + c_double(tolpos)) + catchError(status, sys._getframe().f_lineno) + self.weightsComputed = True + + def apply(self, src_data_in, dst_data, missingValue=None): + """ + Apply interpolation + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + if not self.weightsComputed: + raise RegridError('Weights must be set before applying the regrid') + # extend src data if grid was made cyclic and or had a cut accounted + # for + src_data = self._extend(src_data_in) + + # Check + if reduce(operator.iand, [src_data.shape[i] == self.src_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied src_data have wrong shape " + + "%s != %s") % (__FILE__, str(src_data.shape), + str(tuple([d for d in self.src_dims])))) + if reduce(operator.iand, [dst_data.shape[i] == self.dst_dims[i] + for i in range(self.rank)]) == False: # noqa + raise RegridError(("ERROR in %s: supplied dst_data have wrong shape " + + "%s != %s") % (__FILE__, str(dst_data.shape), + str(tuple([d for d in self.dst_dims])))) + + # Create temporary data objects + src_dataid = c_int(-1) + dst_dataid = c_int(-1) + save = 0 + standard_name = "" + units = "" + time_dimname = "" + + status = self.lib.nccf_def_data(self.src_gridid, "src_data", + standard_name, units, time_dimname, + byref(src_dataid)) + catchError(status, sys._getframe().f_lineno) + + if src_data.dtype != dst_data.dtype: + try: # try recasting + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted src to dst" + % (src_data.dtype, dst_data.dtype)) + src_data = src_data.astype(dst_data.dtype) + except BaseException: + try: + warnings.warn("mismatch in src and dst data types (%s vs %s) we recasted dst to src" + % (src_data.dtype, dst_data.dtype)) + dst_data = dst_data.astype(src_data.dtype) + except BaseException: + raise RegridError("ERROR in %s: mismatch in src and dst data types (%s vs %s)" + % (__FILE__, src_data.dtype, dst_data.dtype)) + + # only float64 and float32 data types are supported for interpolation + if src_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif src_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + ptr = src_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + src_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid src_data type %s (neither float nor double)" + % (__FILE__, src_data.dtype)) + + status = self.lib.nccf_def_data(self.dst_gridid, "dst_data", + standard_name, units, time_dimname, + byref(dst_dataid)) + catchError(status, sys._getframe().f_lineno) + if dst_data.dtype == numpy.float64: + fill_value = c_double(libCFConfig.NC_FILL_DOUBLE) + if missingValue is not None: + fill_value = c_double(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_double)) + status = self.lib.nccf_set_data_double( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + elif dst_data.dtype == numpy.float32: + fill_value = c_float(libCFConfig.NC_FILL_FLOAT) + if missingValue is not None: + fill_value = c_float(missingValue) + dst_data[:] = missingValue + ptr = dst_data.ctypes.data_as(POINTER(c_float)) + status = self.lib.nccf_set_data_float( + dst_dataid, ptr, save, fill_value) + catchError(status, sys._getframe().f_lineno) + else: + raise RegridError("ERROR in %s: invalid dst_data type = %s" + % (__FILE__, dst_data.dtype)) + + # Now apply weights + status = self.lib.nccf_apply_regrid( + self.regridid, src_dataid, dst_dataid) + catchError(status, sys._getframe().f_lineno) + + # Clean up + status = self.lib.nccf_free_data(src_dataid) + catchError(status, sys._getframe().f_lineno) + status = self.lib.nccf_free_data(dst_dataid) + catchError(status, sys._getframe().f_lineno) + + return dst_data + + def __call__(self, src_data, dst_data, missingValue=None): + """ + Apply interpolation (synonymous to apply method) + + Parameters + ---------- + + src_data data on source grid + + dst_data data on destination grid + + missingValue value that should be set for points falling outside the src domain, + pass None if these should not be touched. + """ + self.apply(src_data, dst_data, missingValue) + + def getNumValid(self): + """ + Return the number of valid destination points. Destination points + falling outside the source domain, more gnerally, points which + could not be located on the source grid, reduce the number of + valid points. + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_nvalid(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getNumDstPoints(self): + """ + Return the number of points on the destination grid + + Returns + ------- + + number of points + """ + res = c_int(-1) + status = self.lib.nccf_inq_regrid_ntargets(self.regridid, + byref(res)) + catchError(status, sys._getframe().f_lineno) + return res.value + + def getSrcGrid(self): + """ + Return the source grid + + Returns + ------- + + grid + """ + return self.src_coords + + def getDstGrid(self): + """ + Return the destination grid + + Returns + ------- + + grid + """ + return self.dst_coords + + def getIndicesAndWeights(self, dst_indices): + """ + Get the indices and weights for a single target location + + Parameters + ---------- + + dst_indices index set on the target grid + + Returns + ------- + + [index sets on original grid, weights] + """ + dinds = numpy.array(dst_indices) + sinds = (c_int * 2**self.rank)() + weights = numpy.zeros((2**self.rank,), numpy.float64) + status = self.lib.nccf_inq_regrid_weights(self.regridid, + dinds.ctypes.data_as( + POINTER(c_double)), + sinds, + weights.ctypes.data_as(POINTER(c_double))) + catchError(status, sys._getframe().f_lineno) + # convert the flat indices to index sets + ori_inds = [] + for i in range(2**self.rank): + inx = numpy.zeros((self.rank,), numpy.int32) + self.lib.nccf_get_multi_index(self.rank, self.src_dims, + sinds[i], + inx.ctypes.data_as(POINTER(c_int))) + ori_inds.append(inx) + + return ori_inds, weights + + def _extend(self, src_data): + """ + Extend the data by padding a column and a row, depending on whether the + grid was made cyclic and a fold was added or not + + Parameters + ---------- + + src_data input source data + + Returns + ------- + + extended source data (or source input data of no padding was applied) + """ + + # nlatX, nlonX = self.src_dims[-2], self.src_dims[-1] + # original dimensions, before extension + # assuming ..., lat, lon ordering + nlat, nlon = src_data.shape[-2:] + + # no cut and no cyclic extension + src_dataNew = src_data + + if self.handleCut or self.extendedGrid: + # copy data into new, extended container + src_dataNew = numpy.zeros(self.src_dims, src_data.dtype) + # start filling in... + src_dataNew[..., :nlat, :nlon] = src_data[...] + + if self.handleCut: + # fill in polar cut (e.g. tripolar cut), top row + # self.dst_Index[i] knows how to fold + for i in range(nlon): + src_dataNew[..., -1, i] = src_data[..., -2, self.dst_Index[i]] + + if self.extendedGrid: + # make data periodic in longitudes + src_dataNew[..., -1] = src_dataNew[..., 0] + + return src_dataNew + + def _findIndices(self, targetPos, nitermax, tolpos, + dindicesGuess): + """ + Find the floating point indices + + Parameters + ---------- + + targetPos numpy array of target positions + + nitermax max number of iterations + + tolpos max toelrance in positions + + dindicesGuess guess for the floating point indices + + Returns + ------- + + indices, number of iterations, achieved tolerance + """ + posPtr = targetPos.ctypes.data_as(POINTER(c_double)) + adjustFunc = None + hit_bounds = numpy.zeros((self.rank), + dtype=int).ctypes.data_as(POINTER(c_int)) + # no periodicity + coord_periodicity = float( + 'inf') * numpy.ones((self.rank), targetPos.dtype) + coord_periodicity_ptr = coord_periodicity.ctypes.data_as( + POINTER(c_double)) + res = copy.copy(dindicesGuess) + resPtr = res.ctypes.data_as(POINTER(c_double)) + src_coords = (POINTER(c_double) * self.rank)() + niter = c_int(nitermax) + tol = c_double(tolpos) + for i in range(self.rank): + ptr = self.src_coords[i].ctypes.data_as(POINTER(c_double)) + src_coords[i] = ptr + status = self.lib.nccf_find_indices_double(self.rank, + self.src_dims, + src_coords, + coord_periodicity_ptr, + posPtr, + byref(niter), + byref(tol), + adjustFunc, + resPtr, + hit_bounds) + catchError(status, sys._getframe().f_lineno) + return resPtr.contents.value, niter.value, tol.value + +###################################################################### + + +def testMakeCyclic(): + + y = numpy.array([-90.0 + i * 30.0 for i in range(7)]) + x = numpy.array([(i + 0.5) * 60.0 for i in range(6)]) + yy = getTensorProduct(y, 0, [len(y), len(x)]) + xx = getTensorProduct(x, 1, [len(y), len(x)]) + coords = [yy, xx] + dims = [len(y), len(x)] + newCoords, newDims = makeCoordsCyclic(coords, dims) +# print 'cyclic lats' +# print newCoords[0] +# print 'cyclic lons' +# print newCoords[1] + + +def testHandleCut(): + + import cdms2 + # Need tripolar grid + filename = "data/so_Omon_GFDL-ESM2M_1pctCO2_r1i1p2_000101-000512_2timesteps.nc" + f = cdms2.open(filename) + if not f: + return + + # so = f.variables['so'][0, 0, :, :] + if 'lon' in list(f.variables.keys()): + alllat = f.variables['lat'] + alllon = f.variables['lon'] + else: + alllat = f.getAxis("lat").getData() + alllon = f.getAxis("lon").getData() + + bounds = [f.variables['bounds_lon'][:].data, + f.variables['bounds_lat'][:].data] + coords = [alllat[:].data, alllon[:].data] + dims = alllat.shape + newCoords, newDims = makeCoordsCyclic(coords, dims) + newCoords, newDims = handleCoordsCut(newCoords, newDims, bounds) + + +# def testOuterProduct(): + + # 2d + # x = numpy.array([1, 2, 3, 4]) + # y = numpy.array([10, 20, 30]) + # xx = getTensorProduct(x, 0, [len(x), len(y)]) + # yy = getTensorProduct(y, 1, [len(x), len(y)]) + + # z = numpy.array([100, 200]) + # Mixed coordinates and axes + # aa = makeCurvilinear([z, yy, xx]) + # for g in aa: + # print g + +def test(): + def func1(coords): + return coords[0] * coords[1] + coords[2] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = numpy.array([1, 2, 3, 4, 5, 6]) + src_y = numpy.array([10, 20, 30, 40, 50]) + src_z = numpy.array([100, 200]) + + # destination grid, product of axes + dst_x = numpy.array([1.5, 2.0, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5]) + dst_y = numpy.array([15., 20., 25., 30., 40.]) + dst_z = numpy.array([120.0, 180.0, 240.]) + + # regridding constructor + rg = Regrid([src_x, src_y, src_z], + [dst_x, dst_y, dst_z]) +# rg = Regrid([src_x, src_y], +# [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + maxNumIters = 20 + posTol = 1.e-3 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data = ', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +def testMasking(): + import numpy.ma as ma + + def func1(coords): + return coords[0] * coords[1] + + def func2(coords): + return coords[0] * coords[1] + + # source grid, tensor product of axes + src_x = ma.masked_array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 0, 0]) + src_y = ma.masked_array([10, 20, 30, 40, 50], mask=[0, 0, 0, 1, 0]) + + # destination grid, product of axes + dst_x = numpy.array([0.5, 1, 1.5, 2.0, 2.5, 3.5, + 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) + dst_y = numpy.array([15., 20., 25., 30., 35., 40., 45., 50., 55]) + + # regridding constructor + rg = Regrid([src_x, src_y], + [dst_x, dst_y]) + + # initialIndexGuess = numpy.array([0.0, 0.0, 0.0]) + # indices = rg._findIndices(numpy.array([1.5, 18.0, 140.0]), + # 20, 1.e-2, initialIndexGuess) + # Mask needs to be set before weights are computed + mask = rg.getSrcGrid()[0] == 3 + mask[:, 3] = True + rg.setValidMask(mask) + rg.setMask(mask) + maxNumIters = 20 + posTol = 1.e-2 + rg.computeWeights(maxNumIters, posTol) + + # number of valid points (some destination points may fall + # outside the domain) + nvalid = rg.getNumValid() + + # number of destination points + ndstpts = rg.getNumDstPoints() + print(('nvalid = ', nvalid, ' ndstpts = ', ndstpts)) + + # get the indices and weights for a single target location + dst_indices = [4, 2, 1] + inds, weights = rg.getIndicesAndWeights(dst_indices) + print(('indices and weights are: ', inds, weights)) + + # data + src_coords = rg.getSrcGrid() + dst_coords = rg.getDstGrid() + # print 'src_coords = ', src_coords + # print 'dst_coords = ', dst_coords + src_data = numpy.array(func1(src_coords), numpy.float32) + dst_data = -numpy.ones(dst_coords[0].shape, numpy.float32) + + # regrid + rg(src_data, dst_data) + print(('after interp: dst_data =\n', dst_data)) + + # check + error = numpy.sum(abs(dst_data - func1(dst_coords))) + # print dst_data + # print func(dst_coords) + print(('error = ', error)) + + +if __name__ == '__main__': + # testOuterProduct() + test() + testMasking() + # testMakeCyclic() + # testHandleCut() diff --git a/regrid2/Lib/gs_horizontal.py b/regrid2/Lib/gs_horizontal.py new file mode 100644 index 00000000..20cfa4a6 --- /dev/null +++ b/regrid2/Lib/gs_horizontal.py @@ -0,0 +1,214 @@ +import sys +import os +import os.path +# from ctypes import CDLL, c_char_p, c_int, byref, c_double, c_uint, pointer, create_string_buffer +from ctypes import CDLL, c_double, c_uint +import cdms2 +import time +import config +sys.path.append("/home/painter1/libcf/") +libcf = CDLL(config.prefix + '/lib/libcf.so') + + +class GS_Regridder: + + def __init__(self, ingrid, outgrid, + infile=None, outfile=None, remapfile=None): + # Save the grids, make and save a Gridspec remap file. + # For now, we are using the libCF/Gridspec API which operates only on files; + # thus temporary files are written out and read back in. That requires the + # input grids to support a "write_gridspec" method. + # If a path is provided, it prefixes whatever filenames were input. + # If there is no path provided, each filename must include its path. + # Note: it's a bit messy to keep filenames and paths separate internally, + # but the presnet Gridspec function expects lots of directories. + + self.ingrid = ingrid + self.outgrid = outgrid + if (not hasattr(ingrid, "gsfile")): + ingrid.gsfile = None + ingrid.gspath = None + if (infile is None): + self.infile = ingrid.gsfile + self.inpath = ingrid.gspath + else: + self.infile = os.path.basename(infile) + self.inpath = os.path.dirname(infile) + if (not os.path.isfile(self.inpath + "/" + self.infile)): + raise OSError( + "cannot open infile " + + self.inpath + + "/" + + self.infile) + + if (not hasattr(outgrid, "gsfile")): + outgrid.gsfile = None + outgrid.gspath = None + if (outfile is None): + self.outfile = outgrid.gsfile + self.outpath = outgrid.gspath + else: + self.outfile = os.path.basename(outfile) + self.outpath = os.path.dirname(outfile) + if (not os.path.isfile(self.outpath + "/" + self.outfile)): + raise OSError( + "cannot open outfile " + + self.outpath + + "/" + + self.outfile) + + if (remapfile is None): + timestr = str(int(time.time())) + self.remapfile = "remap" + timestr + self.remappath = "/tmp" + else: + self.remapfile = os.path.basename(remapfile) + self.remappath = os.path.dirname(remapfile) + if (not os.path.isdir(self.remappath + "/")): + raise OSError( + "cannot open remapfile directory " + + self.remappath + + "/") + + ingrid.write_gridspec(self.inpath + "/" + self.infile) + outgrid.write_gridspec(self.outpath + "/" + self.outfile) + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + # No variables to interpolate; the gs_fregrid call will be just to + # make a remap file... + dir_in = 256 * "\x00" + dir_out = 256 * "\x00" + input_file = 256 * "\x00" + nfiles = 0 + output_file = 256 * "\x00" + nfiles_out = 0 + scalar_name = 256 * "\x00" + nscalar = 0 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + # For a call which only writes the remap files, gs_fregrid + # expects remapfile to be a full path. For a call in which + # remapping takes place, gs_fregrid expects remapfile to be + # a pure filename, in a path it gets from elsewhere, maybe dir_in. + # (ARRGH - but with the API slated to be replaced, I'll live with it) + remapf = os.path.abspath( + self.remappath + "/" + self.remapfile) + "\0" * 256 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + remapf, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + def __call__(self, ar): + # Interpolate the input variable to the new grid using the Gridspec + # remap file generated when this GS_Remapper object was initialized. + # >>>for now, ar is required to be a variable (MV) <<< + + # Here, convert ar into a file for gs_fregrid + # There's no special Gridspec way to write a variable; you write to any + # *.nc file. The tough part is making sure you have there exactly what's + # needed for the gs_fregrid call, especially because the grids are + # supposedly supergrids and you just have some keywords to use to figure + # out what goes where. And note that we'll need to check whether ar + # really lives on self.ingrid . Supposedly a future API will work + # better in this respect + + # Write the variable to a temporary file, as required by gs_fregrid. + # The remap path should be suitable. + # >>> this should be done more carefully, e.g. deal with failures; + # >>> more worth doing when we have mosaic variables. + timestr = str(int(time.time())) + varfile = cdms2.open( + self.inpath + + "/" + + "invvar" + + timestr + + ".nc", + 'w') + varfile.write(ar) + varfile.close() + + history = "GS_Regridder" + mosaic_in = self.inpath + "/" + self.infile + mosaic_out = self.outpath + "/" + self.outfile + + dir_in = 256 * "\x00" # path is already encoded in input_file + dir_out = 256 * "\x00" # path is already encoded in output_file + input_file = varfile.id + 256 * "\x00" + nfiles = 1 + output_file = self.outpath + '/' + "outvar" + timestr + ".nc" + 256 * "\x00" + nfiles_out = 1 + scalar_name = ar.id + 256 * "\x00" + nscalar = 1 + u_name = 256 * "\x00" + v_name = 256 * "\x00" + nvector = 0 + nvector2 = 0 + + interp_method = "conserve_order2" + test_case = None + test_param = c_double(1.0) + opcode = c_uint(0) + AGRID = 64 + grid_type = AGRID + finer_step = c_uint(0) + fill_missing = 0 + nlon = 0 + nlat = 0 + check_conserve = 0 + y_at_center = 0 + lonbegin = c_double(0.) + lonend = c_double(360.) + latbegin = c_double(-90.) + latend = c_double(90.) + lbegin = 0 + lend = -1 + kbegin = 0 + kend = -1 + + print(("__call__ remapfile=", self.remapfile)) + libcf.gs_fregrid(history, mosaic_in, mosaic_out, dir_in, dir_out, + input_file, nfiles, output_file, nfiles_out, + self.remapfile, + scalar_name, nscalar, u_name, nvector, v_name, + nvector2, interp_method, test_case, test_param, opcode, + grid_type, finer_step, fill_missing, nlon, nlat, + check_conserve, y_at_center, lonbegin, lonend, latbegin, + latend, kbegin, kend, lbegin, lend) + + # Read the output_file into a variable, and return the variable + f = cdms2.open(self.outpath + "/" + output_file) + vout = f(scalar_name) + f.close() + return vout diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py new file mode 100644 index 00000000..67d673f4 --- /dev/null +++ b/regrid2/Lib/horizontal.py @@ -0,0 +1,422 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import numpy +import copy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import warnings +import cdms2 + +_debug = 0 # Set to 1 for debug + +# Map (n,2) boundary arrays to individual boundary arrays. Returns +# (lowerBounds, upperBounds) + + +def extractBounds(bounds): + if bounds[0, 0] < bounds[0, 1]: + lower = bounds[:, 0] + upper = bounds[:, 1] + else: + lower = bounds[:, 1] + upper = bounds[:, 0] + + return (lower.astype(numpy.float32), upper.astype(numpy.float32)) + +# Create a horizontal regridder. ingrid and outgrid are CDMS AbstractGrid +# objects. + + +class Horizontal: + + def __init__(self, ingrid, outgrid): + """ + Constructor for regridding class + + Parameters + ---------- + + ingrid cdms2, ndarray variable + + outgrid cdms2, ndarray variable + """ + + inlat = ingrid.getLatitude() + outlat = outgrid.getLatitude() + inlon = ingrid.getLongitude() + outlon = outgrid.getLongitude() + inlatBounds, inlonBounds = ingrid.getBounds() + outlatBounds, outlonBounds = outgrid.getBounds() + + self.nlati = len(inlat) + self.nlato = len(outlat) + self.nloni = len(inlon) + self.nlono = len(outlon) + self.inmask = ingrid.getMask() + self.outmask = outgrid.getMask() + # Make grid masks consistent with 'internal' convention: + # 0 == invalid + if self.inmask is not None: + self.inmask = 1. - self.inmask + if self.outmask is not None: + self.outmask = 1. - self.outmask + self.inshape = ingrid.shape + self.inorder = ingrid.getOrder() + self.outlat = outgrid.getLatitude().clone() + self.outlon = outgrid.getLongitude().clone() + + bsin, bnin = extractBounds(inlatBounds) + bwin, bein = extractBounds(inlonBounds) + bsout, bnout = extractBounds(outlatBounds) + bwout, beout = extractBounds(outlonBounds) + + if _debug == 1: + import sys + sys.stdout = open('debug_regrid.txt', 'w') + print(("bsin = ", numpy.array2string(bsin, precision=3))) + print(("bnin = ", numpy.array2string(bnin, precision=3))) + print(("bwin = ", numpy.array2string(bwin, precision=3))) + print(("bein = ", numpy.array2string(bein, precision=3))) + print(("bsout = ", numpy.array2string(bsout, precision=3))) + print(("bnout = ", numpy.array2string(bnout, precision=3))) + print(("bwout = ", numpy.array2string(bwout, precision=3))) + print(("beout = ", numpy.array2string(beout, precision=3))) + + self.londx, self.lonpt, self.wtlon, self.latdx, self.latpt, self.wtlat = _regrid.maparea( + self.nloni, self.nlono, self.nlati, self.nlato, bnin, bnout, bsin, bsout, bein, beout, bwin, bwout) + + def __call__(self, ar, missing=None, order=None, + mask=None, returnTuple=0, **args): + """ + Call the regridder function. + @param ar is the input array. + @param order is of the form "tzyx", "tyx", etc. + @param missing is the missing data value, if any. + @param mask is either 2-D or the same shape as ar. + @param returnTuple If true, return the tuple (outArray, outWeights) where + outWeights is the fraction of each zone of the output grid + which overlaps non-missing zones of the input grid; it has + the same shape as the output array. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Compatibility + if mask is numpy.ma.nomask: + mask = None + + if ar.dtype.type is numpy.bool_: + ar = numpy.asarray(ar, numpy.float32) + + # Make sense of mask consistent with 'internal' convention (0 == + # invalid) + if mask is not None: + mask = 1. - mask + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = list([x[0].clone() for x in ar.getDomain()]) + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + armask = ar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + armask = tempar.mask + if armask is numpy.ma.nomask: + armask = None + else: + armask = 1. - armask # Reverse numpy.ma convention for rgdarea + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armask = armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # If neither mask nor missing value is specified, get them from + # the input array. + if mask is None and missing is None: + missing = armiss + mask = armask + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 2 <= rank <= 4, 'Array rank is %i, must be 2, 3, or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 2: + order = self.inorder + elif rank == 3: + order = "t" + self.inorder + else: + order = "tz" + self.inorder + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to ilon, ilat ... + itim1 = itim2 = 0 + ilon = ilat = -1 + idim = 0 + for i in range(rank - 1, -1, -1): + c = order[i] + if c == 'x': + ilon = idim + elif c == 'y': + ilat = idim + elif c == 'z': + itim1 = idim + elif c == 't': + if rank == 3: + itim1 = idim + else: + itim2 = idim + idim = idim + 1 + + # Map array shape to nloni, nlati, ... + ntim1 = ntim2 = 0 + shape = ar.shape + if ilon == -1: + raise RegridError("Input grid does not have a longitude axis") + if ilat == -1: + raise RegridError("Input grid does not have a latitude axis") + nlati = shape[rank - ilat - 1] + nloni = shape[rank - ilon - 1] + if nlati != self.nlati or nloni != self.nloni: + raise ( + 'array lat,lon (%i,%i) does not match grid lat,lon (%i,%i)' % + (nlati, nloni, self.nlati, self.nloni)) + + if itim1 != 0: + ntim1 = shape[rank - itim1 - 1] + if itim2 != 0: + ntim2 = shape[rank - itim2 - 1] + + # Construct the input mask: + # If user mask is 2-D or not specified, use the logical AND of the mask (or input grid mask + # if no user mask is specified) + # with the 'implicit mask' generated from the missing data, if any + if (mask is None) or len(mask.shape) == 2: + flag2D = 1 + if mask is not None: + assert mask.shape == self.inshape, '2-D mask must be same shape as input grid' + inmask = mask + elif self.inmask is None: + inmask = numpy.ones(self.inshape) + else: + inmask = self.inmask + + if missing is not None: + if rank == 2: + firstslice = ar + elif rank == 3: + firstslice = ar[0] + else: + firstslice = ar[0, 0] + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( firstslice - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + firstslice - + missing), + numpy.absolute( + 0.001 * + missing)), + inmask, + 0) + + # If the user mask was specified and is > 2-D, it overrides the grid + # mask + else: + assert mask.shape == ar.shape, 'Mask must be 2-D or same shape as input array' + inmask = mask + flag2D = 0 # 2-D user masks are handled above + # If armask is derived from the input array, it is probably consistent + # with the missing value - don't bother recalculating it + if missing is not None and armask is None: + # inmask = numpy.logical_and( numpy.greater( numpy.absolute( ar - missing), + # numpy.absolute( 0.001*missing)), inmask) + if issubclass(ar.dtype.type, numpy.floating): + inmask = numpy.where( + numpy.greater( + numpy.absolute( + ar - missing), + numpy.absolute( + 0.001 * missing)), + inmask, + 0) + # Cast the mask to float + inmask = inmask.astype(numpy.float32) + if missing is None: + missing = 1.0e20 + + # Cast the input array to 32-bit floats, if necessary + if ar.dtype.char != numpy.float32: + ar = ar.astype(numpy.float32) + + # Malloc return array + outshape = list(shape) + outshape[rank - ilat - 1] = self.nlato + outshape[rank - ilon - 1] = self.nlono + outar = numpy.zeros(tuple(outshape), numpy.float32) + + # Perform the regridding. The return array has the same shape + # as the output array, and is the fraction of the zone which overlaps + # a non-masked zone of the input grid. + amskout = _regrid.rgdarea( + ilon, + ilat, + itim1, + itim2, + ntim1, + ntim2, + nloni, + self.nlono, + nlati, + self.nlato, + flag2D, + missing, + self.londx, + self.lonpt, + self.wtlon, + self.latdx, + self.latpt, + self.wtlat, + inmask, + ar, + outar) + + # Correct the shape of output weights + amskout.shape = outar.shape + + # Set the missing data mask of the output array, if any. + hasMissing = not numpy.ma.alltrue(numpy.ma.ravel(amskout)) + if hasMissing: + slabMask = numpy.ma.where(numpy.ma.equal(amskout, 0), 1, 0) + else: + slabMask = None + + # Combine missing data mask and output grid mask + # Note: slabMask and outmask are Boolean here + if self.outmask is not None: + outmask = numpy.logical_not(numpy.resize(self.outmask, outshape)) + if hasMissing: + outmask = numpy.ma.logical_or(outmask, slabMask) + else: + outmask = slabMask + + # Create the result TransientVariable (if input ar is an AbstractVariable) + # or masked array + if inputIsVariable == 1: + for i in range(len(order)): + if order[i] == 'x': + axislist[i] = self.outlon + elif order[i] == 'y': + axislist[i] = self.outlat + result = cdms2.createVariable(outar, mask=outmask, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array( + outar, mask=outmask, fill_value=missing) + + if returnTuple == 0: + return result + else: + return result, amskout + + +class Regridder(Horizontal): + def __init__(self, ingrid, outgrid): + warnings.warn( + "While this will work for now, please note that the Regridder class has been " + + "renamed Horizontal, the name 'Regridder' will be deprecated in future version. " + + "Please edit your code accordingly", + Warning) + Horizontal.__init__(self, ingrid, outgrid) + + +def input_mask(ain, type, mask, missing=None): + """ #------------------------------------------------------------------- + # + # purpose: set up the input mask including missing from ain + # + # usage: + # + # passed : + # + # returned: + # + # + #------------------------------------------------------------------------""" + if type != 'h' and type != 'v': + raise ValueError('Mask type must be h or v') + return + + if missing is None: + try: + omit = ain.missing_value + except AttributeError: + omit = 1.0e20 + else: + omit = missing + + # ----- insert 0.0 in mask where array has missing data ------- + + mask_size = len(mask.shape) + data_size = len(ain.shape) + + if mask_size == 2 and data_size > 2: # make reduced array with first lat_lon section from a + + if data_size == 3: # caution: assuming standard order lat-lon varying the fastest + if type == 'h': + reduced = ain[0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[:, :, 0] + elif data_size == 4: + if type == 'h': + reduced = ain[0, 0, :, :] + elif type == 'v': + # removes lats dummy latitude + reduced = ain[0, :, :, 0] + else: + raise IndexError('Data size is out of range') + return + + amskin = numpy.where(numpy.greater(reduced, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + else: # 0.0 -> missing in passed mask + + amskin = numpy.where(numpy.greater(ain, 0.9 * omit), 0.0, mask) + amskin = amskin.astype(numpy.float32) + + return omit, amskin diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py new file mode 100644 index 00000000..235e1fd5 --- /dev/null +++ b/regrid2/Lib/mvESMFRegrid.py @@ -0,0 +1,483 @@ +""" +ESMF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import re +import numpy + +import ESMF +from . import esmf +from . import RegridError +from .mvGenericRegrid import GenericRegrid + +ESMF.Manager(debug=False) +HAVE_MPI = False +try: + from mpi4py import MPI + HAVE_MPI = True +except BaseException: + pass + +# constants +CENTER = ESMF.StaggerLoc.CENTER # Same as ESMF_STAGGERLOC_CENTER_VCENTER +CORNER = ESMF.StaggerLoc.CORNER +VCORNER = ESMF.StaggerLoc.CORNER_VFACE +VFACE = VCORNER +CONSERVE = ESMF.RegridMethod.CONSERVE +PATCH = ESMF.RegridMethod.PATCH +BILINEAR = ESMF.RegridMethod.BILINEAR +IGNORE = ESMF.UnmappedAction.IGNORE +ERROR = ESMF.UnmappedAction.ERROR + + +class ESMFRegrid(GenericRegrid): + """ + Regrid class for ESMF + """ + + def __init__(self, srcGridshape, dstGridshape, dtype, + regridMethod, staggerLoc, periodicity, coordSys, + srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, + dstGridMask=None, hasDstBounds=False, dstGridAreas=None, + ignoreDegenerate=False, + **args): + """ + Constructor + @param srcGridShape tuple source grid shape + @param dstGridShape tuple destination grid shape + @param dtype a valid numpy data type for the src/dst data + @param regridMethod 'linear', 'conserve', or 'patch' + @param staggerLoc the staggering of the field, 'center' or 'corner' + @param periodicity 0 (no periodicity), + 1 (last coordinate is periodic, + 2 (both coordinates are periodic) + @param coordSys 'deg', 'cart', or 'rad' + @param hasSrcBounds tuple source bounds shape + @param hasDstBounds tuple destination bounds shape + @param ignoreDegenerate Ignore degenerate celss when checking inputs + """ + + # esmf grid objects (tobe constructed) + self.srcGrid = None + self.dstGrid = None + self.dtype = dtype + + self.srcGridShape = srcGridshape + self.dstGridShape = dstGridshape + self.ignoreDegenerate = ignoreDegenerate + self.ndims = len(self.srcGridShape) + + self.hasSrcBounds = hasSrcBounds + self.hasDstBounds = hasDstBounds + + self.regridMethod = BILINEAR + self.regridMethodStr = 'linear' + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.regridMethod = CONSERVE + self.regridMethodStr = 'conserve' + elif re.search('patch', regridMethod.lower()): + self.regridMethod = PATCH + self.regridMethodStr = 'patch' + + # data stagger + self.staggerloc = CENTER + self.staggerlocStr = 'center' + if isinstance(staggerLoc, str): + if re.search('vface', staggerLoc.lower(), re.I): + self.staggerloc = VFACE + self.staggerlocStr = 'vcorner' + # there are other staggers we could test here + elif re.search('corner', staggerLoc.lower(), re.I) or \ + re.search('node', staggerLoc.lower(), re.I): + self.staggerloc = CORNER + self.staggerlocStr = 'corner' + # there are other staggers we could test here + + # good for now + unMappedAction = args.get('unmappedaction', 'ignore') + self.unMappedAction = ESMF.UnmappedAction.IGNORE + if re.search('error', unMappedAction.lower()): + self.unMappedAction = ESMF.UnmappedAction.ERROR + + self.coordSys = ESMF.CoordSys.SPH_DEG + self.coordSysStr = 'deg' + if re.search('cart', coordSys.lower()): + self.coordSys = ESMF.CoordSys.CART + self.coordSysStr = 'cart' + elif re.search('rad', coordSys.lower()): + self.coordSys = ESMF.CoordSys.SPH_RAD + self.coordSysStr = 'rad' + + self.periodicity = periodicity + + # masks can take several values in ESMF, we'll have just one + # value (1) which means invalid +# self.srcMaskValues = numpy.array([1],dtype = numpy.int32) +# self.dstMaskValues = numpy.array([1],dtype = numpy.int32) + + if isinstance(regridMethod, str): + if re.search('conserv', regridMethod.lower()): + self.srcMaskValues = numpy.array([1], dtype=numpy.int32) + self.dstMaskValues = numpy.array([1], dtype=numpy.int32) + else: + self.srcMaskValues = srcGridMask + self.dstMaskValues = dstGridMask + + # provided by user or None + self.srcGridAreas = srcGridAreas + self.dstGridAreas = dstGridAreas + self.maskPtr = None + + # MPI stuff + self.pe = 0 + self.nprocs = 1 + self.comm = None + if HAVE_MPI: + self.comm = MPI.COMM_WORLD + self.pe = self.comm.Get_rank() + self.nprocs = self.comm.Get_size() + + # checks + if self.ndims != len(self.dstGridShape): + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: mismatch in the number of topological +dimensions. len(srcGridshape) = %d != len(dstGridshape) = %d""" % \ + (self.ndims, len(self.dstGridShape)) + raise RegridError(msg) + + # Initialize the grids without data. + self.srcGrid = esmf.EsmfStructGrid(self.srcGridShape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasSrcBounds) + self.dstGrid = esmf.EsmfStructGrid(dstGridshape, + coordSys=self.coordSys, + periodicity=self.periodicity, + staggerloc=self.staggerloc, + hasBounds=self.hasDstBounds) + + # Initialize the fields with data. + self.srcFld = esmf.EsmfStructField(self.srcGrid, 'srcFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFld = esmf.EsmfStructField(self.dstGrid, 'dstFld', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcAreaField = esmf.EsmfStructField(self.srcGrid, name='srcAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstAreaField = esmf.EsmfStructField(self.dstGrid, name='dstAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + + self.srcFracField = esmf.EsmfStructField(self.srcGrid, name='srcFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.dstFracField = esmf.EsmfStructField(self.dstGrid, name='dstFracAreas', + datatype=self.dtype, + staggerloc=self.staggerloc) + self.srcFld.field.data[:] = -1 + self.dstFld.field.data[:] = -1 + self.srcAreaField.field.data[:] = 0.0 + self.dstAreaField.field.data[:] = 0.0 + self.srcFracField.field.data[:] = 1.0 + self.dstFracField.field.data[:] = 1.0 + + def setCoords(self, srcGrid, dstGrid, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + globalIndexing=False, **args): + """ + Populator of grids, bounds and masks + @param srcGrid list [[z], y, x] of source grid arrays + @param dstGrid list [[z], y, x] of dstination grid arrays + @param srcGridMask list [[z], y, x] of arrays + @param srcBounds list [[z], y, x] of arrays + @param srcGridAreas list [[z], y, x] of arrays + @param dstGridMask list [[z], y, x] of arrays + @param dstBounds list [[z], y, x] of arrays + @param dstGridAreas list [[z], y, x] of arrays + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + """ + + # create esmf source Grid + self.srcGrid.setCoords(srcGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + + if srcGridMask is not None: + self.srcGrid.setMask(srcGridMask, self.staggerloc) + + if srcBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + # VCORNER for 3D + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + # cell field, need to provide the bounds + self.srcGrid.setCoords(srcBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the src bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + # create destination Grid + self.dstGrid.setCoords(dstGrid, staggerloc=self.staggerloc, + globalIndexing=globalIndexing) + if dstGridMask is not None: + self.dstGrid.setMask(dstGridMask) + + if dstBounds is not None: + # Coords are CENTER (cell) based, bounds are CORNER (nodal) + if self.staggerloc != CORNER and self.staggerloc != VCORNER: + if self.ndims == 2: + self.dstGrid.setCoords(dstBounds, staggerloc=CORNER, + globalIndexing=globalIndexing) + if self.ndims == 3: + self.dstGrid.setCoords(dstBounds, staggerloc=VCORNER, + globalIndexing=globalIndexing) + elif self.staggerloc == CORNER or self.staggerloc == VCORNER: + msg = """ +mvESMFRegrid.ESMFRegrid.__init__: can't set the dst bounds for +staggerLoc = %s!""" % self.staggerLoc + raise RegridError(msg) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args (not used) + """ + self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, + dstfield=self.dstFld.field, + src_mask_values=self.srcMaskValues, + dst_mask_values=self.dstMaskValues, + regrid_method=self.regridMethod, + unmapped_action=self.unMappedAction, + ignore_degenerate=True) + + def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): + """ + Regrid source to destination. + When used in parallel, if the processor is not the root processor, + the dstData returns None. + + Source data mask: + + . If you provide srcDataMask in args the source grid will + be masked and weights will be recomputed. + + . Subsequently, if you do not provide a srcDataMask the last + weights will be used to regrid the source data array. + + . By default, only the data are masked, but not the grid. + + @param srcData array source data, shape should + cover entire global index space + @param dstData array destination data, shape should + cover entire global index space + @param rootPe if other than None, then data will be MPI gathered + on the specified rootPe processor + @param globalIndexing if True array was allocated over global index + space, otherwise array was allocated over + local index space on this processor. This + is only relevant if rootPe is None + @param **args + """ + +# if args.has_key('srcDataMask'): +# srcDataMask=args.get('srcDataMask') + # Make sure with have a mask intialized for this grid. + +# if(self.maskPtr is None): +# if(self.srcFld.field.grid.mask[self.staggerloc] is None): +# self.srcFld.field.grid.add_item(item=ESMF.GridItem.MASK, staggerloc=self.staggerloc) +# self.maskPtr = self.srcFld.field.grid.get_item(item=ESMF.GridItem.MASK, +# staggerloc=self.staggerloc) + # Recompute weights only if masks are different. +# if(not numpy.array_equal(self.maskPtr, srcDataMask)): +# self.maskPtr[:] = srcDataMask[:] +# self.computeWeights(**args) + + zero_region = ESMF.Region.SELECT + if 'zero_region' in args.keys(): + zero_region=args.get('zero_region') + + self.srcFld.field.data[:] = srcData.T + self.dstFld.field.data[:] = dstData.T + # regrid + + self.regridObj(self.srcFld.field, self.dstFld.field, zero_region=zero_region) + + # fill in dstData + if rootPe is None and globalIndexing: + # only fill in the relevant portion of the data + slab = self.dstGrid.getLocalSlab(staggerloc=self.staggerloc) + dstData[slab] = self.dstFld.getData(rootPe=rootPe) + else: + tmp = self.dstFld.field.data.T + if tmp is None: + dstData = None + else: + dstData[:] = tmp + + def getDstGrid(self): + """ + Get the destination grid on this processor + @return grid + """ + return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) + for i in range(self.ndims)] + + def getSrcAreas(self, rootPe): + """ + Get the source grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.srcAreaField.field.get_area() + return self.srcAreaField.field.data + else: + return None + + def getDstAreas(self, rootPe): + """ + Get the destination grid cell areas + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return areas or None if non-conservative interpolation + """ + if self.regridMethod == CONSERVE: + # self.dstAreaField.field.get_area() + return self.dstAreaField.field.data + else: + return None + + def getSrcAreaFractions(self, rootPe): + """ + Get the source grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.srcFracField.field.data + else: + return None + + def getDstAreaFractions(self, rootPe): + """ + Get the destination grid area fractions + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + @return fractional areas or None (if non-conservative) + """ + if self.regridMethod == CONSERVE: + return self.dstFracField.field.data + else: + return + + def getSrcLocalShape(self, staggerLoc): + """ + Get the local source coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getCoordShape(stgloc) + + def getDstLocalShape(self, staggerLoc): + """ + Get the local destination coordinate/data shape + (may be different on each processor) + @param staggerLoc (e.g. 'center' or 'corner') + @return tuple + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getCoordShape(stgloc) + + def getSrcLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center'): + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.srcGrid.getLocalSlab(stgloc) + + def getDstLocalSlab(self, staggerLoc): + """ + Get the destination local slab (ellipsis). You can use + this to grab the data local to this processor + @param staggerLoc (e.g. 'center') + @return tuple of slices + """ + stgloc = CENTER + if re.match('corner', staggerLoc, re.I) or \ + re.search('nod', staggerLoc, re.I): + stgloc = CORNER + elif re.search('vface', staggerLoc, re.I) or \ + re.search('vcorner', staggerLoc, re.I): + stgloc = VFACE + return self.dstGrid.getLocalSlab(stgloc) + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'srcAreaFractions', 'dstAreaFractions', + 'srcAreas', 'dstAreas' + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + oldMethods = {} + oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' + oldMethods['dstAreaFractions'] = 'getDstAreaFractions' + oldMethods['srcAreas'] = 'getSrcAreas' + oldMethods['dstAreas'] = 'getDstAreas' + for entry in 'srcAreaFractions', 'dstAreaFractions', \ + 'srcAreas', 'dstAreas': + if entry in diag: + diag[entry] = eval( + 'self.' + oldMethods[entry] + '(rootPe=rootPe)').T + diag['regridTool'] = 'esmf' + diag['regridMethod'] = self.regridMethodStr + diag['periodicity'] = self.periodicity + diag['coordSys'] = self.coordSysStr + diag['staggerLoc'] = self.staggerlocStr diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py new file mode 100644 index 00000000..2452e9c4 --- /dev/null +++ b/regrid2/Lib/mvGenericRegrid.py @@ -0,0 +1,313 @@ +""" +Generic interface to multiple regrid classes. No dependence on cdms2 variables. + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +import operator +import numpy + +import regrid2 +import re +from distarray import MultiArrayIter +from functools import reduce + +# used to locate fully masked cells +EPS = 10 * 1.19209e-07 + + +def guessPeriodicity(srcBounds): + """ + Guess if a src grid is periodic + @param srcBounds the nodal src set of coordinates + @return 1 if periodic, warp around, 0 otherwise + """ + res = 0 + if srcBounds is not None: + res = 1 + # assume longitude to be the last coordinate + lonsb = srcBounds[-1] + nlon = lonsb.shape[-1] + dlon = (lonsb.max() - lonsb.min()) / float(nlon) + tol = 1.e-2 * dlon + if abs((lonsb[..., -1] - 360.0 - lonsb[..., 0] + ).sum() / float(lonsb.size)) > tol: + # looks like a regional model + res = 0 + return res + + +class GenericRegrid: + """ + Generic Regrid class. + """ + + def __init__(self, srcGrid, dstGrid, + dtype, + regridMethod, + regridTool, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + **args): + """ + Constructor. + @param srcGrid list of numpy arrays, source horizontal coordinates + @param dstGrid list of numpy arrays, destination horizontal coordinate + @param dtype numpy data type for src/dst data + @param regridMethod linear (bi, tri,...) default or conservative + @param regridTool currently either 'libcf' or 'esmf' + @param srcGridMask array of same shape as srcGrid + @param srcBounds list of numpy arrays of same shape as srcGrid + @param srcGridAreas array of same shape as srcGrid + @param dstGridMask array of same shape as dstGrid + @param dstBounds list of numpy arrays of same shape as dstGrid + @param dstGridAreas array of same shape as dstGrid + @param **args additional arguments to be passed to the + specific tool + 'libcf': mkCyclic={True, False}, handleCut={True,False} + 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... + """ + + self.nGridDims = len(srcGrid) + self.regridMethod = regridMethod + + if len(srcGrid) != len(dstGrid): + msg = 'mvGenericRegrid.__init__: mismatch in number of dims' + msg += ' len(srcGrid) = %d != len(dstGrid) = %d' % \ + (self.nGridDims, len(dstGrid)) + raise regrid2.RegridError(msg) + + # parse the options + if re.search('libcf', regridTool.lower()) or \ + re.search('gsreg', regridTool.lower()): + # LibCF + self.tool = regrid2.LibCFRegrid(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + **args) + elif re.search('esm', regridTool.lower()): + # ESMF + staggerLoc = args.get('staggerLoc', 'center') + if 'staggerLoc' in args: + del args['staggerLoc'] + periodicity = args.get('periodicity', + guessPeriodicity(srcBounds)) + if 'periodicity' in args: + del args['periodicity'] + coordSys = args.get('coordSys', 'deg') + if 'coordSys' in args: + del args['coordSys'] + + # Get the shapes + self.srcGridShape = srcGrid[0].shape + self.dstGridShape = dstGrid[0].shape + self.hasSrcBounds = False + self.hasDstBounds = False + + if srcBounds is not None: + self.hasSrcBounds = True + + if dstBounds is not None: + self.hasDstBounds = True + + self.srcGridAreasShape = None + self.dstGridAreasShape = None + + if srcGridAreas is not None: + self.srcGridAreasShape = srcGridAreas[0].shape + + if dstGridAreas is not None: + self.dstGridAreasShape = dstGridAreas[0].shape + + # Initialize + self.tool = regrid2.ESMFRegrid(self.srcGridShape, self.dstGridShape, + dtype=dtype, + regridMethod=regridMethod, + staggerLoc=staggerLoc, + periodicity=periodicity, + coordSys=coordSys, + hasSrcBounds=self.hasSrcBounds, + hasDstBounds=self.hasDstBounds, + srcGridAreasShape=self.srcGridAreasShape, + dstGridAreasShape=self.dstGridAreasShape, + **args) + + self.tool.setCoords(srcGrid, dstGrid, + srcGridMask=srcGridMask, + srcBounds=srcBounds, + srcGridAreas=srcGridAreas, + dstGridMask=dstGridMask, + dstBounds=dstBounds, + dstGridAreas=dstGridAreas, + globalIndexing=True, + **args) + else: + msg = """mvGenericRegrid.__init__: ERROR unrecognized tool %s, +valid choices are: 'libcf', 'esmf'""" % regridTool + raise regrid2.RegridError(msg) + + def computeWeights(self, **args): + """ + Compute Weights + """ + self.tool.computeWeights(**args) + + def apply(self, srcData, dstData, + rootPe=None, + missingValue=None, + **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param rootPe if other than None, then results will be MPI + gathered + @param missingValue if not None, then data mask will be interpolated + and data value set to missingValue when masked + """ + + # assuming the axes are the slowly varying indices + srcHorizShape = srcData.shape[-self.nGridDims:] + dstHorizShape = dstData.shape[-self.nGridDims:] + + srcDataMaskFloat = None + dstDataMaskFloat = None + dstMask = None + if missingValue is not None: + srcDataMaskFloat = numpy.zeros(srcHorizShape, srcData.dtype) + dstDataMaskFloat = numpy.zeros(dstHorizShape, dstData.dtype) + + nonHorizShape = srcData.shape[: -self.nGridDims] + + if len(nonHorizShape) == 0: + + # + # no axis... just call apply + # + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (srcData == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later + indata = numpy.array(srcData * (1 - (srcDataMaskFloat == 1)), + dtype=srcData.dtype) + + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, **args) + if re.search('conserv', self.regridMethod.lower(), re.I): + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + dstMask = numpy.array((dstDataMaskFloat > 0), numpy.int32) + + # Initialize output to missin_value + dstData[:] = missingValue + # interpolate the data + self.tool.apply(indata, dstData, rootPe=rootPe, + globalIndexing=True, **args) + + # add missing values + dstData *= (1 - dstMask) + dstData += dstMask * missingValue + + else: + # no masking, just interpolate the data + self.tool.apply(srcData, dstData, rootPe=rootPe, + globalIndexing=True, **args) + else: + + nonHorizShape2 = dstData.shape[: -self.nGridDims] + if not numpy.all(nonHorizShape2 == nonHorizShape): + msg = 'mvGenericRegrid.apply: axes detected ' + msg += 'but %s != %s ' % (str(nonHorizShape2), + str(nonHorizShape)) + raise regrid2.RegridError(msg) + + # + # iterate over all axes + # + + # create containers to hold input/output values + # (a copy is essential here) + zros = '[' + ('0,' * len(nonHorizShape)) + '...]' + indata = numpy.array(eval('srcData' + zros)) + outdata = numpy.array(eval('dstData' + zros)) + + # now iterate over all non lat/lon coordinates + for it in MultiArrayIter(nonHorizShape): + + indices = it.getIndices() + slce = '[' + slce += reduce(operator.add, ['%d,' % i for i in indices]) + slce += '...]' + indata = eval('srcData' + slce) + + # adjust for masking + if missingValue is not None: + + srcDataMaskFloat[:] = (indata == missingValue) + + # set field values to zero where missing, we'll add the mask + # contribution later +# indata *= (1 - (srcDataMaskFloat == 1)) + +# srcDataMaskFloatData = srcDataMaskFloat * numpy.random.rand(srcHorizShape[0],srcHorizShape[1])*100 + # interpolate mask + self.tool.apply(srcDataMaskFloat, dstDataMaskFloat, + rootPe=rootPe, globalIndexing=True, + srcDataMask=(1 - srcDataMaskFloat), **args) + + if re.search('conserv', self.regridMethod.lower(), re.I): + # cell interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 1 - EPS), numpy.int32) + else: + # nodal interpolation + dstMask = numpy.array( + (dstDataMaskFloat > 0), numpy.int32) + + # interpolate the data, using the appropriate tool + self.tool.apply(indata, outdata, rootPe=rootPe, + globalIndexing=True, + srcDataMask=srcDataMaskFloat, **args) + +# import vcs +# pp = vcs.init() +# pp.plot(indata) +# pp.interact() +# pp.clear() +# pp.plot(outdata) +# pp.interact() +# pp.clear() + # apply missing value contribution + if missingValue is not None: + # add mask contribution + outdata *= (1 - dstMask) + outdata += dstMask * missingValue + + # fill in dstData + exec('dstData' + slce + ' = outdata') + + def getDstGrid(self): + """ + Return the destination grid, may be different from the dst grid provided + to the constructor due to domain decomposition + @return local grid on this processor + """ + return self.tool.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe=None): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + entries are tool dependent + @param rootPe root processor where data should be gathered (or + None if local areas are to be returned) + """ + self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py new file mode 100644 index 00000000..30c5f4bf --- /dev/null +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -0,0 +1,101 @@ +""" +LibCF regridding class + +This code is provided with the hope that it will be useful. +No guarantee is provided whatsoever. Use at your own risk. + +David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" + +from regrid2 import gsRegrid +from regrid2 import GenericRegrid + + +class LibCFRegrid(GenericRegrid): + """ + """ + + def __init__(self, srcGrid, dstGrid, srcGridMask=None, + srcBounds=None, **args): + """ + Constructor + @param srcGrid array + @param dstGrid array + @param srcBounds cell boundaries + @param **args keyword arguments, eg mkCyclic, handleCut, ... + to be passed to gsRegrid + """ + self.regridMethodStr = 'linear' + self.mkCyclic = args.get('mkCyclic', False) + self.handleCut = args.get('handleCut', False) + self.verbose = args.get('verbose', False) + self.regridObj = gsRegrid.Regrid(srcGrid, dstGrid, + src_bounds=srcBounds, + mkCyclic=self.mkCyclic, + handleCut=self.handleCut) + if srcGridMask is not None: + self.regridObj.setMask(srcGridMask) + + # min resolution, required in order to set the tolerance (tolpos) + self.delta = float('inf') + for i in range(len(dstGrid)): + coordMin = dstGrid[i].min() + coordMax = dstGrid[i].max() + n = max(dstGrid[i].shape) + self.delta = min(self.delta, (coordMax - coordMin) / float(n)) + + def computeWeights(self, **args): + """ + Compute interpolation weights + @param **args arguments to be passed to gsRegrid, e.g. + nitermax, tolpos, ... + """ + nitermax = args.get('nitermax', 20) + # make tolpos relative to the min cell size + tolpos = args.get('tolpos', 0.01) * self.delta + self.regridObj.computeWeights(nitermax=nitermax, tolpos=tolpos) + + def apply(self, srcData, dstData, missingValue=None, **args): + """ + Regrid source to destination + @param srcData array (input) + @param dstData array (output) + @param missingValue value that should be set for points falling outside + the src domain, pass None if these should not be + touched. + """ + + self.regridObj.apply(srcData, dstData, missingValue) + + def getSrcGrid(self): + """ + Get the grid of the src data (maybe larger than the + dst grid passed to the constructor due to column/row + padding) + @return grid + """ + return self.regridObj.getSrcGrid() + + def getDstGrid(self): + """ + Get the grid of the dst data + @return grid + """ + return self.regridObj.getDstGrid() + + def fillInDiagnosticData(self, diag, rootPe): + """ + Fill in diagnostic data + @param diag a dictionary whose entries, if present, will be filled + valid entries are: 'numDstPoints' and 'numValid' + @param rootPe not used + """ + for entry in 'numDstPoints', 'numValid': + if entry in diag: + meth = 'get' + entry[0].upper() + entry[1:] + diag[entry] = eval('self.regridObj.' + meth + '()') + diag['regridTool'] = 'libcf' + diag['regridMethod'] = self.regridMethodStr + diag['handleCut'] = self.handleCut + diag['mkCyclic'] = self.mkCyclic + diag['verbose'] = self.verbose diff --git a/regrid2/Lib/mytest.py b/regrid2/Lib/mytest.py new file mode 100644 index 00000000..e91d1361 --- /dev/null +++ b/regrid2/Lib/mytest.py @@ -0,0 +1,2 @@ +import ESMF # noqa +from .mvESMFRegrid import ESMFRegrid # noqa diff --git a/regrid2/Lib/pressure.py b/regrid2/Lib/pressure.py new file mode 100644 index 00000000..fb79a9e2 --- /dev/null +++ b/regrid2/Lib/pressure.py @@ -0,0 +1,490 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by +import cdms2 +import numpy +#from . import _regrid +import regrid2._regrid as _regrid +from .error import RegridError +import copy + + +class PressureRegridder: + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data into the ouput data along + # the pressure dimension only. + # + # PROCEDURE: Step One: + # Make an instance of class PressureRegridder passing it input and output grid information + # Step Two: + # Pass the input data with some descriptive parameters and get the output data + # in return + # + #------------------------------------------------------------------------------------------------""" + + def __init__(self, axisIn, axisOut): + """ #----------------------------------------------------------------------------------------------- + # + # PURPOSE: To make an instance which entails setting up the input and output grids + # + # DEFINITION: + # + # def __init__(self, levIn, levOut): + # + # PROCEDURE: + # + # The user must assemble two pieces of information: + # + # axisIn - the input level axis + # + # axisOut - the output level axis + # + # USAGE: + # + # To make an instance preparing for a regrid along the level dimension pnly, type + # + # r = PressureRegridder(levIn, levOut) + # + #------------------------------------------------------------------------------------------------""" + + # --- set the instance grid data attributes used to describe input and output grid sizes + + self.axisIn = axisIn + self.axisOut = axisOut + self.nlevi = len(axisIn) + self.nlevo = len(axisOut) + + def __call__(self, ar, missing=None, order=None, method="log"): + """ + Call the pressure regridder function. + ar is the input array, a variable, masked array, or numpy array. + missing is the missing data value, if any. It defaults to the missing/fill value + defined for the input array, if any. + order is of the form "tzyx", "tyx", etc. + method is either 'log' to interpolate in the log of pressure, or 'linear' for linear interpolation. + """ + + from cdms2.avariable import AbstractVariable + from cdms2.tvariable import TransientVariable + + # Save Variable metadata for output + if isinstance(ar, AbstractVariable): + attrs = copy.copy(ar.attributes) + varid = ar.id + axislist = ar.getAxisList() + inputIsVariable = 1 + if order is None: + order = ar.getOrder() + # this expects contiguous arrays + if isinstance( + ar, TransientVariable) and ar.iscontiguous() is False: + ar = ar.ascontiguous() + else: + inputIsVariable = 0 + + # Turn ar into a numpy array. + if numpy.ma.isMaskedArray(ar): + armiss = ar.fill_value + ar = numpy.ma.filled(ar) + elif isinstance(ar, AbstractVariable): + tempar = ar.getValue(squeeze=0) + armiss = ar.getMissing() + ar = numpy.ma.filled(tempar) + elif isinstance(ar, numpy.ndarray): + armiss = None + else: + raise RegridError( + "Input array is not a Variable, numpy.ma, or numpy array") + + # Set missing value + if missing is None: + missing = armiss + if isinstance(missing, numpy.ndarray): + missing = missing[0] + + rank = len(ar.shape) + assert 3 <= rank <= 4, 'Array rank is %i, must be 3 or 4' % rank + + # Set the default order to match the input grid order + if order is None: + if rank == 3: + order = "zyx" + elif rank == 4: + order = "tzyx" + + assert rank == len( + order), 'Order must be same length as array rank: %i' % len(ar.shape) + + order = order.lower() + + # Map order to positionIn + positionIn = [None] * 4 + for i in range(len(order)): + if order[i] == 'x': + positionIn[0] = i + elif order[i] == 'y': + positionIn[1] = i + elif order[i] == 'z': + positionIn[2] = i + if inputIsVariable: + axislist[i] = self.axisOut + else: + positionIn[3] = i + + # Regrid + if method == 'log': + logYes = 'yes' + else: + logYes = 'no' + outar = self.rgrd(ar, missing, 'greater', logYes, positionIn) + + # Reconstruct the same class as on input + if inputIsVariable == 1: + result = cdms2.createVariable(outar, fill_value=missing, + axes=axislist, attributes=attrs, id=varid) + else: + result = numpy.ma.masked_array(outar, fill_value=missing) + + return result + + def rgrd(self, dataIn, missingValueIn, missingMatch, + logYes='yes', positionIn=None, missingValueOut=None): + """ #--------------------------------------------------------------------------------- + # + # PURPOSE: To perform all the tasks required to regrid the input data, dataIn, into the ouput data, + # dataout along the level dimension only. + # + # DEFINITION: + # + # def rgrd(self, dataIn, missingValueIn, missingMatch, positionIn = None, missingValueOut = None): + # + # + # PASSED : dataIn -- data to regrid + # + # missingValueIn -- the missing data value to use in setting missing in the mask. It is required + # and there are two choices: + # None -- there is no missing data + # A number -- the value to use in the search for possible missing data. + # The presence of missing data at a grid point leads to recording 0.0 in the mask. + # + # missingMatch -- the comparison scheme used in searching for missing data in dataIn using + # the value passed in as missingValueIn. The choices are: + # None -- used if None is the entry for missingValueIn + # exact -- used if missingValue is the exact value from the file + # greater -- the missing data value is equal to or greater than missingValueIn + # less -- the missing data value is equal to or less than missingValueIn + # + # logYes -- choose the level regrid as linear in log of level or linear in level. Set to + # 'yes' for log. Anything else is linear in level. + # + # + # + # positionIn -- a tuple with the numerical position of the dimensions + # in C or Python order specified in the sequence longitude, + # latitude, level and time. Longitude, latitude and level are + # required. If time is missing submit None in its slot in the + # tuple. Notice that the length of the tuple is always four. + # + # Explicitly, in terms of the shape of dataIn as returned by Python's shape function + # + # positionIn[0] contains the position of longitude in dataIn + # positionIn[1] contains the position of latitude in dataIn + # positionIn[2] contains the position of level in dataIn or None + # positionIn[3] contains the position of time in dataIn or None + # + # As examples: + # If the C order shape of 4D data is + # (number of longitudes, number of times, number of levels, + # number of latitudes) + # submit + # (0, 3, 2, 1) + # + # If the C order shape of 3D data is + # (number of longitudes, number of times, number oflatitudes) + # submit + # (0, 2, 1, None) + # + # Send in None if the shape is a subset of (time, level, + # latitude, longitude) which is evaluated as follows: + # 3D -- code assumes (2,1,0,None) + # 4D -- code assumes (3,2,1,0) + # + # missingValueOut -- the value for the missing data used in writing the output data. If left at the + # default entry, None, the code uses missingValueIn if present or as a last + # resort + # 1.0e20 + # + # + # RETURNED : dataOut -- the regridded data + # + # + # USAGE: + # + # Example 1. To regrid dataIn into dataOut using all the defaults where None, None signifies no + # missing data. + # dataOut = x.rgrd(dataIn, None, None) + # + # Example 2. To regrid dataIn into dataOut using 1.0e20 and greater as the missing data + # + # dataOut = x.rgrd(dataIn, 1.e20, 'greater') + # + # ----------------------------------------------------------------------------------------------------------""" + + # check the required input -- dataIn, missingValueIn and missingMatch + + # make sure that dataIn is an array + + try: + len(dataIn) + except TypeError: + sendmsg('Error in calling the rgrd method -- dataIn must be an array') + raise TypeError + + # check the missingValueIn pass + + if missingValueIn is not None: + try: + abs(missingValueIn) + except TypeError: + sendmsg( + 'Error in calling the rgrd method -- missingvalueIn must be None or a number. Now it is ', + missingValueIn) + raise TypeError + + # check the missingMatch pass + + missingPossibilities = ['greater', 'equal', 'less', None] + if missingMatch not in missingPossibilities: + msg = 'Error in missingMatch -- it must be None or the string greater, equal, or less. Now it is ' + sendmsg(msg, missingMatch) + raise ValueError + + # --- Check data type and change to float if necessary ---- + + if dataIn.dtype.char != 'f': + dataIn = dataIn.astype(numpy.float32) + + dataShape = dataIn.shape + numberDim = len(dataShape) + + if numberDim < 2: + msg = 'Error in call to rgrd -- data must have at least 2 dimensions' + sendmsg(msg) + raise TypeError + + # --- evaluate positionIn ---- + + # --- make standard positionIn as a check---- + positionList = [] + for n in range(numberDim): # insert a sequence of numbers + positionList.append(n) + positionList.reverse() + + for n in range(numberDim, 4): # fill end of list with Nones + positionList.append(None) + + positionCheck = tuple(positionList) + + standardPosition = 0 # transpose required + + if positionIn is None: # construct the default positionIn tuple + positionIn = positionCheck + standardPosition = 1 # no need for a transpose with this data + else: + if positionIn == positionCheck: # compare to the standard + standardPosition = 1 # no need for a transpose with this data + + if len(positionIn) != 4: + msg = 'Error in call to rgrd -- positionIn must be a tuple of length 4' + sendmsg(msg) + raise TypeError + + # transpose data to the standard order (t,z,y,x) + if standardPosition == 0: + + newOrder, inverseOrder = checkorder(positionIn) + + # transpose data to standard order (t,z,y,x) + dataIn = numpy.transpose(dataIn, newOrder) + dataIn = numpy.array( + dataIn.astype( + numpy.float32), + numpy.float32) # make contiguous + + # set dimension sizes and check for consistency + + if positionIn[0] is not None: + self.nlon = (dataShape[positionIn[0]]) + else: + self.nlon = 0 + if positionIn[1] is not None: + self.nlat = (dataShape[positionIn[1]]) + else: + self.nlat = 0 + if positionIn[2] is not None: + if self.nlevi != (dataShape[positionIn[2]]): + msg = 'Level size is inconsistent with input data' + sendmsg(msg) + raise ValueError + if positionIn[3] is not None: + self.ntime = (dataShape[positionIn[3]]) + else: + self.ntime = 0 + + # allocate memory for dataOut -- the array with new number of levels + + outList = list(dataIn.shape) + + for i in range(len(outList)): + if outList[i] == self.nlevi: + outList[i] = self.nlevo + break + + dataOut = numpy.zeros( + tuple(outList), + numpy.float32) # memory for aout + + if missingMatch is None: # if no missing do not pass None + missingMatch = 'none' + + # if no missing do not pass None + if missingValueIn is None: + missingValueIn = 1.333e33 + + if logYes != 'yes': + logYes = 'no' + + levIn = self.axisIn[:].astype(numpy.float64) + levOut = self.axisOut[:].astype(numpy.float64) + _regrid.rgdpressure( + self.nlevi, + self.nlevo, + self.nlat, + self.nlon, + self.ntime, + missingValueIn, + missingMatch, + logYes, + levIn, + levOut, + dataIn, + dataOut) + + # if no missing do not pass None + if missingMatch == 'none': + missingMatch = None + if missingValueIn == 1.333e33: + missingValueIn = None + + if standardPosition == 0: + # transpose data to original order + dataOut = numpy.transpose(dataOut, inverseOrder) + dataOut = numpy.array( + dataOut.astype( + numpy.float32), + numpy.float32) # make contiguous + + if missingValueOut is not None: # set the missing value in data to missingValueOut + + if missingMatch == 'greater': + if missingValueIn > 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.greater( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'equal': + missing = missingValueIn + dataOut = numpy.where( + numpy.equal( + dataOut, + missing), + missingValueOut, + dataOut) + + elif missingMatch == 'less': + if missingValueIn < 0.0: + missing = 0.99 * missingValueIn + else: + missing = 1.01 * missingValueIn + + dataOut = numpy.where( + numpy.less( + dataOut, + missing), + missingValueOut, + dataOut) + + return dataOut + + +def checkorder(positionIn): + """ #----------------------------------------------------------------------------------------- + # + # purpose: construct the tuples for transposing the data to standard dimension order and the + # inverse for transposing it back to the original dimension order + # + # usage: newOrder, inverseOrder = checkorder(positionIn) + # + # passed: positionIn -- array with location of longitude, latitude. level and time respectively + # in the sense of the python shape of the data + # + # returned: newOrder -- tuple to transpose data to the order (t,z,y,x) + # inverseOrder -- tuple to transpose data to back to the original order + # + #----------------------------------------------------------------------------------------------""" + + # remove the None values from positionIn and reverse the order + + reducedPosition = [] + for item in positionIn: + if item is not None: + reducedPosition.append(item) + reducedPosition.reverse() + + # make the newOrder tuple + + newOrder = tuple(reducedPosition) + + # ----- Determine the inverse to this new order for use in mathtogeo ----- + + xform = [] + for i in range(len(newOrder)): + xform.append([newOrder[i], i]) + xform.sort() + + inverse_shapelist = [] + for item in xform: + inverse_shapelist.append(item[1]) + inverseOrder = tuple(inverse_shapelist) + + return newOrder, inverseOrder + + +def sendmsg(msg, value1=None, value2=None): + """ #--------------------------------------------------------------------------------- + # + # purpose: send the same message to the screen + # + # passed : msg - the string + # value - the number associated with the string + # + # returned: return + # + #---------------------------------------------------------------------------------""" + + print('*******************************************************************') + if value1 is None: + print(msg) + elif value2 is None: + print((msg, value1)) + else: + print((msg, value1, value2)) + print('*******************************************************************') + + return None diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py new file mode 100644 index 00000000..5a052700 --- /dev/null +++ b/regrid2/Lib/scrip.py @@ -0,0 +1,447 @@ +# Automatically adapted for numpy.oldnumeric Aug 02, 2007 by + +import cdms2 +#from . import _scrip +import regrid2._scrip as _scrip +from .error import RegridError +import numpy +from functools import reduce + +"""Regrid support for nonrectangular grids, based on the SCRIP package.""" + + +class ScripRegridder: + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + self.outputGrid = outputGrid + self.remapMatrix = remapMatrix + self.sourceAddress = sourceAddress + self.destAddress = destAddress + self.inputGrid = inputGrid + self.sourceFrac = sourceFrac + self.destFrac = destFrac + + def __call__(self, input): + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + # this expects contiguous arrays + if input.iscontiguous() is False: + input = input.ascontiguous() + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + + # Regrid + output = self.regrid(input) + + # Reshape output and restore input shape + input.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + def getOutputGrid(self): + return self.outputGrid + + def getInputGrid(self): + return self.inputGrid + + def getSourceFraction(self): + return self.sourceFrac + + def getDestinationFraction(self): + return self.destFrac + + +class ConservativeRegridder(ScripRegridder): + """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' + is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length + as the output grid size, with values: + 1.0 for normalize="fracarea", + grid_frac for normalize="destarea", or + grid_frac*grid_area for normalize="none". + sourceArea is the area of the source grid cells + destArea is the area of the destination grid cells + """ + + def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, + sourceFrac=None, destFrac=None, normalize="fracarea", normal=None, sourceArea=None, destArea=None): + if normalize not in ["fracarea", "destarea", "none"]: + raise RegridError("Invalid normalization option: %s" % normalize) + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + self.normalize = normalize + self.normal = None + self.sourceArea = sourceArea + self.destArea = destArea + + def getSourceArea(self): + return self.sourceArea + + def getDestinationArea(self): + return self.destArea + + def regrid(self, input): + if self.normal is None: + # print "On input, num_links = %d"%(len(self.sourceAddress)) + # print "On input, nextra = %d"%(input.shape[0]) + # print "On input, ninput = %d"%(input.shape[1]) + # print "On input, noutput = %d"%(self.outputGrid.size()) + # print "On input, shape(input) = %s"%`input.shape` + # print "On input, shape(output) = %s"%`self.outputGrid.shape` + # print "On input, shape(remap_matrix) = %s"%`self.remapMatrix.shape` + # print "On input, shape(src_address) = %s"%`self.sourceAddress.shape` + # print "On input, shape(dst_address) = + # %s"%`self.destAddress.shape` + result = _scrip.conserv_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + else: + result = _scrip.conserv_regrid_normal( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + self.normal) + return result + + +class BilinearRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.bilinear_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +class BicubicRegridder(ScripRegridder): + """Bicubic regrid.""" + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def __call__(self, input, gradLat, gradLon, gradLatlon): + """gradLat = df/di + gradLon = df/dj + gradLatlon = d(df)/(di)(dj) + """ + + import numpy.ma + from cdms2 import isVariable + from cdms2.tvariable import TransientVariable + + if (gradLat.shape != input.shape or + gradLon.shape != input.shape or + gradLatlon.shape != input.shape): + raise RegridError( + "All input arrays must have shape %s" % + repr( + input.shape)) + + if (not isinstance(gradLat, type(input)) or + not isinstance(gradLon, type(input)) or + not isinstance(gradLatlon, type(input))): + raise RegridError( + "All input arrays must have type %s" % + repr( + type(input))) + + # If input is a variable, make it a TV + if isVariable(input) and not isinstance(input, TransientVariable): + input = input.subSlice() + gradLat = gradLat.subSlice() + gradLon = gradLon.subSlice() + gradLatlon = gradLatlon.subSlice() + + isvar = isinstance(input, TransientVariable) + + if isvar: + domain = tuple(input.getAxisList()) + if self.inputGrid is not None: + ingrid = self.inputGrid + else: + ingrid = input.getGrid() + if ingrid is None: + raise RegridError( + "Input variable must have an associated grid.") + rank = len(ingrid.shape) + gridsize = ingrid.size() + outgridshape = self.outputGrid.shape + + # Check that the grid matches the last dimension(s) of input + if input.shape[-rank:] != ingrid.shape: + raise RegridError( + 'Last dimensions of input array must match grid shape: %s' % + repr( + ingrid.shape)) + + else: + rank = 1 # If not a TV, last dimension is the 'cell' dimension + gridsize = input.shape[-1] + outgridshape = ( + reduce( + lambda x, + y: x * y, + self.outputGrid.shape, + 1), + ) + + # If input is an numpy.ma, make it Numeric + if numpy.ma.isMaskedArray(input): + input = input.filled() + gradLat = gradLat.filled() + gradLon = gradLon.filled() + gradLatlon = gradLatlon.filled() + + restoreShape = input.shape[:-rank] + restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) + oldshape = input.shape + newshape = (restoreLen, gridsize) + input.shape = newshape + gradLat.shape = newshape + gradLon.shape = newshape + gradLatlon.shape = newshape + + # Regrid + output = _scrip.bicubic_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress, + gradLat, + gradLon, + gradLatlon) + + # Reshape output and restore input shape + input.shape = oldshape + gradLat.shape = oldshape + gradLon.shape = oldshape + gradLatlon.shape = oldshape + outshape = restoreShape + outgridshape + output.shape = outshape + + # If the input was a variable, so is the output + if isvar: + outdomain = domain[:-rank] + (self.outputGrid,) + output = TransientVariable(output, axes=outdomain) + + return output + + +class DistwgtRegridder(ScripRegridder): + + def __init__(self, outputGrid, remapMatrix, sourceAddress, + destAddress, inputGrid=None, sourceFrac=None, destFrac=None): + ScripRegridder.__init__( + self, + outputGrid, + remapMatrix, + sourceAddress, + destAddress, + inputGrid=inputGrid, + sourceFrac=sourceFrac, + destFrac=destFrac) + + def regrid(self, input): + result = _scrip.distwgt_regrid( + self.outputGrid.size(), + input, + self.remapMatrix, + self.sourceAddress, + self.destAddress) + return result + + +def readRegridder(fileobj, mapMethod=None, checkGrid=1): + """Read a regridder from an open fileobj. + mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method + defined in the file. + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, + and 'repaired' if necessary. + """ + + if isinstance(fileobj, str): + fileobj = cdms2.open(fileobj) + elif not isinstance(fileobj, cdms2.dataset.CdmsFile): + raise RegridError( + "fileobj arguments must be a cdms2 file or a string pointing to a file") + + if mapMethod is None: + mapString = fileobj.map_method.strip().lower() + if mapString[0:12] == "conservative": + mapMethod = "conservative" + elif mapString[0:8] == "bilinear": + mapMethod = "bilinear" + elif mapString[0:7] == "bicubic": + mapMethod = "bicubic" + elif mapString[0:8] == "distance" or mapString[0:7] == "distwgt": + mapMethod = "distwgt" + else: + raise RegridError("Unrecognized map method: %s" % mapString) + + convention = 'SCRIP' + if list(fileobj.variables.keys()).count('S'): + convention = 'NCAR' + if convention == 'SCRIP': + remapMatrix = fileobj('remap_matrix').filled() + srcAddress = fileobj('src_address').filled() + dstAddress = fileobj('dst_address').filled() + srcfrac = fileobj('src_grid_frac') + dstfrac = fileobj('dst_grid_frac') + else: + remapMatrix = fileobj('S').filled() + srcAddress = fileobj('col').filled() + dstAddress = fileobj('row').filled() + srcfrac = fileobj('frac_a') + dstfrac = fileobj('frac_b') + ingrid = fileobj.readScripGrid(whichGrid="source", checkGrid=checkGrid) + outgrid = fileobj.readScripGrid( + whichGrid="destination", + checkGrid=checkGrid) + + if mapMethod == "conservative": + if convention == 'SCRIP': + srcarea = fileobj('src_grid_area') + dstarea = fileobj('dst_grid_area') + else: # NCAR stuff + if "S2" in list(fileobj.variables.keys()): + remapMatrix = fileobj("S2") + sh = list(remapMatrix.shape) + if len(sh) == 2 and sh[-1] == 2: + sh[-1] = 1 + S = fileobj("S").filled() + S.shape = sh + remapMatrix = numpy.concatenate((S, remapMatrix), axis=1) + srcarea = fileobj('area_a') + dstarea = fileobj('area_b') + regridder = ConservativeRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac, + sourceArea=srcarea, + destArea=dstarea) + elif mapMethod == "bilinear": + regridder = BilinearRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "bicubic": + regridder = BicubicRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + elif mapMethod == "distwgt": + regridder = DistwgtRegridder( + outgrid, + remapMatrix, + srcAddress, + dstAddress, + inputGrid=ingrid, + sourceFrac=srcfrac, + destFrac=dstfrac) + else: + raise RegridError("Unrecognized map method: %s" % mapMethod) + + return regridder From c2baa86f3c8fff045077654941c92a0cf05e7cc9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:11:43 -0700 Subject: [PATCH 099/239] try readthedocs.yml file --- Lib/git.py | 1 - docs/environment.yml | 69 ++++++++++++++++++++++++++++++++++++++++++++ readthedocs.yml | 12 ++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) delete mode 100644 Lib/git.py create mode 100644 docs/environment.yml create mode 100644 readthedocs.yml diff --git a/Lib/git.py b/Lib/git.py deleted file mode 100644 index 30023a51..00000000 --- a/Lib/git.py +++ /dev/null @@ -1 +0,0 @@ -closest_tag = '3.0' \ No newline at end of file diff --git a/docs/environment.yml b/docs/environment.yml new file mode 100644 index 00000000..a7ed92c4 --- /dev/null +++ b/docs/environment.yml @@ -0,0 +1,69 @@ +name: rtdh +channels: +- conda-forge +- defaults +dependencies: +- asn1crypto=0.24.0=py27_0 +- ca-certificates=2018.4.16=0 +- cdat_info=8.0=py27_0 +- cdms2=3.0=py27_6 +- cdtime=3.0=py27_0 +- certifi=2018.4.16=py27_0 +- cffi=1.11.5=py27_0 +- chardet=3.0.4=py27_0 +- clapack=3.2.1=0 +- cryptography=2.2.1=py27_0 +- curl=7.59.0=1 +- distarray=2.12.2=py27_0 +- enum34=1.1.6=py27_1 +- esmf=7.1.0r=0 +- esmpy=7.1.0r=py27_1 +- future=0.16.0=py27_0 +- g2clib=1.6.0=5 +- hdf4=4.2.13=0 +- hdf5=1.10.1=2 +- idna=2.6=py27_1 +- ipaddress=1.0.22=py_1 +- jasper=1.900.1=4 +- jpeg=9b=2 +- krb5=1.14.6=0 +- lapack=3.6.1=1 +- libcdms=3.0.1=0 +- libcf=1.0.1=py27_1 +- libdrs=3.0=0 +- libdrs_f=3.0=0 +- libffi=3.2.1=3 +- libnetcdf=4.4.1.1=10 +- libpng=1.6.34=0 +- libssh2=1.8.0=2 +- libtiff=4.0.9=0 +- mkl_fft=1.0.2=py27_0 +- mkl_random=1.0.1=py27_0 +- mpi=1.0=mpich +- mpich=3.2.1=0 +- ncurses=5.9=10 +- netcdf-fortran=4.4.4=6 +- openssl=1.0.2o=0 +- ossuuid=1.6.2=0 +- pycparser=2.18=py27_0 +- pyopenssl=17.5.0=py27_1 +- pysocks=1.6.8=py27_1 +- python=2.7.14=5 +- readline=7.0=0 +- requests=2.18.4=py27_1 +- setuptools=39.0.1=py27_0 +- six=1.11.0=py27_1 +- sqlite=3.20.1=2 +- tk=8.6.7=0 +- urllib3=1.22=py27_0 +- xz=5.2.3=0 +- zlib=1.2.11=0 +- intel-openmp=2018.0.0=8 +- libgcc=7.2.0=h69d50b8_2 +- libgcc-ng=7.2.0=hdf63c60_3 +- libgfortran=3.0.0=1 +- libgfortran-ng=7.2.0=hdf63c60_3 +- libstdcxx-ng=7.2.0=hdf63c60_3 +- mkl=2018.0.2=1 +- numpy=1.14.2=py27hdbf6ddf_1 +prefix: /software/anaconda2/envs/rtdh diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 00000000..7ed0cd59 --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,12 @@ +formats: + - epub + - pdb + +requirements_file: docs/requirements.txt:wq + +conda: + - file: docs/environment.yml + +python: + - setup_py_install: true + From 970bb4e89b4d45b02a7b458f4492a67fd2f0a269 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:13:49 -0700 Subject: [PATCH 100/239] fix readthedocs maping file --- readthedocs.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/readthedocs.yml b/readthedocs.yml index 7ed0cd59..0ee9d4ce 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -5,8 +5,11 @@ formats: requirements_file: docs/requirements.txt:wq conda: - - file: docs/environment.yml + file: docs/environment.yml +build: + image: latest python: - - setup_py_install: true + version: 2.70 + setup_py_install: true From 92b39e64b5844b2e2880bb92335b824d17dedf60 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:14:21 -0700 Subject: [PATCH 101/239] change type pdb to pdf --- readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs.yml b/readthedocs.yml index 0ee9d4ce..090d53d2 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -1,6 +1,6 @@ formats: - epub - - pdb + - pdf requirements_file: docs/requirements.txt:wq From b0df74fdef5e4ddbab54d3f2ffae32df4eb9214d Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:14:58 -0700 Subject: [PATCH 102/239] typo requirements.yml --- readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs.yml b/readthedocs.yml index 090d53d2..e5e49ce6 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -2,7 +2,7 @@ formats: - epub - pdf -requirements_file: docs/requirements.txt:wq +requirements_file: docs/requirements.txt conda: file: docs/environment.yml From 26661a8faab3bc12732d051e16154f314c82b2c9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:24:05 -0700 Subject: [PATCH 103/239] add dependencies --- docs/environment.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/environment.yml b/docs/environment.yml index a7ed92c4..aa21dce3 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -12,13 +12,15 @@ dependencies: - cffi=1.11.5=py27_0 - chardet=3.0.4=py27_0 - clapack=3.2.1=0 +- colorama=0.3.9=py27_0 +- colorlog=3.1.2=py27_0 - cryptography=2.2.1=py27_0 - curl=7.59.0=1 - distarray=2.12.2=py27_0 +- easydev=0.9.36=py27_0 - enum34=1.1.6=py27_1 - esmf=7.1.0r=0 - esmpy=7.1.0r=py27_1 -- future=0.16.0=py27_0 - g2clib=1.6.0=5 - hdf4=4.2.13=0 - hdf5=1.10.1=2 @@ -45,6 +47,8 @@ dependencies: - netcdf-fortran=4.4.4=6 - openssl=1.0.2o=0 - ossuuid=1.6.2=0 +- pexpect=4.5.0=py27_0 +- ptyprocess=0.5.2=py27_0 - pycparser=2.18=py27_0 - pyopenssl=17.5.0=py27_1 - pysocks=1.6.8=py27_1 @@ -58,6 +62,7 @@ dependencies: - urllib3=1.22=py27_0 - xz=5.2.3=0 - zlib=1.2.11=0 +- future=0.16.0=py27_1 - intel-openmp=2018.0.0=8 - libgcc=7.2.0=h69d50b8_2 - libgcc-ng=7.2.0=hdf63c60_3 From 721da2d3e15a30bc2a26bd21433e97cadd6cb2bf Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:25:14 -0700 Subject: [PATCH 104/239] add dependencies and change conf.yml --- docs/source/conf.py | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 4183add0..e291694d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,35 +15,6 @@ install_aliases() import sys import os -sys.path.append(os.path.abspath('../../regrid2')) -sys.path.append(os.path.abspath('../..')) -import mock -os.environ['READTHEDOCS']="True" -#MOCK_MODULES = ['collections', 'numpy', 'Cdunif', 'numpy.core.multiarray', 'cdat_info', 'cdtime', 'future', 'cdms2'] -MOCK_MODULES =[ 'Cdunif', 'axis', 'OpenSSL', 'cdat_info', 'cdtime', 'cdms2', 'future', 'myproxy_logon', 'collections.UserList', 'UserList', 'regrid2', 'regrid2.mvGenericRegrid', 'bindex', '_bindex', 'cdms2.avariable', 'cdms2.tvariable', 'cdms2.grid', 'cdms2.error', 'cdms2.axis', 'cdms2.Cdunif','regrid2._regrid', 'regrid2._scrip'] -#,'distarray','collections'] -#'urllib.parse','urllib.request','urllib.error','ESMF'] - - -def side_effect(*args, **kwargs): - return mock.DEFAULT - -for mod_name in MOCK_MODULES: - m = mock.Mock() - m.return_value=3 - m.side_effect = side_effect - sys.modules[mod_name] = m - -import glob -print "***" -print glob.glob("../../regrid2/*") -if os.path.isdir('../../regrid2/Lib'): - os.rename('../../regrid2/Lib', '../../regrid2/Libregrid') -print "***" -print glob.glob("../../regrid2/*") - -print os.getcwd() - import sys import os @@ -56,9 +27,8 @@ def side_effect(*args, **kwargs): # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) -#sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) -#sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) -sys.path.insert(0,"..") +sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) +sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) print os.path.join(sys.prefix,"lib","python2.7","site-packages") From 2dc4acc0dd2863616d77b2424b0705e980ba3454 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 14:50:03 -0700 Subject: [PATCH 105/239] change API.rst and other rst files --- docs/Makefile | 1 - docs/source/API.rst | 2 +- docs/source/avariable.rst | 2 +- docs/source/axis.rst | 2 +- docs/source/fvariable.rst | 2 +- docs/source/horizontal.rst | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index b4df31a1..61c88bb2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -55,7 +55,6 @@ html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - @mv ../regrid2/Libregrid/ ../regrid2/Lib dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml diff --git a/docs/source/API.rst b/docs/source/API.rst index 6a83760f..15787d00 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -1,6 +1,6 @@ API === -.. currentmodule:: Lib +.. currentmodule:: cdms2 Classes ------- diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index 5a4ae51e..0d8a099b 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -1,7 +1,7 @@ avariable ========= -.. automodule:: Lib.avariable +.. automodule:: cdms2.avariable :members: diff --git a/docs/source/axis.rst b/docs/source/axis.rst index 7cbe4f35..e032851f 100644 --- a/docs/source/axis.rst +++ b/docs/source/axis.rst @@ -1,7 +1,7 @@ axis ==== -.. automodule:: Lib.axis +.. automodule:: cdms2.axis :members: diff --git a/docs/source/fvariable.rst b/docs/source/fvariable.rst index 14e69707..a433f3d4 100644 --- a/docs/source/fvariable.rst +++ b/docs/source/fvariable.rst @@ -1,7 +1,7 @@ fvariable ========= -.. automodule:: Lib.fvariable +.. automodule:: cdms2.fvariable :members: diff --git a/docs/source/horizontal.rst b/docs/source/horizontal.rst index 288f3c09..806572a3 100644 --- a/docs/source/horizontal.rst +++ b/docs/source/horizontal.rst @@ -1,7 +1,7 @@ regrid2-horizontal ================== -.. automodule:: Libregrid.horizontal +.. automodule:: regrid2.horizontal :members: From 9d1487aef7c73ca023c10e26e38b55fa9712a20c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 24 Apr 2018 15:47:01 -0700 Subject: [PATCH 106/239] Changes to API --- docs/source/API.rst | 4 +- regrid2/Lib/esmf.py | 145 ++++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 61 deletions(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index 6a83760f..10105dd3 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -67,7 +67,9 @@ Regridder pressure scrip mvLibCFRegrid - gs_horizontal + + + diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index ccabad43..242fa033 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -75,19 +75,21 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """ Set Cell connectivity - Parameters - ---------- - - cell indices (0-based) + ---------- + + cell indices + (0-based) - cellTypes one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + cellTypes + one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - connectivity node connectivity array, see below for node ordering + connectivity node + connectivity array, see below for node ordering - cellMask + cellMask - cellAreas area (volume) of each cell + cellAreas area (volume) of each cell Note ---- @@ -146,11 +148,14 @@ def setNodes(self, indices, coords, peOwners=None): Parameters ---------- - indices Ids of the nodes (0-based) + indices + Ids of the nodes (0-based) - coords nodal coordinates + coords + nodal coordinates - peOwners processor ranks where the coordinates reside (0-based) + peOwners + processor ranks where the coordinates reside (0-based) """ n = len(indices) if not self.nodesAdded: @@ -168,7 +173,9 @@ def toVTK(self, filename): Parameters ---------- - filename VTK file name + filename + VTK file name + _: None """ @@ -194,22 +201,27 @@ def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, Parameters ---------- - shape Tuple of cell sizes along each axis + shape + Tuple of cell sizes along each axis - coordSys coordinate system - ESMF.CoordSys.CART Cartesian - ESMF.CoordSys.SPH_DEG (default) Degrees - ESMF.CoordSys.SPH_RAD Radians - - periodicity Does the grid have a periodic coordinate - 0 No periodicity - 1 Periodic in x (1st) axis - 2 Periodic in x, y axes + coordSys + coordinate system + ESMF.CoordSys.CART Cartesian + ESMF.CoordSys.SPH_DEG (default) Degrees + ESMF.CoordSys.SPH_RAD Radians + + periodicity + Does the grid have a periodic coordinate + 0 No periodicity + 1 Periodic in x (1st) axis + 2 Periodic in x, y axes - staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX - The stagger constants are listed at the top + staggerloc + ESMF stagger location. ESMF.StaggerLoc.XXXX + The stagger constants are listed at the top - hasBounds If the grid has bounds, Run AddCoords for the bounds + hasBounds + If the grid has bounds, Run AddCoords for the bounds """ # ESMF grid object self.grid = None @@ -336,14 +348,13 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): staggerloc The stagger location - ESMF.StaggerLoc.CENTER (default) - ESMF.StaggerLoc.CORNER + ESMF.StaggerLoc.CENTER (default) + ESMF.StaggerLoc.CORNER globalIndexing - if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None + if True array was allocated over global index space, + otherwise array was allocated over local index space + on this processor. This is only relevant if rootPe is None Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. @@ -366,9 +377,11 @@ def getCoords(self, dim, staggerloc): Parameters --------- - dim desired dimension (zero based indexing) + dim + desired dimension (zero based indexing) - staggerloc Stagger location + staggerloc + Stagger location """ gridPtr = self.grid.get_coords(coord_dim=dim, staggerloc=staggerloc) shp = self.getCoordShape(staggerloc) @@ -432,8 +445,9 @@ def setMask(self, mask, staggerloc=CENTER): Parameters ---------- - mask numpy array. 1 is invalid by default. This array exists - on all procs + mask numpy array. + 1 is invalid by default. This array exists + on all procs _: None """ @@ -470,11 +484,11 @@ def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): datatype data type, one of 'float64', 'float32', 'int64', or 'int32' - (or equivalent numpy dtype) + (or equivalent numpy dtype) staggerloc ESMF.StaggerLoc.CENTER - ESMF.StaggerLoc.CORNER + ESMF.StaggerLoc.CORNER """ # field object self.field = None @@ -535,9 +549,10 @@ def getData(self, rootPe): Parameters ---------- - rootPe if None then local data will be fetched, otherwise - gather the data on processor "rootPe" (all other - procs will return None). + rootPe + if None then local data will be fetched, otherwise + gather the data on processor "rootPe" (all other + procs will return None). _: None @@ -592,15 +607,17 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): Parameters ---------- - data full numpy array, this method will take care of setting a - the subset of the data that reside on the local processor - - staggerloc stagger location of the data + data + full numpy array, + this method will take care of setting a + the subset of the data that reside on the local processor + staggerloc + stagger location of the data - globalIndexing if True array was allocated over global index - space, array was allocated over local index - space (on this processor) + globalIndexing + if True array was allocated over global index space, + array was allocated over local index space (on this processor) """ ptr = self.field.data if globalIndexing: @@ -728,8 +745,9 @@ def getSrcAreas(self, rootPe): Parameters ---------- - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered + rootPe + None is local areas are returned, otherwise + provide rootPe and the data will be gathered _: None @@ -749,8 +767,9 @@ def getDstAreas(self, rootPe): Parameters ---------- - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered + rootPe + None is local areas are returned, otherwise + provide rootPe and the data will be gathered _: None @@ -770,8 +789,9 @@ def getSrcAreaFractions(self, rootPe): Parameters ---------- - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered + rootPe + None is local areas are returned, otherwise + provide rootPe and the data will be gathered _: None @@ -792,8 +812,9 @@ def getDstAreaFractions(self, rootPe): Parameters ---------- - rootPe None is local areas are returned, otherwise - provide rootPe and the data will be gathered + rootPe + None is local areas are returned, otherwise + provide rootPe and the data will be gathered _: None @@ -814,13 +835,17 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): Parameters ---------- - srcField source field (or None if src field passed to - constructor is to be used) + srcField + source field (or None if src field passed to + constructor is to be used) - dstField destination field (or None if dst field passed - to constructor is to be used) + dstField + destination field (or None if dst field passed + to constructor is to be used) - zero_region specify which region of the field indices will be zeroed (or None default to TOTAL Region) + zero_region + specify which region of the field indices will be zeroed + (or None default to TOTAL Region) """ if srcField is None: srcField = self.srcField From 3cf5491fd5d9355f1200f95f28393a54d211fe03 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 16:52:38 -0700 Subject: [PATCH 107/239] UVCDAT_ANONYMOUS_LOG set to false --- docs/source/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index e291694d..b9821291 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -30,6 +30,8 @@ sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) print os.path.join(sys.prefix,"lib","python2.7","site-packages") +os.environ['UVCDAT_ANONYMOUS_LOG']="False" + # -- General configuration ------------------------------------------------ From 443d7f5388c6c6380303d33acb235e9233b679a9 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 17:09:16 -0700 Subject: [PATCH 108/239] check if git.py is there --- docs/source/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index b9821291..bb98b14c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,6 +20,7 @@ import os import shlex import easydev +import glob html_theme_path = [easydev.get_path_sphinx_themes()] @@ -31,6 +32,9 @@ sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) print os.path.join(sys.prefix,"lib","python2.7","site-packages") os.environ['UVCDAT_ANONYMOUS_LOG']="False" +print glob.glob(os.path.join(sys.prefix,"lib","python2.7","site-packages")+"/regrid2/gi*") +print glob.glob(os.path.join(sys.prefix,"lib","python2.7","site-packages")+"/cdms2/gi*") + From 92fa468aea6a5e02f18306c13d64a1bcdad2cf60 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 17:26:54 -0700 Subject: [PATCH 109/239] add gcc to environment.yml --- docs/environment.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/environment.yml b/docs/environment.yml index aa21dce3..46bd2218 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -22,6 +22,7 @@ dependencies: - esmf=7.1.0r=0 - esmpy=7.1.0r=py27_1 - g2clib=1.6.0=5 +- gmp=6.1.2=0 - hdf4=4.2.13=0 - hdf5=1.10.1=2 - idna=2.6=py27_1 @@ -41,6 +42,8 @@ dependencies: - libtiff=4.0.9=0 - mkl_fft=1.0.2=py27_0 - mkl_random=1.0.1=py27_0 +- mpc=1.1.0=4 +- mpfr=3.1.5=0 - mpi=1.0=mpich - mpich=3.2.1=0 - ncurses=5.9=10 @@ -62,13 +65,31 @@ dependencies: - urllib3=1.22=py27_0 - xz=5.2.3=0 - zlib=1.2.11=0 +- alabaster=0.7.10=py27he5a193a_0 +- babel=2.5.3=py27_0 +- cloog=0.18.0=0 +- docutils=0.14=py27hae222c1_0 - future=0.16.0=py27_1 +- gcc=4.8.5=7 +- imagesize=1.0.0=py27_0 - intel-openmp=2018.0.0=8 +- isl=0.12.2=0 +- jinja2=2.10=py27h4114e70_0 - libgcc=7.2.0=h69d50b8_2 - libgcc-ng=7.2.0=hdf63c60_3 - libgfortran=3.0.0=1 - libgfortran-ng=7.2.0=hdf63c60_3 - libstdcxx-ng=7.2.0=hdf63c60_3 +- markupsafe=1.0=py27h97b2822_1 - mkl=2018.0.2=1 - numpy=1.14.2=py27hdbf6ddf_1 +- packaging=17.1=py27_0 +- pygments=2.2.0=py27h4a8b6f5_0 +- pyparsing=2.2.0=py27hf1513f8_1 +- pytz=2018.4=py27_0 +- snowballstemmer=1.2.1=py27h44e2768_0 +- sphinx=1.7.3=py27_0 +- sphinxcontrib=1.0=py27h1512b58_1 +- sphinxcontrib-websupport=1.0.1=py27hf906f22_1 +- typing=3.6.4=py27_0 prefix: /software/anaconda2/envs/rtdh From eeb77777e37eeb8f124ede72ed6b746598cc7b38 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 17:54:54 -0700 Subject: [PATCH 110/239] try docker environment.yml --- docs/environment.yml | 202 +++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 93 deletions(-) diff --git a/docs/environment.yml b/docs/environment.yml index 46bd2218..a687d9a7 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -1,95 +1,111 @@ -name: rtdh +name: readthedoctest channels: -- conda-forge -- defaults + - conda-forge + - defaults dependencies: -- asn1crypto=0.24.0=py27_0 -- ca-certificates=2018.4.16=0 -- cdat_info=8.0=py27_0 -- cdms2=3.0=py27_6 -- cdtime=3.0=py27_0 -- certifi=2018.4.16=py27_0 -- cffi=1.11.5=py27_0 -- chardet=3.0.4=py27_0 -- clapack=3.2.1=0 -- colorama=0.3.9=py27_0 -- colorlog=3.1.2=py27_0 -- cryptography=2.2.1=py27_0 -- curl=7.59.0=1 -- distarray=2.12.2=py27_0 -- easydev=0.9.36=py27_0 -- enum34=1.1.6=py27_1 -- esmf=7.1.0r=0 -- esmpy=7.1.0r=py27_1 -- g2clib=1.6.0=5 -- gmp=6.1.2=0 -- hdf4=4.2.13=0 -- hdf5=1.10.1=2 -- idna=2.6=py27_1 -- ipaddress=1.0.22=py_1 -- jasper=1.900.1=4 -- jpeg=9b=2 -- krb5=1.14.6=0 -- lapack=3.6.1=1 -- libcdms=3.0.1=0 -- libcf=1.0.1=py27_1 -- libdrs=3.0=0 -- libdrs_f=3.0=0 -- libffi=3.2.1=3 -- libnetcdf=4.4.1.1=10 -- libpng=1.6.34=0 -- libssh2=1.8.0=2 -- libtiff=4.0.9=0 -- mkl_fft=1.0.2=py27_0 -- mkl_random=1.0.1=py27_0 -- mpc=1.1.0=4 -- mpfr=3.1.5=0 -- mpi=1.0=mpich -- mpich=3.2.1=0 -- ncurses=5.9=10 -- netcdf-fortran=4.4.4=6 -- openssl=1.0.2o=0 -- ossuuid=1.6.2=0 -- pexpect=4.5.0=py27_0 -- ptyprocess=0.5.2=py27_0 -- pycparser=2.18=py27_0 -- pyopenssl=17.5.0=py27_1 -- pysocks=1.6.8=py27_1 -- python=2.7.14=5 -- readline=7.0=0 -- requests=2.18.4=py27_1 -- setuptools=39.0.1=py27_0 -- six=1.11.0=py27_1 -- sqlite=3.20.1=2 -- tk=8.6.7=0 -- urllib3=1.22=py27_0 -- xz=5.2.3=0 -- zlib=1.2.11=0 -- alabaster=0.7.10=py27he5a193a_0 -- babel=2.5.3=py27_0 -- cloog=0.18.0=0 -- docutils=0.14=py27hae222c1_0 -- future=0.16.0=py27_1 -- gcc=4.8.5=7 -- imagesize=1.0.0=py27_0 -- intel-openmp=2018.0.0=8 -- isl=0.12.2=0 -- jinja2=2.10=py27h4114e70_0 -- libgcc=7.2.0=h69d50b8_2 -- libgcc-ng=7.2.0=hdf63c60_3 -- libgfortran=3.0.0=1 -- libgfortran-ng=7.2.0=hdf63c60_3 -- libstdcxx-ng=7.2.0=hdf63c60_3 -- markupsafe=1.0=py27h97b2822_1 -- mkl=2018.0.2=1 -- numpy=1.14.2=py27hdbf6ddf_1 -- packaging=17.1=py27_0 -- pygments=2.2.0=py27h4a8b6f5_0 -- pyparsing=2.2.0=py27hf1513f8_1 -- pytz=2018.4=py27_0 -- snowballstemmer=1.2.1=py27h44e2768_0 -- sphinx=1.7.3=py27_0 -- sphinxcontrib=1.0=py27h1512b58_1 -- sphinxcontrib-websupport=1.0.1=py27hf906f22_1 -- typing=3.6.4=py27_0 -prefix: /software/anaconda2/envs/rtdh + - asn1crypto=0.24.0=py27_0 + - ca-certificates=2018.4.16=0 + - cdat_info=8.0=py27_0 + - cdms2=3.0=py27_6 + - cdtime=3.0=py27_0 + - certifi=2018.4.16=py27_0 + - cffi=1.11.5=py27_0 + - chardet=3.0.4=py27_0 + - clapack=3.2.1=0 + - colorama=0.3.9=py27_0 + - colorlog=3.1.2=py27_0 + - cryptography=2.2.1=py27_0 + - curl=7.59.0=1 + - distarray=2.12.2=py27_0 + - easydev=0.9.36=py27_0 + - enum34=1.1.6=py27_1 + - esmf=7.1.0r=0 + - esmpy=7.1.0r=py27_1 + - g2clib=1.6.0=5 + - gmp=6.1.2=0 + - hdf4=4.2.13=0 + - hdf5=1.10.1=2 + - idna=2.6=py27_1 + - ipaddress=1.0.22=py_1 + - jasper=1.900.1=4 + - jpeg=9b=2 + - krb5=1.14.6=0 + - lapack=3.6.1=1 + - libcdms=3.0.1=0 + - libcf=1.0.1=py27_1 + - libdrs=3.0=0 + - libdrs_f=3.0=0 + - libffi=3.2.1=3 + - libnetcdf=4.4.1.1=10 + - libpng=1.6.34=0 + - libssh2=1.8.0=2 + - libtiff=4.0.9=0 + - mkl_fft=1.0.2=py27_0 + - mkl_random=1.0.1=py27_0 + - mpc=1.1.0=4 + - mpfr=3.1.5=0 + - mpi=1.0=mpich + - mpich=3.2.1=0 + - ncurses=5.9=10 + - netcdf-fortran=4.4.4=6 + - openssl=1.0.2o=0 + - ossuuid=1.6.2=0 + - pexpect=4.5.0=py27_0 + - pip=9.0.3=py27_0 + - ptyprocess=0.5.2=py27_0 + - pycparser=2.18=py27_0 + - pyopenssl=17.5.0=py27_1 + - pysocks=1.6.8=py27_1 + - python=2.7.14=5 + - readline=7.0=0 + - requests=2.18.4=py27_1 + - setuptools=39.0.1=py27_0 + - six=1.11.0=py27_1 + - sqlite=3.20.1=2 + - tk=8.6.7=0 + - urllib3=1.22=py27_0 + - wheel=0.31.0=py27_0 + - xz=5.2.3=0 + - zlib=1.2.11=0 + - alabaster=0.7.10=py27he5a193a_0 + - babel=2.5.3=py27_0 + - cloog=0.18.0=0 + - docutils=0.14=py27hae222c1_0 + - freetype=2.8=hab7d2ae_1 + - funcsigs=1.0.2=py27h83f16ab_0 + - future=0.16.0=py27_1 + - gcc=4.8.5=7 + - imagesize=1.0.0=py27_0 + - intel-openmp=2018.0.0=8 + - isl=0.12.2=0 + - jinja2=2.10=py27h4114e70_0 + - libgcc=7.2.0=h69d50b8_2 + - libgcc-ng=7.2.0=hdf63c60_3 + - libgfortran=3.0.0=1 + - libgfortran-ng=7.2.0=hdf63c60_3 + - libstdcxx-ng=7.2.0=hdf63c60_3 + - markupsafe=1.0=py27h97b2822_1 + - mkl=2018.0.2=1 + - mock=2.0.0=py27h0c0c831_0 + - numpy=1.14.2=py27hdbf6ddf_1 + - olefile=0.45.1=py27_0 + - packaging=17.1=py27_0 + - pbr=4.0.2=py27_0 + - pillow=5.1.0=py27h3deb7b8_0 + - pygments=2.2.0=py27h4a8b6f5_0 + - pyparsing=2.2.0=py27hf1513f8_1 + - pytz=2018.4=py27_0 + - snowballstemmer=1.2.1=py27h44e2768_0 + - sphinx=1.7.3=py27_0 + - sphinx_rtd_theme=0.3.0=py27_0 + - sphinxcontrib=1.0=py27h1512b58_1 + - sphinxcontrib-websupport=1.0.1=py27hf906f22_1 + - typing=3.6.4=py27_0 + - pip: + - commonmark==0.5.4 + - mv2==3.0.0 + - nilsimsa==0.3.8 + - readthedocs-sphinx-ext==0.5.10 + - recommonmark==0.4.0 + - regrid2==3.0.0 +prefix: /home/docs/.conda/envs/readthedoctest From 3cac37be2af632789f3b95d47842cdd2b121e924 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 18:11:28 -0700 Subject: [PATCH 111/239] remove git.py --- Lib/__init__.py | 1 - regrid2/Lib/__init__.py | 2 -- setup.py | 40 ++++++++++++++++++++-------------------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Lib/__init__.py b/Lib/__init__.py index 23c2a595..90ca0096 100644 --- a/Lib/__init__.py +++ b/Lib/__init__.py @@ -4,7 +4,6 @@ import cdat_info cdat_info.pingPCMDIdb("cdat", "cdms2") # noqa -from . import git # noqa from . import myproxy_logon # noqa __all__ = ["cdmsobj", "axis", "coord", "grid", "hgrid", "avariable", diff --git a/regrid2/Lib/__init__.py b/regrid2/Lib/__init__.py index 36b7f9e2..3b3269f9 100644 --- a/regrid2/Lib/__init__.py +++ b/regrid2/Lib/__init__.py @@ -21,8 +21,6 @@ except BaseException: pass -from . import git # noqa - ESMF_HAS_BEEN_INITIALIZED = False if not ESMF_HAS_BEEN_INITIALIZED: try: diff --git a/setup.py b/setup.py index 1fa1e432..3c454cf7 100644 --- a/setup.py +++ b/setup.py @@ -22,27 +22,27 @@ PATCH = 0 Version = "%s.%s.%s" % (MAJOR,MINOR,PATCH) -f=open("git.py","w") -git_branch=subprocess.Popen(["git","rev-parse","--abbrev-ref","HEAD"],stdout=subprocess.PIPE).stdout.read().strip().decode("utf-8") -print("branch = '%s'" % git_branch, file=f) -git_tag = subprocess.Popen(["git","describe","--tags"],stdout=subprocess.PIPE).stdout.read().strip().decode("utf-8") -sp=git_tag.split("-") -if len(sp)>2: - commit = sp[-1] - nm = "-".join(sp[:-2]) - diff=sp[-2] -else: - commit = git_tag - nm = git_tag - diff=0 -print("closest_tag = '%s'" % nm, file=f) -print("commit = '%s'" % commit, file=f) -print("diff_from_tag = %s" % diff, file=f) -print("version = '%s'" % Version, file=f) -f.close() +#f=open("git.py","w") +#git_branch=subprocess.Popen(["git","rev-parse","--abbrev-ref","HEAD"],stdout=subprocess.PIPE).stdout.read().strip().decode("utf-8") +#print("branch = '%s'" % git_branch, file=f) +#git_tag = subprocess.Popen(["git","describe","--tags"],stdout=subprocess.PIPE).stdout.read().strip().decode("utf-8") +#sp=git_tag.split("-") +#if len(sp)>2: +# commit = sp[-1] +# nm = "-".join(sp[:-2]) +# diff=sp[-2] +#else: +# commit = git_tag +# nm = git_tag +# diff=0 +#print("closest_tag = '%s'" % nm, file=f) +#print("commit = '%s'" % commit, file=f) +#print("diff_from_tag = %s" % diff, file=f) +#print("version = '%s'" % Version, file=f) +#f.close() -shutil.copy("git.py",os.path.join("Lib","git.py")) -shutil.copy("git.py",os.path.join("regrid2","Lib","git.py")) +#shutil.copy("git.py",os.path.join("Lib","git.py")) +#shutil.copy("git.py",os.path.join("regrid2","Lib","git.py")) import cdat_info import numpy From 8952fb18e6f0ce32845cfb55ad8f5bf193a429fe Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 18:22:51 -0700 Subject: [PATCH 112/239] chage Libregrid to regrid2 --- docs/source/API.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index 15787d00..b5ec7f4d 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -53,7 +53,7 @@ Classes -.. currentmodule:: Libregrid +.. currentmodule:: regrid2 Regridder --------- From 8ae28f7206dd216a215588f4cba1e3f76b19d6b2 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 18:29:03 -0700 Subject: [PATCH 113/239] revert --- docs/source/API.rst | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index b5ec7f4d..d5df5c61 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -37,24 +37,6 @@ Classes slabinterface - - - - - - - - - - - - - - - - -.. currentmodule:: regrid2 - Regridder --------- .. autosummary:: From 0c6e8099c70b8219f6b67699754e407d67279e12 Mon Sep 17 00:00:00 2001 From: Denis Nadeau Date: Tue, 24 Apr 2018 18:29:31 -0700 Subject: [PATCH 114/239] revert --- docs/source/API.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index d5df5c61..cb844848 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -40,7 +40,7 @@ Classes Regridder --------- .. autosummary:: - horizontal + regrid2.horizontal esmf crossSection gsRegrid From 2d129520e557b3e2828084621dd84dd60a3ebcd5 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 24 Apr 2018 21:02:14 -0700 Subject: [PATCH 115/239] add cdms2 class --- docs/source/API.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index cb844848..7044e241 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -5,7 +5,7 @@ API Classes ------- .. autosummary:: - avariable + cdms2.avariable axis fvariable bindex From ad9828893f2517f5efed5dbd94df0721d94a4508 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 24 Apr 2018 21:13:17 -0700 Subject: [PATCH 116/239] delet cdms2 class --- docs/source/API.rst | 2 +- docs/source/avariable.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index 7044e241..cb844848 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -5,7 +5,7 @@ API Classes ------- .. autosummary:: - cdms2.avariable + avariable axis fvariable bindex diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index 0d8a099b..8db7df8b 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -1,7 +1,7 @@ avariable ========= -.. automodule:: cdms2.avariable +.. automodule:: avariable :members: From 7c311f2446aa1812e936f7dc6587b6ba11d8981b Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 24 Apr 2018 21:22:12 -0700 Subject: [PATCH 117/239] delet cdms2 class --- docs/source/API.rst | 1 + docs/source/avariable.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/API.rst b/docs/source/API.rst index cb844848..6dba3b29 100644 --- a/docs/source/API.rst +++ b/docs/source/API.rst @@ -1,5 +1,6 @@ API === + .. currentmodule:: cdms2 Classes diff --git a/docs/source/avariable.rst b/docs/source/avariable.rst index 8db7df8b..0d8a099b 100644 --- a/docs/source/avariable.rst +++ b/docs/source/avariable.rst @@ -1,7 +1,7 @@ avariable ========= -.. automodule:: avariable +.. automodule:: cdms2.avariable :members: From 0b340e59fed4b200bdd1c47d403e180b49aad2c9 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 24 Apr 2018 21:39:39 -0700 Subject: [PATCH 118/239] change conf.py os.path --- docs/source/conf.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index bb98b14c..dbcb25aa 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,11 +29,8 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages")) -sys.path.insert(0,os.path.join(sys.prefix,"lib","python2.7","site-packages","cdms2")) print os.path.join(sys.prefix,"lib","python2.7","site-packages") os.environ['UVCDAT_ANONYMOUS_LOG']="False" -print glob.glob(os.path.join(sys.prefix,"lib","python2.7","site-packages")+"/regrid2/gi*") -print glob.glob(os.path.join(sys.prefix,"lib","python2.7","site-packages")+"/cdms2/gi*") From 67cf58480129f9a8d12ae7041a11f5c3138078b1 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 26 Apr 2018 15:39:12 -0700 Subject: [PATCH 119/239] Changes to API --- Lib/cdurlparse.py | 5 +- Lib/cudsinterface.py | 277 ++++++++++++++++++++++++++----------------- Lib/database.py | 97 ++++++++------- regrid2/Lib/esmf.py | 29 +++-- 4 files changed, 239 insertions(+), 169 deletions(-) diff --git a/Lib/cdurlparse.py b/Lib/cdurlparse.py index 6f6ac6f7..7ac727ee 100644 --- a/Lib/cdurlparse.py +++ b/Lib/cdurlparse.py @@ -188,9 +188,8 @@ def urldefrag(url): Returns ------- - a tuple of the defragmented URL and the fragment. If - the URL contained no fragments, the second element is the - empty string. + a tuple of the defragmented URL and the fragment. + If the URL contained no fragments, the second element is the empty string. """ s, n, p, a, q, frag = urlparse(url) defrag = urlunparse((s, n, p, a, q, '')) diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index cff27151..5cedd90e 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -63,11 +63,15 @@ def cleardefault(self): def listall(self, vname=None, all=None): """Get info about data from the file. - ::: - Options::: - vname :: (str/None) (None) variable name - all :: (None/True/False/int) (None) include axes information - ::: + + Options + + vname + (str/None) (None) variable name + + all + (None/True/False/int) (None) include axes information + """ if vname is None: vname = self.default_variable_name @@ -103,10 +107,12 @@ def listall(self, vname=None, all=None): def listattribute(self, vname=None): """Get attributes of data from the file. - ::: - Options::: - vname :: (str/None) (None) variable name - ::: + + Options + + vname + (str/None) (None) variable name + """ if vname is None: vname = self.default_variable_name @@ -122,10 +128,12 @@ def listdimension(self, vname=None): a list of the dimension names associated with a variable. If no argument, return the file.axes.keys() - ::: - Options::: - vname :: (str/None) (None) variable name - ::: + + Options + + vname + (str/None) (None) variable name + """ if vname is None: return list(self.axes.keys()) @@ -143,7 +151,7 @@ def listglobal(self): a list of the global attributes in the file. _None_ - ::: + """ return list(self.attributes.keys()) @@ -157,7 +165,7 @@ def listvariable(self): _None_ - ::: + """ return list(self.variables.keys()) @@ -165,10 +173,12 @@ def listvariable(self): def showglobal(self, device=None): """Show the global attributes in the file. - ::: - Options::: - device :: (None/file) (None) output device - ::: + + Options + + device + (None/file) (None) output device + """ if device is None: device = sys.stdout @@ -180,10 +190,13 @@ def showglobal(self, device=None): def showvariable(self, device=None): """Show the variables in the file. - ::: - Options::: - device :: (None/file) (None) output device - ::: + + Options + + + device + (None/file) (None) output device + """ if device is None: device = sys.stdout @@ -195,11 +208,14 @@ def showvariable(self, device=None): def showattribute(self, vname=None, device=None): """Show the attributes of vname. - ::: - Options::: - vname :: (str/None) (None) variable name - device :: (None/file) (None) output device - ::: + + Options + + vname + (str/None) (None) variable name + device + (None/file) (None) output device + """ if device is None: device = sys.stdout @@ -215,11 +231,15 @@ def showattribute(self, vname=None, device=None): def showdimension(self, vname=None, device=None): """Show the dimension names associated with a variable. - ::: - Options::: - vname :: (str/None) (None) variable name - device :: (None/file) (None) output device - ::: + + Options + + vname + (str/None) (None) variable name + + device + (None/file) (None) output device + """ if device is None: device = sys.stdout @@ -235,12 +255,16 @@ def showdimension(self, vname=None, device=None): def showall(self, vname=None, all=None, device=None): """Show a full description of the variable. - ::: - Options::: - vname :: (str/None) (None) variable name - all :: (None/True/False/int) (None) include axes information - device :: (None/file) (None) output device - ::: + + Options + + vname + (str/None) (None) variable name + all + (None/True/False/int) (None) include axes information + device + (None/file) (None) output device + """ if device is None: device = sys.stdout @@ -252,16 +276,20 @@ def showall(self, vname=None, all=None, device=None): def dimensionobject(self, dname, vname=None): """CDMS axis object for the dimension named dname. - ::: - Options::: - vname :: (str/None) (None) variable name - ::: - Input::: - dname :: (str) (0) dimension name - ::: - Output::: - axis :: (cdms2.axis.FileAxis) (0) file axis whose id is vname - ::: + + Options + + vname + (str/None) (None) variable name + + Input + dname + (str) (0) dimension name + + Output + axis + (cdms2.axis.FileAxis) (0) file axis whose id is vname + """ if vname is None: try: @@ -281,44 +309,53 @@ def dimensionobject(self, dname, vname=None): def dimensionarray(self, dname, vname=None): """Values of the dimension named dname. - ::: - Options::: - vname :: (str/None) (None) variable name - ::: - Input::: - dname :: (str) (0) dimension name - ::: - Output::: - axisvalues :: (numpy.ndarray) (0) array with values of axis whose id is vname - ::: - """ + + Options + + vname + (str/None) (None) variable name + + Input + dname + (str) (0) dimension name + + Output + axisvalues + (numpy.ndarray) (0) array with values of axis whose id is vname + """ return self.dimensionobject(dname, vname).getValue() def getdimensionunits(self, dname, vname=None): """Get the units for the given dimension. - ::: - Options::: - vname :: (str/None) (None) variable name - ::: - Input::: - dname :: (str) (0) dimension name - ::: - Output::: - units :: (str) (0) units of axis whose id is vname - ::: + + Options + + vname + (str/None) (None) variable name + + Input + dname + (str) (0) dimension name + + Output + units + (str) (0) units of axis whose id is vname + """ x = self.dimensionobject(dname, vname) return x.units def getglobal(self, attribute): """Get the value of the global attribute. - ::: - Input::: - attribute :: (str) (0) global attribute name - ::: - Output::: - attribute_value :: (str/int/float/numpy.ndarray) (0) value of requested global attribute - ::: + + Input + attribute + (str) (0) global attribute name + + Output + attribute_value + (str/int/float/numpy.ndarray) (0) value of requested global attribute + """ try: return self.attributes[attribute] @@ -327,14 +364,18 @@ def getglobal(self, attribute): def getattribute(self, vname, attribute): """Get the value of attribute for variable vname - ::: - Input::: - vname :: (str/None) (0) variable name - attribute :: (str) (1) attribute name - ::: - Output::: - attribute_value :: (str/int/float/numpy.ndarray) (0) value of requested attribute - ::: + + Input + vname + (str/None) (0) variable name + + attribute + (str) (1) attribute name + + Output + attribute_value + (str/int/float/numpy.ndarray) (0) value of requested attribute + """ v = self._v(vname) return getattr(v, attribute) @@ -349,24 +390,35 @@ def getslab(self, vname, *args, **keys): (3) a pair of successive arguments giving an interval in world coordinates. (4) a cdms-style tuple of world coordinates e.g. (start, stop, 'cc') - ::: - Options::: - args :: (*tuple/*cdms2.selectors.Selector) () tuple of type (val1,val2,'cob') + + Options + + args + (*tuple/*cdms2.selectors.Selector) () tuple of type (val1,val2,'cob') for any given dimension or cdms selector - ::: - Keys::: - squeeze :: (int/True/False) (0) squeezes (removes) dimensions of length 1 - order :: (str) ('...') reorder the dimensions, can use numbers or xyzt or dim - names in between paranthesis - raw :: (int/True/False) (0) return a numpy.ma instead of a transient variable - grid :: (cdms2.grid.AbstractGrid) (None) regrid the result to the grid passed - ::: - Input::: - vname :: (str/None) (0) variable name - ::: - Output::: - variable :: (cdms2.tvariable.TransientVariable) (0) variable requested - ::: + + Keys + squeeze + (int/True/False) (0) squeezes (removes) dimensions of length 1 + + order + (str) ('...') reorder the dimensions, can use numbers or xyzt or dim + names in between paranthesis + + raw + (int/True/False) (0) return a numpy.ma instead of a transient variable + + grid + (cdms2.grid.AbstractGrid) (None) regrid the result to the grid passed + + Input + vname + (str/None) (0) variable name + + Output + variable + (cdms2.tvariable.TransientVariable) (0) variable requested + """ nargs = len(args) v = self._v(vname) @@ -418,14 +470,19 @@ def readScripGrid(self, whichGrid="destination", checkGrid=1): If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Returns the grid object. - ::: - Options::: - whichGrid :: (str) ('destination') grid to read - checkGrid (int) (1) if 1 the grid cells are checked for convexity - ::: - Output::: - grid :: (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested - ::: + + Options + + whichGrid + (str) ('destination') grid to read + + checkGrid + (int) (1) if 1 the grid cells are checked for convexity + + Output + grid + (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested + """ from . import hgrid, gengrid diff --git a/Lib/database.py b/Lib/database.py index cc65895e..ff6163e4 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -195,12 +195,13 @@ def __init__(self, uri, db): def close(self): """ Method - ------ - close() + + close() Description - ----------- - Close a database connection. + + + Close a database connection. Returns ------- @@ -275,15 +276,15 @@ def getObjFromDataset(self, dn): def openDataset(self, dsetid, mode='r'): """ Method - ------ + openDataset(dsetid, mode='r') Description - ----------- + Open a dataset. Arguments - --------- + dsetid: string dataset identifier mode: open mode ('r' - read-only, 'r+' - read-write, 'w' - create) @@ -327,43 +328,54 @@ def searchFilter(self, filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None): """ Method - ------ + searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) Description - ----------- + Search a CDMS database. - Arguments - --------- - filter: string search filter + Arguments - + + filter: string search filter Simple filters have the form "tag = value". Simple filters can be combined using logical operators '&', '|', '!' in prefix notation. For example, the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. More formally - ------------- - filter ::= "(" filtercomp ")" - filtercomp ::= "&" filterlist | # and + + filter = "(" filtercomp ")" + + filtercomp = "&" filterlist | # and "|" filterlist | # or "!" filterlist | # not simple - filterlist ::= filter | filter filterlist - simple ::= tag op value - op ::= "=" | # equality + + filterlist = filter | filter filterlist + + simple = tag op value + + op = "=" | # equality "~=" | # approximate equality "<=" | # lexicographically less than or equal to ">=" # lexicographically greater than or equal to - value ::= string, may include '*' as a wild card - tag: string class tag ("dataset" | "variable" | "database" | "axis" | "grid"). - Restricts the search to a class of objects - relbase: string search base, relative to the database path - scope: search scope (Subtree | Onelevel | Base). Subtree searches the base object and its descendants. - Onelevel searches the base object and its immediate descendants. Base searches the base object alone. + value = string, may include '*' as a wild card + + tag: string class tag ("dataset" | "variable" | "database" | "axis" | "grid"). + Restricts the search to a class of objects + + relbase: string search base, relative to the database path + scope: search scope (Subtree | Onelevel | Base). Subtree searches the base object and its descendants. + + Onelevel searches the base object and its immediate descendants. Base searches the base object alone. Default is Subtree. - attnames: list of attribute names. Restricts the attributes returned. - timeout: integer number of seconds before timeout. + + attnames: + list of attribute names. Restricts the attributes returned. + + timeout: + integer number of seconds before timeout. Returns ------- @@ -372,7 +384,7 @@ def searchFilter(self, filter=None, tag=None, relbase=None, entry.getObject() returns the CDMS object associated with the entry: for entry in result: - print entry.name, entry.attributes["id"] + print entry.name, entry.attributes["id"] Entries can be refined with searchPredicate(). @@ -465,36 +477,35 @@ def __getitem__(self, key): def searchPredicate(self, predicate, tag=None): """ Method - ------ - searchPredicate(predicate, tag=None) + + searchPredicate(predicate, tag=None) Description - ----------- - Refine a search result, with a predicate search. + + Refine a search result, with a predicate search. Arguments - --------- - predicate: Function name or lambda function. The function takes a single CDMS object, + + predicate: Function name or lambda function. The function takes a single CDMS object, and returns true (1) if the object satisfies the predicate, 0 if not. - tag: Restrict the search to objects in one class. + tag: Restrict the search to objects in one class. Returns ------- - SearchResult instance. Entries can be accessed sequentially. For each entry, entry.name is the - name of the entry, entry.attributes is a dictionary of the attributes returned by the search, - entry.getObject() returns the CDMS object associated with the entry: + SearchResult instance. Entries can be accessed sequentially. For each entry, entry.name is the + name of the entry, entry.attributes is a dictionary of the attributes returned by the search, + entry.getObject() returns the CDMS object associated with the entry: - for entry in result: - print entry.name, entry.attributes["id"] + for entry in result: + print entry.name, entry.attributes["id"] - Entries can be refined with searchPredicate(). + Entries can be refined with searchPredicate(). Example ------- - (1) Find all variables on a 73x96 grid - - newresult = result.searchPredicate(lambda obj: obj.getGrid().shape==(73,96),"variable") + (1) Find all variables on a 73x96 grid + newresult = result.searchPredicate(lambda obj: obj.getGrid().shape==(73,96),"variable") """ if tag is not None: tag = string.lower(tag) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 242fa033..2769619b 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -94,24 +94,27 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- - 3 - / \ - / \ - / \ - / \ - / \ - 1 --------- 2 + 3 + /-------------------\ + /----------------------\ + /------------------------\ + /--------------------------\ + /----------------------------\ + 1 ------------------------------------- 2 4------------3 - | | - | | - | | - | | - | | - 1 ---------- 2 + + | + | + | + | + | + + 1------------2 + From 401b6cb5e885207c8252850810dee3596176d26b Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 30 Apr 2018 11:55:01 -0700 Subject: [PATCH 120/239] Changes made to API --- regrid2/Lib/mvESMFRegrid.py | 47 +++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 1c4dd350..7d796711 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -47,18 +47,41 @@ def __init__(self, srcGridshape, dstGridshape, dtype, **args): """ Constructor - @param srcGridShape tuple source grid shape - @param dstGridShape tuple destination grid shape - @param dtype a valid numpy data type for the src/dst data - @param regridMethod 'linear', 'conserve', or 'patch' - @param staggerLoc the staggering of the field, 'center' or 'corner' - @param periodicity 0 (no periodicity), - 1 (last coordinate is periodic, - 2 (both coordinates are periodic) - @param coordSys 'deg', 'cart', or 'rad' - @param hasSrcBounds tuple source bounds shape - @param hasDstBounds tuple destination bounds shape - @param ignoreDegenerate Ignore degenerate celss when checking inputs + + Parameters + ---------- + + srcGridShape + tuple source grid shape + + dstGridShape + tuple destination grid shape + + dtype + a valid numpy data type for the src/dst data + + regridMethod + 'linear', 'conserve', or 'patch' + + staggerLoc + the staggering of the field, 'center' or 'corner' + + periodicity + 0 (no periodicity), + 1 (last coordinate is periodic, + 2 (both coordinates are periodic) + + coordSys + 'deg', 'cart', or 'rad' + + hasSrcBounds + tuple source bounds shape + + hasDstBounds + tuple destination bounds shape + + + ignoreDegenerate Ignore degenerate celss when checking inputs """ # esmf grid objects (tobe constructed) From 49c6890793441c24b9b21aafeb5d00b4288f7e8f Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 30 Apr 2018 15:45:05 -0700 Subject: [PATCH 121/239] Changes to API --- regrid2/Lib/mvESMFRegrid.py | 246 ++++++++++++++++++++++++++---------- 1 file changed, 177 insertions(+), 69 deletions(-) diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 7d796711..f67352f9 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -53,34 +53,24 @@ def __init__(self, srcGridshape, dstGridshape, dtype, srcGridShape tuple source grid shape - dstGridShape tuple destination grid shape - dtype a valid numpy data type for the src/dst data - regridMethod 'linear', 'conserve', or 'patch' - staggerLoc the staggering of the field, 'center' or 'corner' - periodicity 0 (no periodicity), 1 (last coordinate is periodic, 2 (both coordinates are periodic) - coordSys 'deg', 'cart', or 'rad' - hasSrcBounds tuple source bounds shape - hasDstBounds tuple destination bounds shape - - ignoreDegenerate Ignore degenerate celss when checking inputs """ @@ -219,18 +209,30 @@ def setCoords(self, srcGrid, dstGrid, globalIndexing=False, **args): """ Populator of grids, bounds and masks - @param srcGrid list [[z], y, x] of source grid arrays - @param dstGrid list [[z], y, x] of dstination grid arrays - @param srcGridMask list [[z], y, x] of arrays - @param srcBounds list [[z], y, x] of arrays - @param srcGridAreas list [[z], y, x] of arrays - @param dstGridMask list [[z], y, x] of arrays - @param dstBounds list [[z], y, x] of arrays - @param dstGridAreas list [[z], y, x] of arrays - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None + + Parameters + ---------- + + srcGrid + list [[z], y, x] of source grid arrays + dstGrid + list [[z], y, x] of dstination grid arrays + srcGridMask + list [[z], y, x] of arrays + srcBounds + list [[z], y, x] of arrays + srcGridAreas + list [[z], y, x] of arrays + dstGridMask + list [[z], y, x] of arrays + dstBounds + list [[z], y, x] of arrays + dstGridAreas + list [[z], y, x] of arrays + globalIndexing + if True array was allocated over global index space, + otherwise array was allocated over local index space on + this processor. This is only relevant if rootPe is None """ # create esmf source Grid @@ -283,7 +285,13 @@ def setCoords(self, srcGrid, dstGrid, def computeWeights(self, **args): """ Compute interpolation weights - @param **args (not used) + + Parameters + ---------- + + **args (not used) + + _: None """ self.regridObj = ESMF.Regrid(srcfield=self.srcFld.field, dstfield=self.dstFld.field, @@ -309,17 +317,19 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): . By default, only the data are masked, but not the grid. - @param srcData array source data, shape should - cover entire global index space - @param dstData array destination data, shape should - cover entire global index space - @param rootPe if other than None, then data will be MPI gathered - on the specified rootPe processor - @param globalIndexing if True array was allocated over global index - space, otherwise array was allocated over - local index space on this processor. This - is only relevant if rootPe is None - @param **args + Parameters + ---------- + + srcData + array source data, shape should cover entire global index space + dstData + array destination data, shape should cover entire global index space + rootPe + if other than None, then data will be MPI gathered on the specified rootPe processor + globalIndexing + if True array was allocated over global index space, otherwise array was allocated + over local index space on this processor. This is only relevant if rootPe is None + **args """ # if args.has_key('srcDataMask'): @@ -357,7 +367,10 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): def getDstGrid(self): """ Get the destination grid on this processor - @return grid + + Returns + ------- + grid """ return [self.dstGrid.getCoords(i, staggerloc=self.staggerloc) for i in range(self.ndims)] @@ -365,9 +378,20 @@ def getDstGrid(self): def getSrcAreas(self, rootPe): """ Get the source grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation + + Parameters + ---------- + rootPe + root processor where data should be gathered (or None if local areas + are to be returned) + + _: None + + Returns + ------- + + areas + or None if non-conservative interpolation """ if self.regridMethod == CONSERVE: # self.srcAreaField.field.get_area() @@ -378,9 +402,21 @@ def getSrcAreas(self, rootPe): def getDstAreas(self, rootPe): """ Get the destination grid cell areas - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return areas or None if non-conservative interpolation + + Parameters + ---------- + + rootPe + root processor where data should be gathered (or None + if local areas are to be returned) + + _: None + + + Returns + ------- + + areas or None if non-conservative interpolation """ if self.regridMethod == CONSERVE: # self.dstAreaField.field.get_area() @@ -390,10 +426,22 @@ def getDstAreas(self, rootPe): def getSrcAreaFractions(self, rootPe): """ - Get the source grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) + Get the source grid area fractions + + Parameters + ---------- + + rootPe + root processor where data should be gathered (or None if local + areas are to be returned) + + _: None + + + Returns + ------- + + fractional areas or None (if non-conservative) """ if self.regridMethod == CONSERVE: return self.srcFracField.field.data @@ -403,9 +451,21 @@ def getSrcAreaFractions(self, rootPe): def getDstAreaFractions(self, rootPe): """ Get the destination grid area fractions - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) - @return fractional areas or None (if non-conservative) + + Parameters + ---------- + + rootPe + root processor where data should be gathered (or None if local + areas are to be returned) + + _: None + + Returns + ------- + + fractional areas + or None (if non-conservative) """ if self.regridMethod == CONSERVE: return self.dstFracField.field.data @@ -414,10 +474,20 @@ def getDstAreaFractions(self, rootPe): def getSrcLocalShape(self, staggerLoc): """ - Get the local source coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple + Get the local source coordinate/data shape (may be different on each processor) + + Parameters + ---------- + + staggerLoc + (e.g. 'center' or 'corner') + + _: None + + Returns + ------- + + tuple """ stgloc = CENTER if re.match('corner', staggerLoc, re.I) or \ @@ -430,10 +500,20 @@ def getSrcLocalShape(self, staggerLoc): def getDstLocalShape(self, staggerLoc): """ - Get the local destination coordinate/data shape - (may be different on each processor) - @param staggerLoc (e.g. 'center' or 'corner') - @return tuple + Get the local destination coordinate/data shape (may be different on each processor) + + Parameters + ---------- + + staggerLoc + (e.g. 'center' or 'corner') + + _: None + + Returns + ------- + + tuple """ stgloc = CENTER if re.match('corner', staggerLoc, re.I) or \ @@ -446,10 +526,21 @@ def getDstLocalShape(self, staggerLoc): def getSrcLocalSlab(self, staggerLoc): """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center'): - @return tuple of slices + Get the destination local slab (ellipsis). You can use this to grab the data + local to this processor + + Parameters + ---------- + + staggerLoc + (e.g. 'center'): + + _: None + + Returns + ------- + + tuple of slices """ stgloc = CENTER if re.match('corner', staggerLoc, re.I) or \ @@ -462,10 +553,21 @@ def getSrcLocalSlab(self, staggerLoc): def getDstLocalSlab(self, staggerLoc): """ - Get the destination local slab (ellipsis). You can use - this to grab the data local to this processor - @param staggerLoc (e.g. 'center') - @return tuple of slices + Get the destination local slab (ellipsis). You can use this to grab the data local to this + processor + + Parameters + ---------- + + staggerLoc + (e.g. 'center') + + _: None + + Returns + ------- + + tuple of slices """ stgloc = CENTER if re.match('corner', staggerLoc, re.I) or \ @@ -479,11 +581,17 @@ def getDstLocalSlab(self, staggerLoc): def fillInDiagnosticData(self, diag, rootPe): """ Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'srcAreaFractions', 'dstAreaFractions', - 'srcAreas', 'dstAreas' - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) + + Parameters + ---------- + + diag + a dictionary whose entries, if present, will be filled valid entries + are: 'srcAreaFractions', 'dstAreaFractions', srcAreas', 'dstAreas' + + rootPe + root processor where data should be gathered (or None if local areas are + to be returned) """ oldMethods = {} oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' From 297d386dd0764e134977d8a14b727458a212900c Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 1 May 2018 15:44:34 -0700 Subject: [PATCH 122/239] Changes made to API --- regrid2/Lib/mvESMFRegrid.py | 18 +++--- regrid2/Lib/mvGenericRegrid.py | 100 ++++++++++++++++++++++++--------- regrid2/Lib/mvLibCFRegrid.py | 60 +++++++++++++++----- 3 files changed, 126 insertions(+), 52 deletions(-) diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index f67352f9..7bfed601 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -47,15 +47,15 @@ def __init__(self, srcGridshape, dstGridshape, dtype, **args): """ Constructor - + Parameters ---------- - srcGridShape + srcGridShape tuple source grid shape - dstGridShape + dstGridShape tuple destination grid shape - dtype + dtype a valid numpy data type for the src/dst data regridMethod 'linear', 'conserve', or 'patch' @@ -426,8 +426,8 @@ def getDstAreas(self, rootPe): def getSrcAreaFractions(self, rootPe): """ - Get the source grid area fractions - + Get the source grid area fractions + Parameters ---------- @@ -454,10 +454,10 @@ def getDstAreaFractions(self, rootPe): Parameters ---------- - + rootPe - root processor where data should be gathered (or None if local - areas are to be returned) + root processor where data should be gathered (or None if local + areas are to be returned) _: None diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 3aa8a00e..aa1aeb10 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -21,8 +21,22 @@ def guessPeriodicity(srcBounds): """ Guess if a src grid is periodic - @param srcBounds the nodal src set of coordinates - @return 1 if periodic, warp around, 0 otherwise + + Parameters + ---------- + + + srcBounds + the nodal src set of coordinates + + _: None + + + Returns + ------- + + + 1 if periodic, warp around, 0 otherwise """ res = 0 if srcBounds is not None: @@ -52,21 +66,34 @@ def __init__(self, srcGrid, dstGrid, dstGridMask=None, dstBounds=None, dstGridAreas=None, **args): """ - Constructor. - @param srcGrid list of numpy arrays, source horizontal coordinates - @param dstGrid list of numpy arrays, destination horizontal coordinate - @param dtype numpy data type for src/dst data - @param regridMethod linear (bi, tri,...) default or conservative - @param regridTool currently either 'libcf' or 'esmf' - @param srcGridMask array of same shape as srcGrid - @param srcBounds list of numpy arrays of same shape as srcGrid - @param srcGridAreas array of same shape as srcGrid - @param dstGridMask array of same shape as dstGrid - @param dstBounds list of numpy arrays of same shape as dstGrid - @param dstGridAreas array of same shape as dstGrid - @param **args additional arguments to be passed to the - specific tool - 'libcf': mkCyclic={True, False}, handleCut={True,False} + Constructor + + + srcGrid + list of numpy arrays, source horizontal coordinates + dstGrid + list of numpy arrays, destination horizontal coordinate + dtype + numpy data type for src/dst data + regridMethod + linear (bi, tri,...) default or conservative + regridTool + currently either 'libcf' or 'esmf' + srcGridMask + array of same shape as srcGrid + srcBounds + list of numpy arrays of same shape as srcGrid + srcGridAreas + array of same shape as srcGrid + dstGridMask + array of same shape as dstGrid + dstBounds + list of numpy arrays of same shape as dstGrid + dstGridAreas + array of same shape as dstGrid + **args + additional arguments to be passed to the specific tool + libcf': mkCyclic={True, False}, handleCut={True,False} 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... """ @@ -160,12 +187,19 @@ def apply(self, srcData, dstData, **args): """ Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param rootPe if other than None, then results will be MPI - gathered - @param missingValue if not None, then data mask will be interpolated - and data value set to missingValue when masked + + Parameters + ---------- + + srcData + array (input) + dstData + array (output) + rootPe + if other than None, then results will be MPI gathered + missingValue + if not None, then data mask will be interpolated + and data value set to missingValue when masked """ # assuming the axes are the slowly varying indices @@ -288,16 +322,26 @@ def getDstGrid(self): """ Return the destination grid, may be different from the dst grid provided to the constructor due to domain decomposition - @return local grid on this processor + + Returns + ------- + + local grid on this processor """ return self.tool.getDstGrid() def fillInDiagnosticData(self, diag, rootPe=None): """ Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - entries are tool dependent - @param rootPe root processor where data should be gathered (or - None if local areas are to be returned) + + Parameters + ---------- + + diag + a dictionary whose entries, if present, will be filled + entries are tool dependent + rootPe + root processor where data should be gathered (or + None if local areas are to be returned) """ self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py index 30c5f4bf..79aa812a 100644 --- a/regrid2/Lib/mvLibCFRegrid.py +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -19,10 +19,17 @@ def __init__(self, srcGrid, dstGrid, srcGridMask=None, srcBounds=None, **args): """ Constructor - @param srcGrid array - @param dstGrid array - @param srcBounds cell boundaries - @param **args keyword arguments, eg mkCyclic, handleCut, ... + + Parameters + ---------- + + srcGrid + array + dstGrid + array + srcBounds + cell boundaries + **args keyword arguments, eg mkCyclic, handleCut, ... to be passed to gsRegrid """ self.regridMethodStr = 'linear' @@ -47,7 +54,11 @@ def __init__(self, srcGrid, dstGrid, srcGridMask=None, def computeWeights(self, **args): """ Compute interpolation weights - @param **args arguments to be passed to gsRegrid, e.g. + + Parameters + ---------- + + **args arguments to be passed to gsRegrid, e.g. nitermax, tolpos, ... """ nitermax = args.get('nitermax', 20) @@ -58,11 +69,17 @@ def computeWeights(self, **args): def apply(self, srcData, dstData, missingValue=None, **args): """ Regrid source to destination - @param srcData array (input) - @param dstData array (output) - @param missingValue value that should be set for points falling outside - the src domain, pass None if these should not be - touched. + + Parameters + ---------- + + srcData + array (input) + dstData + array (output) + missingValue + value that should be set for points falling outside + the src domain, pass None if these should not be touched. """ self.regridObj.apply(srcData, dstData, missingValue) @@ -72,23 +89,36 @@ def getSrcGrid(self): Get the grid of the src data (maybe larger than the dst grid passed to the constructor due to column/row padding) - @return grid + + Returns + ------- + + grid """ return self.regridObj.getSrcGrid() def getDstGrid(self): """ Get the grid of the dst data - @return grid + + Returns + ------- + grid """ return self.regridObj.getDstGrid() def fillInDiagnosticData(self, diag, rootPe): """ Fill in diagnostic data - @param diag a dictionary whose entries, if present, will be filled - valid entries are: 'numDstPoints' and 'numValid' - @param rootPe not used + + Parameters + ---------- + + diag + a dictionary whose entries, if present, will be filled + valid entries are: 'numDstPoints' and 'numValid' + rootPe + not used """ for entry in 'numDstPoints', 'numValid': if entry in diag: From 72414f29497afee48cb8a759d333866f429575c4 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 2 May 2018 15:49:53 -0700 Subject: [PATCH 123/239] Changes to API --- Lib/avariable.py | 3 +- Lib/axis.py | 32 ++++++++--------- Lib/cache.py | 71 ++++++++++++++++++++++++++------------ Lib/coord.py | 3 +- Lib/database.py | 16 ++++++--- Lib/dataset.py | 12 ++++--- Lib/forecast.py | 9 ++--- Lib/gengrid.py | 1 + Lib/mvCdmsRegrid.py | 82 ++++++++++++++++++++++++++------------------ Lib/mvSphereMesh.py | 10 +++--- Lib/mvVTKSGWriter.py | 3 +- Lib/mvVsWriter.py | 7 +++- Lib/slabinterface.py | 11 +++--- Lib/variable.py | 59 ++++++++++++++++++++----------- regrid2/Lib/esmf.py | 29 ++++++---------- regrid2/Lib/scrip.py | 49 +++++++++++++++++++------- 16 files changed, 245 insertions(+), 152 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index 653ced15..b9c4baab 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -133,6 +133,7 @@ def info(self, flag=None, device=None): def __init__(self, parent=None, variableNode=None): """Not to be called by users. + Parameters ---------- @@ -170,7 +171,7 @@ def __array__(self, t=None, context=None): # Numeric, ufuncs call this def __call__(self, *args, **kwargs): """ Selection of a subregion using selectors. - + Parameters ---------- raw: diff --git a/Lib/axis.py b/Lib/axis.py index 63d1c50e..e62160da 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -193,8 +193,8 @@ def createUniformLongitudeAxis(startLon, nlon, deltaLon): def mapLinearIntersection(xind, yind, iind, aMinusEps, aPlusEps, bPlusEps, bMinusEps, boundLeft, nodeSubI, boundRight): - """ Parameters - ---------- + """Parameters + ---------- xind: 'c' if (a,b) is closed on the left, 'o' if open, @@ -206,19 +206,14 @@ def mapLinearIntersection(xind, yind, iind, Returns ------- - True if the coordinate interval (a,b) intersects the node nodeSubI or cell - bounds [boundLeft,boundRight], where the interval (a,b) is defined by: + True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: * aMinusEps,aPlusEps = a +/- epsilon * bPlusEps,bMinusEps = b +/- epsilon - and the intersection option iind = 'n','b','e','s' specifies whether - the intersection is with respect to the node value nodeSubI ('n' or 'e') - or the cell bounds [boundLeft,boundRight]. + and the intersection option iind = 'n','b','e','s' specifies whether the intersection is with respect to the node value nodeSubI ('n' or 'e') or the cell bounds [boundLeft,boundRight]. - See Also - -------- - mapLinearExt + See Also mapLinearExt """ @@ -260,15 +255,17 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', meaning for the right-hand point. The third character indicates how the intersection of the interval and axis is treated: - 'n' - the node is in the interval - 'b' - the interval intersects the cell bounds - 's' - the cell bounds are a subset of the interval - 'e' - same as 'n', plus an extra node on either side. + 'n' - the node is in the interval + + 'b' - the interval intersects the cell bounds + + 's' - the cell bounds are a subset of the interval + + 'e' - same as 'n', plus an extra node on either side. Returns ------- - The corresponding index interval (i,j), where i to local file . For FTP transfers, if cache._useWindow is true, - display a progress dialog, otherwise just print progress messages. + Copy file to local file . + + For FTP transfers, if cache._useWindow is true, display a progress dialog, otherwise just print progress messages. + + For request manager transfers, is the logical collection distinguished name, - For request manager transfers, is the logical collection distinguished name, - is the string user ID, is true iff the request manager should - search the replica catalog for the actual file to transfer. + + + is the string user ID, is true iff the request manager should search the replica catalog for the actual file to transfer. """ if callback is None: if _useWindow: @@ -335,9 +348,15 @@ def copyFile(self, fromURL, filekey, lcpath=None, """ Copy the file into the cache. Return the result path. - For request manager transfers, lcpath is the logical collection path, - is the string user ID, is true iff the request manager should - search the replica catalog for the actual file to transfer. + For request manager transfers, lcpath is the logical collection path, + + + + is the string user ID, + + + + is true iff the request manager should search the replica catalog for the actual file to transfer. """ # Put a notification into the cache, that this file is being read. @@ -375,19 +394,29 @@ def copyFile(self, fromURL, filekey, lcpath=None, def getFile(self, fromURL, filekey, naptime=5, maxtries=60, lcpath=None, userid=None, useReplica=None): """ - Get the file with . If the file is in the cache, read it. - If another process is transferring it into the cache, wait for the - transfer to complete. is the number of seconds between - retries, is the maximum number of retries. - Otherwise, copy it from the remote file. + Get the file with . + + If the file is in the cache, read it. + + If another process is transferring it into the cache, wait for the + transfer to complete. - is the cache index key. A good choice is (datasetDN, filename) + is the number of seconds between + retries, + + is the maximum number of retries. Otherwise, copy it from the remote file. + + is the cache index key. A good choice is (datasetDN, filename) where datasetDN is the distinguished name of the dataset, and filename is the name of the file within the dataset. - For request manager transfers, is the logical collection path, - is the user string ID, is true iff the request manager should - search the replica catalog for the actual file to transfer. + For request manager transfers, + + is the logical collection path, + + is the user string ID, + + is true iff the request manager should search the replica catalog for the actual file to transfer. Returns the path of a file in the cache. diff --git a/Lib/coord.py b/Lib/coord.py index c4e3b3ce..ef731cec 100644 --- a/Lib/coord.py +++ b/Lib/coord.py @@ -372,7 +372,8 @@ class TransientAxis2D(AbstractAxis2D, TransientVariable): def __init__(self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, axes=None, attributes=None, id=None, copyaxes=1, bounds=None): - """Create a transient 2D axis. + """ + Create a transient 2D axis. All arguments are as for TransientVariable. diff --git a/Lib/database.py b/Lib/database.py index ff6163e4..7bc813ed 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -106,10 +106,15 @@ def connect(uri=None, user="", password=""): def loadString(text, uri, parent=None, datapath=None): - """ Create a dataset from a text string. is the string in CDML format. - is the URL of the dataset in a catalog or file. - is the containing database object, if any. - is the location of data files relative to the parent database URL. + """ Create a dataset from a text string. + + is the string in CDML format. + + is the URL of the dataset in a catalog or file. + + is the containing database object, if any. + + is the location of data files relative to the parent database URL. """ p = CDMLParser() p.feed(text) @@ -329,7 +334,8 @@ def searchFilter(self, filter=None, tag=None, relbase=None, """ Method - searchFilter(filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) + searchFilter + (filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) Description diff --git a/Lib/dataset.py b/Lib/dataset.py index e3545553..166c3a39 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -1741,14 +1741,18 @@ def copyGrid(self, grid, newname=None): Parameters ---------- - newname: (str/None) - new name for grid (default None) + newname: + (str/None) + new name for grid (default None) + grid: - file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + file grid + (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) Returns ------- - file grid (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + file grid + (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) """ if newname is None: diff --git a/Lib/forecast.py b/Lib/forecast.py index fe8dae05..e060e553 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -129,8 +129,7 @@ def available_forecasts(dataset_file, path="."): Returns ------- - a list of forecasts (as their generating times) which are - available through the specified cdscan-generated dataset xml file. + a list of forecasts (as their generating times) which are available through the specified cdscan-generated dataset xml file. Note ---- @@ -353,8 +352,7 @@ def forecast_axis(self, varname, fcss=None): Returns ------- - a tuple (axis,start,length,true_length) where axis is in the - forecast direction. + a tuple (axis,start,length,true_length) where axis is in the forecast direction. Note ----- @@ -405,8 +403,7 @@ def __getitem__(self, varname, fccs=None): Returns ------- - whatever the forecast set has that matches the given - attribute, normally a DatasetVariable. + whatever the forecast set has that matches the given attribute, normally a DatasetVariable. Note diff --git a/Lib/gengrid.py b/Lib/gengrid.py index e657d6e0..70c29088 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -38,6 +38,7 @@ def clone(self, copyData=1): def getMesh(self, transpose=None): """Generate a mesh array for the meshfill graphics method. + Parameters ---------- diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index d221a6f4..6bc6b153 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -180,7 +180,8 @@ def _buildBounds(bounds): Parameters ---------- - bounds CdmsVar.getBounds() + bounds + CdmsVar.getBounds() Returns ------- @@ -210,14 +211,17 @@ def getBoundList(coordList, mask=None, Parameters ---------- - coordList coordinate list, should have getBounds() + coordList + coordinate list, should have getBounds() - mask avoid checking areas where mask is one + mask + avoid checking areas where mask is one - removeBadCells set to True if you want to the code to remove - bad cells, ie zero cells, butterfly cells, ... + removeBadCells + set to True if you want to the code to remove bad cells, ie zero cells, butterfly cells, ... - maskCellIndices list of bad cell indices to mask out (output) + maskCellIndices + list of bad cell indices to mask out (output) Returns ------- @@ -283,9 +287,11 @@ def _getDstDataShape(srcVar, dstGrid): Parameters ---------- - srcVar the variable from which all axes other than lat/lon - will be taken from - dstGrid target, horizontal grid + srcVar + the variable from which all axes other than lat/lon will be taken from + + dstGrid + target, horizontal grid Returns ------- @@ -327,15 +333,16 @@ def _getAxisList(srcVar, dstGrid): Parameters ---------- - srcVar the variable from which all axes other than lat/lon - will be taken from - dstGrid target, horizontal grid + srcVar + the variable from which all axes other than lat/lon will be taken from + + dstGrid + target, horizontal grid Returns ------- - variable with non-horizontal axes from srcVar and horizontal axes - from dstGrid + variable with non-horizontal axes from srcVar and horizontal axes from dstGrid """ shp = srcVar.shape @@ -384,33 +391,38 @@ def __init__(self, srcGrid, dstGrid, dtype, Parameters ---------- - srcGrid CDMS source grid + srcGrid + CDMS source grid - dstGrid CDMS destination grid + dstGrid + CDMS destination grid - dtype numpy data type for src and dst data + dtype + numpy data type for src and dst data - regridMethod linear (all tools - bi, tri), - conserve (ESMF Only) - patch (ESMF Only) + regridMethod + linear (all tools - bi, tri), + conserve (ESMF Only) + patch (ESMF Only) - regridTool LibCF, ESMF, ... + regridTool + LibCF, ESMF, ... - srcGridMask array source mask, interpolation - coefficients will not be computed for masked - points/cells. + srcGridMask + array source mask, interpolation coefficients will not be computed for masked + points/cells. - srcGridAreas array destination cell areas, only needed for - conservative regridding + srcGridAreas + array destination cell areas, only needed for conservative regridding - dstGridMask array destination mask, interpolation - coefficients will not be computed for masked - points/cells. + dstGridMask + array destination mask, interpolation coefficients will not be computed for masked points/cells. - dstGridAreas array destination cell areas, only needed for - conservative regridding + dstGridAreas + array destination cell areas, only needed for conservative regridding - **args additional, tool dependent arguments + **args + additional, tool dependent arguments """ srcBounds = None @@ -503,9 +515,11 @@ def __call__(self, srcVar, **args): Parameters ---------- - srcVar CDMS variable + srcVar + CDMS variable - **args Tool dependent arguments + **args + Tool dependent arguments Returns ------- diff --git a/Lib/mvSphereMesh.py b/Lib/mvSphereMesh.py index 0807d8da..d673bc78 100644 --- a/Lib/mvSphereMesh.py +++ b/Lib/mvSphereMesh.py @@ -21,10 +21,11 @@ def __init__(self, var, sphereThickness=0.1): Parameters ---------- - var cdms2 variable + var + cdms2 variable - sphereThickness thickness of the shell in normalized - sphere radius + sphereThickness + thickness of the shell in normalized sphere radius """ self.isRectilinear = True @@ -102,7 +103,8 @@ def getXYZCoords(self, sphereRadius=1.0): Parameters ---------- - sphereRadius radius of sphere + sphereRadius + radius of sphere Returns ------- diff --git a/Lib/mvVTKSGWriter.py b/Lib/mvVTKSGWriter.py index 6bdc7c41..8dc7757c 100644 --- a/Lib/mvVTKSGWriter.py +++ b/Lib/mvVTKSGWriter.py @@ -22,7 +22,8 @@ def write(self, filename): Parameters ---------- - filename file name + filename + file name """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVsWriter.py b/Lib/mvVsWriter.py index 369333de..d18ecd27 100644 --- a/Lib/mvVsWriter.py +++ b/Lib/mvVsWriter.py @@ -17,7 +17,12 @@ class VsWriter(mvBaseWriter.BaseWriter): def write(self, filename): """ Write file - @param filename file name + + Parameters + ---------- + + filename + file name """ try: import tables diff --git a/Lib/slabinterface.py b/Lib/slabinterface.py index 98e37251..80c7535f 100644 --- a/Lib/slabinterface.py +++ b/Lib/slabinterface.py @@ -12,11 +12,12 @@ class Slab: """Slab is the cu api - This is an abstract class to inherit in AbstractVariable - About axes: - weight and bounds attributes always set but may be None - if bounds are None, getdimattribute returns result of querying the - axis. + + This is an abstract class to inherit in AbstractVariable About axes: + + weight and bounds attributes always set but may be None + if bounds are None, getdimattribute returns result of querying the + axis. """ std_slab_atts = ['filename', 'missing_value', diff --git a/Lib/variable.py b/Lib/variable.py index 0f4e0033..d4a9c597 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -217,12 +217,18 @@ def getPaths(self, *specs, **keys): def genMatch(self, axis, interval, matchnames): """Helper function for expertPaths. axis is a partitioned axis, either time or vertical level or forecast. - interval is an index interval (istart, iend). - matchnames is a partially filled list [id, timestart, timeend, levstart, levend, fc] - If a filemap is used, matchnames has indices, otherwise has coordinates. - Function modifies matchnames based on axis and interval, - returns the modified matchnames tuple. + Parameters + ---------- + + interval + is an index interval (istart, iend). + + matchnames + is a partially filled list [id, timestart, timeend, levstart, levend, fc] If a filemap is used, matchnames has indices, otherwise has coordinates. + + Function + modifies matchnames based on axis and interval, returns the modified matchnames tuple. """ if axis.isTime(): if hasattr(self.parent, 'cdms_filemap'): @@ -290,25 +296,38 @@ def getPartition(self, axis): def expertPaths(self, slist): """ expertPaths(self, slicelist) + takes a list of slices, - returns a 3-tuple: (npart, dimensionlist, partitionSlices) where: - npart is the number of partitioned dimensions: 0, 1, or 2; - dimensionlist is a tuple of length npart, having the dimension - numbers of the partitioned dimensions; - partitionSlices is the list of file-specific (filename, slice) - corresponding to the paths and slices within the files to be read. + + returns a 3-tuple: + (npart, dimensionlist, partitionSlices) + + where: + npart is the number of partitioned dimensions: 0, 1, or 2; + + dimensionlist + is a tuple of length npart, having the dimension + numbers of the partitioned dimensions; + + partitionSlices + is the list of file-specific (filename, slice) + corresponding to the paths and slices within the files to be read. + The exact form of partitionSlices depends on the value of npart: - npart partitionSlices - 0 (filename,slicelist) - 1 [(filename,slicelist),...,(filename,slicelist)] - 2 [[(filename,slicelist),...,(filename,slicelist)] - [(filename,slicelist),...,(filename,slicelist)] - ... - [(filename,slicelist),...,(filename,slicelist)]] + + npart partitionSlices + + 0 (filename,slicelist) + + 1 [(filename,slicelist),...,(filename,slicelist)] + + 2 [[(filename,slicelist),...,(filename,slicelist)] + [(filename,slicelist),...,(filename,slicelist)] + ... + [(filename,slicelist),...,(filename,slicelist)]] Note: - - A filename of None indicates that no file was found with data - corresponding to the slicelist. + - A filename of None indicates that no file was found with data corresponding to the slicelist. - If partitionSlices is None, the slicelist does not intersect the domain. - An empty partitionSlices [] means that the variable is zero-dimensional. """ diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 2769619b..bbc1cb81 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -94,28 +94,19 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- - 3 - /-------------------\ - /----------------------\ - /------------------------\ - /--------------------------\ - /----------------------------\ - 1 ------------------------------------- 2 - + 3 4-------------3 + /\ | | + / \ | | + / \ | | + / \ | | + / \ | | + / \ | | + 1------------2 1-------------2 + - 4------------3 - - | - | - | - | - | - - 1------------2 - - + 3 8---------------7 diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 5a052700..8af37699 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -107,14 +107,29 @@ def getDestinationFraction(self): class ConservativeRegridder(ScripRegridder): - """First-order conservative regrid. By default, the normalize option ="fracarea", and array 'normal' - is not specified. If 'normal' is specified, it should be a one-dimensional array of the same length - as the output grid size, with values: - 1.0 for normalize="fracarea", - grid_frac for normalize="destarea", or - grid_frac*grid_area for normalize="none". - sourceArea is the area of the source grid cells - destArea is the area of the destination grid cells + """First-order conservative regrid. + + By default, the normalize option ="fracarea", and array 'normal' is not specified. + + If 'normal' is specified, it should be a one-dimensional array of the same length + as the output grid size, with values: + + 1.0 for normalize="fracarea", + + grid_frac for normalize="destarea", or + + grid_frac*grid_area for normalize="none". + + Parameters + ---------- + + sourceArea + + is the area of the source grid cells + + destArea + + is the area of the destination grid cells """ def __init__(self, outputGrid, remapMatrix, sourceAddress, destAddress, inputGrid=None, @@ -344,10 +359,20 @@ def regrid(self, input): def readRegridder(fileobj, mapMethod=None, checkGrid=1): """Read a regridder from an open fileobj. - mapMethod is one of "conservative", "bilinear", "bicubic", or "distwgt". If unspecified, it defaults to the method - defined in the file. - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. + + Parameters + ---------- + + mapMethod + + is one of "conservative", "bilinear", "bicubic", or "distwgt". + + If unspecified, it defaults to the method defined in the file. + + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, + and 'repaired' if necessary. + + _: None """ if isinstance(fileobj, str): From 735a306bb1836d9f1573887f33f975ba8e1ed937 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 3 May 2018 14:58:01 -0700 Subject: [PATCH 124/239] Changes made to API --- Lib/MV2.py | 18 +++++++++--------- Lib/avariable.py | 14 ++++++++------ Lib/axis.py | 7 +++---- Lib/cache.py | 35 +++++++++++++++++++++-------------- Lib/cudsinterface.py | 20 +++++++++++--------- Lib/database.py | 12 ++++++++---- Lib/dataset.py | 2 +- Lib/grid.py | 18 ++++++++++++------ Lib/hgrid.py | 29 ++++++++++++++++++----------- Lib/variable.py | 22 ++++++++++++++++++---- 10 files changed, 109 insertions(+), 68 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index aa622f33..db309613 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -109,11 +109,13 @@ def __call__(self, a, axis=0, **kwargs): def commonDomain(a, b, omit=None): """commonDomain(a,b) tests that the domains of variables/arrays a and b are equal, - and returns the common domain if equal, or None if not equal. The domains may - differ in that one domain may have leading axes not common - to the other; the result domain will contain those axes. - If is specified, as an integer i, skip comparison of the ith dimension - and return None for the ith (common) dimension. + and returns the common domain if equal, or None if not equal. + + The domains may differ in that one domain may have leading axes not common + to the other; the result domain will contain those axes. + + If is specified, as an integer i, skip comparison of the ith dimension + and return None for the ith (common) dimension. """ if isinstance(b, AbstractVariable): @@ -183,11 +185,9 @@ def commonGrid(a, b, axes): and consistent with the list of axes. If so, the common grid is returned, else None is returned. a and b can be numpy arrays, in which case the result is None. - The common grid is 'consistent' with axes if the grid axes (e.g., the axes of latitude and - longitude coordinate variables) are members of the list 'axes'. + The common grid is 'consistent' with axes if the grid axes (e.g., the axes of latitude and longitude coordinate variables) are members of the list 'axes'. - If the grid(s) of a, b are rectilinear, the result is None, as the grids are implicitly - defined by the axes. + If the grid(s) of a, b are rectilinear, the result is None, as the grids are implicitly defined by the axes. """ if isinstance(b, AbstractVariable): gb = b.getGrid() diff --git a/Lib/avariable.py b/Lib/avariable.py index b9c4baab..f747d460 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -1191,6 +1191,7 @@ def subRegion(self, *specs, **keys): def getValue(self, squeeze=1): """Get the entire set of values. + Returns ------- All values and elimite the 1-D dimension. @@ -1684,11 +1685,11 @@ def isEncoded(self): def decode(self, ar): """Decode compressed data. + Parameter + --------- + ar + is a masked array, scalar, or numpy.ma.masked. - Parameter - --------- - - ar is a masked array, scalar, or numpy.ma.masked. _: None """ @@ -1719,8 +1720,9 @@ def decode(self, ar): return ar def getGridIndices(self): - """Return - ------ + """ + Returns + ------- a tuple of indices corresponding to the variable grid.""" grid = self.getGrid() result = [] diff --git a/Lib/axis.py b/Lib/axis.py index e62160da..d5f2881b 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -266,6 +266,7 @@ def mapLinearExt(axis, bounds, interval, indicator='ccn', Returns ------- The corresponding index interval (i,j), where i. + """Get the file with . If the file is in the cache, read it. If another process is transferring it into the cache, wait for the transfer to complete. - is the number of seconds between - retries, + + is the number of seconds between retries, - is the maximum number of retries. Otherwise, copy it from the remote file. + + is the maximum number of retries. Otherwise, copy it from the remote file. - is the cache index key. A good choice is (datasetDN, filename) + + is the cache index key. A good choice is (datasetDN, filename) where datasetDN is the distinguished name of the dataset, and filename is the name of the file within the dataset. For request manager transfers, - is the logical collection path, + + is the logical collection path, - is the user string ID, + + is the user string ID, - is true iff the request manager should search the replica catalog for the actual file to transfer. + + is true iff the request manager should search the replica catalog for the actual file to transfer. Returns the path of a file in the cache. diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index 5cedd90e..c2ace837 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -381,8 +381,9 @@ def getattribute(self, vname, attribute): return getattr(v, attribute) def getslab(self, vname, *args, **keys): - """getslab('name', arg1, arg2, ....) returns a cdms variable - containing the data. + """getslab('name', arg1, arg2, ....) + + returns a cdms variable containing the data. Arguments for each dimension can be: (1) : or None -- selected entire dimension @@ -465,11 +466,13 @@ def getslab(self, vname, *args, **keys): def readScripGrid(self, whichGrid="destination", checkGrid=1): """Read a SCRIP curvilinear or generic grid from the dataset. - The dataset can be a SCRIP grid file or mapping file. If a mapping file, - 'whichGrid' chooses the grid to read, either "source" or "destination". - If 'checkGrid' is 1 (default), the grid cells are checked for convexity, - and 'repaired' if necessary. - Returns the grid object. + + The dataset can be a SCRIP grid file or mapping file. If a mapping file, + 'whichGrid' chooses the grid to read, either "source" or "destination". + + If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. + + Returns the grid object. Options @@ -479,8 +482,7 @@ def readScripGrid(self, whichGrid="destination", checkGrid=1): checkGrid (int) (1) if 1 the grid cells are checked for convexity - Output - grid + Output grid (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested """ diff --git a/Lib/database.py b/Lib/database.py index 7bc813ed..e32ad676 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -108,13 +108,17 @@ def connect(uri=None, user="", password=""): def loadString(text, uri, parent=None, datapath=None): """ Create a dataset from a text string. - is the string in CDML format. + + is the string in CDML format. - is the URL of the dataset in a catalog or file. + + is the URL of the dataset in a catalog or file. - is the containing database object, if any. + + is the containing database object, if any. - is the location of data files relative to the parent database URL. + + is the location of data files relative to the parent database URL. """ p = CDMLParser() p.feed(text) diff --git a/Lib/dataset.py b/Lib/dataset.py index 166c3a39..e2308815 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -1996,7 +1996,7 @@ def searchPredicate(self, predicate, tag): def createVariableCopy(self, var, id=None, attributes=None, axes=None, extbounds=None, extend=0, fill_value=None, index=None, newname=None, grid=None): - """Define a new variable, with the same axes and attributes as in . + """Define a new variable, with the same axes and attributes as in "var". Note ---- diff --git a/Lib/grid.py b/Lib/grid.py index 5da709e3..5b68799a 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -148,15 +148,21 @@ def setRegionSpecs(grid, coordSpec, coordType, resultSpec): coordSpec: is a coordinate specification, having one of the forms: - x - (x,y) - (x,y,'co') - (x,y,'co',cycle) - ':' - None + x + + (x,y) + + (x,y,'co') + + (x,y,'co',cycle) + + ':' + + None coordType: is one of CoordinateTypes + resultSpec: is a list of 4-tuples of the form (x,y,'co',cycle), or None if no spec for the corresponding dimension type. diff --git a/Lib/hgrid.py b/Lib/hgrid.py index 5ac1bdca..e012e929 100644 --- a/Lib/hgrid.py +++ b/Lib/hgrid.py @@ -148,17 +148,20 @@ def checkConvex(self): return badcells def fixCutCells(self, nonConvexCells, threshold=270.0): - """For any mapping from a spherical to a planar surface, there is a linear cut. - Grid cells that span the cut may appear to be nonconvex, which causes - problems with meshfill graphics. This routine attempts to 'repair' the cut cell - boundaries so that meshfill recognizes they are convex. - - nonConvexCells: 1D numpy array of indices of nonconvex cells, as returned from - checkConvex. - threshold: positive floating-point value in degrees. - If the difference in longitude values of - consecutive boundaries nodes exceeds the threshold, the cell is considered - a cut cell. + """ + + For any mapping from a spherical to a planar surface, there is a linear cut. Grid cells that span the cut may appear to be nonconvex, which causes problems with meshfill graphics. This routine attempts to 'repair' the cut cell boundaries so that meshfill recognizes they are convex. + + Parameters + ---------- + + nonConvexCells: + 1D numpy array of indices of nonconvex cells, as returned from checkConvex. + threshold: + positive floating-point value in degrees. + + + If the difference in longitude values of consecutive boundaries nodes exceeds the threshold, the cell is considered a cut cell. On return, the grid boundaries are modified. Return value is a 1D array of indices of cells that cannot be repaired. @@ -877,6 +880,10 @@ def readScripCurveGrid(fileobj, dims, whichType, whichGrid): if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" + + Returns + ------- + """ import string from .coord import TransientAxis2D diff --git a/Lib/variable.py b/Lib/variable.py index d4a9c597..0b3778b6 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -41,9 +41,15 @@ def timeindex(value, units, basetime, delta, delunits, calendar): class DatasetVariable(AbstractVariable): def __init__(self, parent, id, variableNode=None): - """ "Variable (parent, variableNode=None)" - variableNode is the variable tree node, if any. - parent is the containing dataset instance. + """"Variable (parent, variableNode=None)" + + Parameters + ---------- + variableNode + is the variable tree node, if any. + + parent + is the containing dataset instance. """ AbstractVariable.__init__(self, parent, variableNode) val = self.__cdms_internals__ + ['domain', 'name_in_file'] @@ -279,9 +285,17 @@ def getFilePath(self, matchnames, template): def getPartition(self, axis): """Get the partition attribute for this variable, axis. - axis is either a time or level axis. If cdms_filemap is being used, + + Parameters + ---------- + + axis: + is either a time or level axis. If cdms_filemap is being used, get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. + + _: None + """ if hasattr(self.parent, 'cdms_filemap'): if axis.isTime(): From 8ad34b54681814799ce9e99aa5a51c2d44adcc96 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 9 May 2018 15:01:01 -0700 Subject: [PATCH 125/239] Changes made to API --- Lib/axis.py | 5 +- Lib/cache.py | 3 +- Lib/cudsinterface.py | 12 +-- Lib/database.py | 19 +++-- Lib/dataset.py | 4 +- Lib/mvCdmsRegrid.py | 3 +- Lib/variable.py | 29 ++++---- regrid2/Lib/esmf.py | 63 ++++++---------- regrid2/Lib/gsRegrid.py | 132 ++++++++++++++++++++------------- regrid2/Lib/horizontal.py | 32 +++++--- regrid2/Lib/mvESMFRegrid.py | 54 ++++++++------ regrid2/Lib/mvGenericRegrid.py | 21 +++++- regrid2/Lib/mvLibCFRegrid.py | 21 +++--- 13 files changed, 226 insertions(+), 172 deletions(-) diff --git a/Lib/axis.py b/Lib/axis.py index d5f2881b..f7eac285 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -193,8 +193,9 @@ def createUniformLongitudeAxis(startLon, nlon, deltaLon): def mapLinearIntersection(xind, yind, iind, aMinusEps, aPlusEps, bPlusEps, bMinusEps, boundLeft, nodeSubI, boundRight): - """Parameters - ---------- + """ +Parameters +---------- xind: 'c' if (a,b) is closed on the left, 'o' if open, diff --git a/Lib/cache.py b/Lib/cache.py index e74816f2..8bc99007 100644 --- a/Lib/cache.py +++ b/Lib/cache.py @@ -182,9 +182,8 @@ def copyFile(fromURL, toURL, callback=None, For request manager transfers, is the logical collection distinguished name, - - is the string user ID, is true iff the request manager should search the replica catalog for the actual file to transfer. + is the string user ID, is true if the request manager should search the replica catalog for the actual file to transfer. """ if callback is None: if _useWindow: diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index c2ace837..ace6cf94 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -315,13 +315,13 @@ def dimensionarray(self, dname, vname=None): vname (str/None) (None) variable name - Input - dname - (str) (0) dimension name + Input + dname + (str) (0) dimension name - Output - axisvalues - (numpy.ndarray) (0) array with values of axis whose id is vname + Output + axisvalues + (numpy.ndarray) (0) array with values of axis whose id is vname """ return self.dimensionobject(dname, vname).getValue() diff --git a/Lib/database.py b/Lib/database.py index e32ad676..68488f27 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -389,14 +389,21 @@ def searchFilter(self, filter=None, tag=None, relbase=None, Returns ------- - SearchResult instance. Entries can be accessed sequentially. For each entry, entry.name is the - name of the entry, entry.attributes is a dictionary of the attributes returned by the search, - entry.getObject() returns the CDMS object associated with the entry: + SearchResult instance. - for entry in result: - print entry.name, entry.attributes["id"] + Entries can be accessed sequentially. - Entries can be refined with searchPredicate(). + For each entry, + + entry.name is the name of the entry, + + entry.attributes is a dictionary of the attributes returned by the search, + + entry.getObject() returns the CDMS object associated with the entry: + + for entry in result: print entry.name, entry.attributes["id"] + + Entries can be refined with searchPredicate(). Example ------- diff --git a/Lib/dataset.py b/Lib/dataset.py index e2308815..b1af3413 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -1751,8 +1751,8 @@ def copyGrid(self, grid, newname=None): Returns ------- - file grid - (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + file grid + (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) """ if newname is None: diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index 6bc6b153..ed3d4734 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -387,10 +387,9 @@ def __init__(self, srcGrid, dstGrid, dtype, """ Establish which regridding method to use, handle CDMS variables before handing off to regridder. See specific tool for more information. - + Parameters ---------- - srcGrid CDMS source grid diff --git a/Lib/variable.py b/Lib/variable.py index 0b3778b6..80028e6b 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -41,7 +41,7 @@ def timeindex(value, units, basetime, delta, delunits, calendar): class DatasetVariable(AbstractVariable): def __init__(self, parent, id, variableNode=None): - """"Variable (parent, variableNode=None)" + """Variable (parent, variableNode=None)" Parameters ---------- @@ -222,11 +222,13 @@ def getPaths(self, *specs, **keys): def genMatch(self, axis, interval, matchnames): """Helper function for expertPaths. - axis is a partitioned axis, either time or vertical level or forecast. - + Parameters ---------- + axis + is a partitioned axis, either time or vertical level or forecast. + interval is an index interval (istart, iend). @@ -290,9 +292,7 @@ def getPartition(self, axis): ---------- axis: - is either a time or level axis. If cdms_filemap is being used, - get the partition from the _varpart_ attribute, otherwise (for templating) use - axis.partition. + is either a time or level axis. If cdms_filemap is being used, get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. _: None @@ -309,27 +309,26 @@ def getPartition(self, axis): return partition def expertPaths(self, slist): - """ expertPaths(self, slicelist) + """ - takes a list of slices, + expertPaths(self, slicelist) + takes a list of slices, returns a 3-tuple: - (npart, dimensionlist, partitionSlices) + (npart, dimensionlist, partitionSlices) where: npart is the number of partitioned dimensions: 0, 1, or 2; dimensionlist - is a tuple of length npart, having the dimension - numbers of the partitioned dimensions; + is a tuple of length npart, having the dimension numbers of the partitioned dimensions; partitionSlices - is the list of file-specific (filename, slice) - corresponding to the paths and slices within the files to be read. + is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. - The exact form of partitionSlices depends on the value of npart: + The exact form of partitionSlices depends on the value of npart: - npart partitionSlices + npart partitionSlices 0 (filename,slicelist) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index bbc1cb81..35accdff 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -74,21 +74,22 @@ def __init__(self, numTopoDims, numSpaceDims): def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """ - Set Cell connectivity + Set Cell connectivity + Parameters - ---------- - - cell indices + ---------- + + cell indices: + (0-based) - cellTypes + cellTypes: one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - connectivity node + connectivity node: connectivity array, see below for node ordering - cellMask - + cellMask: cellAreas area (volume) of each cell Note @@ -337,18 +338,13 @@ def setCoords(self, coords, staggerloc=CENTER, globalIndexing=False): ---------- coords - The curvilinear coordinates of the grid. - List of numpy arrays. Must exist on all procs. + The curvilinear coordinates of the grid. List of numpy arrays. Must exist on all procs. staggerloc - The stagger location - ESMF.StaggerLoc.CENTER (default) - ESMF.StaggerLoc.CORNER + The stagger location ESMF.StaggerLoc.CENTER (default) ESMF.StaggerLoc.CORNER globalIndexing - if True array was allocated over global index space, - otherwise array was allocated over local index space - on this processor. This is only relevant if rootPe is None + if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None Note: coord dims in cdms2 are ordered in y, x, but ESMF expects x, y, hence the dimensions are reversed here. @@ -440,8 +436,7 @@ def setMask(self, mask, staggerloc=CENTER): ---------- mask numpy array. - 1 is invalid by default. This array exists - on all procs + 1 is invalid by default. This array exists on all procs _: None """ @@ -544,9 +539,7 @@ def getData(self, rootPe): ---------- rootPe - if None then local data will be fetched, otherwise - gather the data on processor "rootPe" (all other - procs will return None). + if None then local data will be fetched, otherwise gather the data on processor "rootPe" (all other procs will return None). _: None @@ -602,16 +595,13 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): ---------- data - full numpy array, - this method will take care of setting a - the subset of the data that reside on the local processor + full numpy array, this method will take care of setting a the subset of the data that reside on the local processor staggerloc stagger location of the data globalIndexing - if True array was allocated over global index space, - array was allocated over local index space (on this processor) + if True array was allocated over global index space, array was allocated over local index space (on this processor) """ ptr = self.field.data if globalIndexing: @@ -740,8 +730,7 @@ def getSrcAreas(self, rootPe): ---------- rootPe - None is local areas are returned, otherwise - provide rootPe and the data will be gathered + None is local areas are returned, otherwise provide rootPe and the data will be gathered _: None @@ -762,8 +751,7 @@ def getDstAreas(self, rootPe): ---------- rootPe - None is local areas are returned, otherwise - provide rootPe and the data will be gathered + None is local areas are returned, otherwise provide rootPe and the data will be gathered _: None @@ -784,8 +772,7 @@ def getSrcAreaFractions(self, rootPe): ---------- rootPe - None is local areas are returned, otherwise - provide rootPe and the data will be gathered + None is local areas are returned, otherwise provide rootPe and the data will be gathered _: None @@ -807,8 +794,7 @@ def getDstAreaFractions(self, rootPe): ---------- rootPe - None is local areas are returned, otherwise - provide rootPe and the data will be gathered + None is local areas are returned, otherwise provide rootPe and the data will be gathered _: None @@ -830,16 +816,13 @@ def __call__(self, srcField=None, dstField=None, zero_region=None): ---------- srcField - source field (or None if src field passed to - constructor is to be used) + source field (or None if src field passed to constructor is to be used) dstField - destination field (or None if dst field passed - to constructor is to be used) + destination field (or None if dst field passed to constructor is to be used) zero_region - specify which region of the field indices will be zeroed - (or None default to TOTAL Region) + specify which region of the field indices will be zeroed (or None default to TOTAL Region) """ if srcField is None: srcField = self.srcField diff --git a/regrid2/Lib/gsRegrid.py b/regrid2/Lib/gsRegrid.py index de150dba..2d915b1e 100644 --- a/regrid2/Lib/gsRegrid.py +++ b/regrid2/Lib/gsRegrid.py @@ -48,11 +48,14 @@ def getTensorProduct(axis, dim, dims): Parameters ---------- - axis 1D array of coordinates + axis + 1D array of coordinates - dim dimensional index of the above coordinate + dim + dimensional index of the above coordinate - dims sizes of all coordinates + dims + sizes of all coordinates Returns ------- @@ -71,7 +74,9 @@ def makeCurvilinear(coords): Parameters ---------- - coords list of coordinates + coords + list of coordinates + _: None Returns ------- @@ -121,15 +126,16 @@ def makeCoordsCyclic(coords, dims): Parameters ---------- - coords input coordinates + coords + input coordinates - dims input dimensions + dims + input dimensions Returns ------- - new, extended coordinates such that the longitudes cover the sphere - and new dimensions + new, extended coordinates such that the longitudes cover the sphere and new dimensions """ # assume lon is the last coordinate!! @@ -186,9 +192,11 @@ def checkForCoordCut(coords, dims): Parameters ---------- - coords input coordinates + coords + input coordinates - dims input dimensions + dims + input dimensions Returns ------- @@ -292,17 +300,19 @@ def handleCoordsCut(coords, dims, bounds): Parameters ---------- - coords input coordinates list of rank + coords + input coordinates list of rank - dims input dimensions + dims + input dimensions - bounds boundaries for each coordinate + bounds + boundaries for each coordinate Returns ------- - extended coordinates such that there is an extra row containing - connectivity information across the cut + extended coordinates such that there is an extra row containing connectivity information across the cut """ # Assume latitude is next to last coordinate and longitude is @@ -319,11 +329,14 @@ def getIndices(array, nlon, newI): Parameters ---------- - array Array of booleans + array + Array of booleans - nlon number of longitudes + nlon + number of longitudes - newI index row with connectivity to be updated + newI + index row with connectivity to be updated Returns ------- @@ -366,26 +379,24 @@ def __init__(self, src_grid, dst_grid, src_bounds=None, mkCyclic=False, Parameters ---------- - src_grid source grid, a list of [x, y, ...] coordinates - or a cdms2.grid.Transient + src_grid + source grid, a list of [x, y, ...] coordinates or a cdms2.grid.Transient - dst_grid destination grid, a list of [x, y, ...] coordinates + dst_grid + destination grid, a list of [x, y, ...] coordinates - src_bounds list of cell bounding coordinates (to be used when - handling a cut in coordinates) + src_bounds + list of cell bounding coordinates (to be used when handling a cut in coordinates) - mkCyclic Add a column to the right side of the grid to complete - a cyclic grid - - handleCut Add a row to the top of grid to handle a cut for - grids such as the tri-polar grid + mkCyclic + Add a column to the right side of the grid to complete a cyclic grid + handleCut + Add a row to the top of grid to handle a cut for grids such as the tri-polar grid verbose print diagnostic messages - Note: the grid coordinates can either be axes (rectilinear grid) or - n-dimensional for curvilinear grids. Rectilinear grids will - be converted to curvilinear grids. + Note: the grid coordinates can either be axes (rectilinear grid) or n-dimensional for curvilinear grids. Rectilinear grids will be converted to curvilinear grids. """ self.regridid = c_int(-1) self.src_gridid = c_int(-1) @@ -601,12 +612,13 @@ def setValidMask(self, inMask): Parameters ---------- - inMask flat numpy array of type numpy.int32 or a valid cdms2 variable - with its mask set. + inMask + flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set. 0 - invalid, 1 - valid data - Note: This must be invoked before computing the weights, the - mask is a property of the grid (not the data). + _: None + + Note: This must be invoked before computing the weights, the mask is a property of the grid (not the data). """ if self.weightsComputed: raise RegridError('Must set mask before computing weights') @@ -633,6 +645,8 @@ def setMask(self, inDataOrMask): 0 - valid data 1 - invalid data + _: None + Note: this definition is compatible with the numpy masked arrays Note: note see setValidMask for the opposite definition @@ -658,9 +672,11 @@ def computeWeights(self, nitermax=100, tolpos=1.e-2): Parameters ---------- - nitermax max number of iterations + nitermax + max number of iterations - tolpos max tolerance when locating destination positions in + tolpos + max tolerance when locating destination positions in index space """ status = self.lib.nccf_compute_regrid_weights(self.regridid, @@ -676,12 +692,14 @@ def apply(self, src_data_in, dst_data, missingValue=None): Parameters ---------- - src_data data on source grid + src_data + data on source grid - dst_data data on destination grid + dst_data + data on destination grid - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ if not self.weightsComputed: raise RegridError('Weights must be set before applying the regrid') @@ -795,12 +813,14 @@ def __call__(self, src_data, dst_data, missingValue=None): Parameters ---------- - src_data data on source grid + src_data + data on source grid - dst_data data on destination grid + dst_data + data on destination grid - missingValue value that should be set for points falling outside the src domain, - pass None if these should not be touched. + missingValue + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ self.apply(src_data, dst_data, missingValue) @@ -866,7 +886,10 @@ def getIndicesAndWeights(self, dst_indices): Parameters ---------- - dst_indices index set on the target grid + dst_indices + index set on the target grid + + _: None Returns ------- @@ -901,7 +924,10 @@ def _extend(self, src_data): Parameters ---------- - src_data input source data + src_data + input source data + + _: None Returns ------- @@ -943,13 +969,17 @@ def _findIndices(self, targetPos, nitermax, tolpos, Parameters ---------- - targetPos numpy array of target positions + targetPos + numpy array of target positions - nitermax max number of iterations + nitermax + max number of iterations - tolpos max toelrance in positions + tolpos + max toelrance in positions - dindicesGuess guess for the floating point indices + dindicesGuess + guess for the floating point indices Returns ------- diff --git a/regrid2/Lib/horizontal.py b/regrid2/Lib/horizontal.py index 67d673f4..baae5831 100644 --- a/regrid2/Lib/horizontal.py +++ b/regrid2/Lib/horizontal.py @@ -37,9 +37,11 @@ def __init__(self, ingrid, outgrid): Parameters ---------- - ingrid cdms2, ndarray variable + ingrid cdms2, + ndarray variable - outgrid cdms2, ndarray variable + outgrid cdms2, + ndarray variable """ inlat = ingrid.getLatitude() @@ -90,14 +92,24 @@ def __call__(self, ar, missing=None, order=None, mask=None, returnTuple=0, **args): """ Call the regridder function. - @param ar is the input array. - @param order is of the form "tzyx", "tyx", etc. - @param missing is the missing data value, if any. - @param mask is either 2-D or the same shape as ar. - @param returnTuple If true, return the tuple (outArray, outWeights) where - outWeights is the fraction of each zone of the output grid - which overlaps non-missing zones of the input grid; it has - the same shape as the output array. + + Parameters + ---------- + + ar + is the input array. + + order + is of the form "tzyx", "tyx", etc. + + missing + is the missing data value, if any. + + mask + is either 2-D or the same shape as ar. + + returnTuple + If true, return the tuple (outArray, outWeights) where outWeights is the fraction of each zone of the output grid which overlaps non-missing zones of the input grid; it has the same shape as the output array. """ from cdms2.avariable import AbstractVariable diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 7bfed601..58b3cf22 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -53,25 +53,35 @@ def __init__(self, srcGridshape, dstGridshape, dtype, srcGridShape tuple source grid shape + dstGridShape tuple destination grid shape + dtype a valid numpy data type for the src/dst data + regridMethod 'linear', 'conserve', or 'patch' + staggerLoc the staggering of the field, 'center' or 'corner' + periodicity 0 (no periodicity), 1 (last coordinate is periodic, 2 (both coordinates are periodic) + coordSys 'deg', 'cart', or 'rad' + hasSrcBounds tuple source bounds shape + hasDstBounds tuple destination bounds shape - ignoreDegenerate Ignore degenerate celss when checking inputs + + ignoreDegenerate + Ignore degenerate celss when checking inputs """ # esmf grid objects (tobe constructed) @@ -215,24 +225,30 @@ def setCoords(self, srcGrid, dstGrid, srcGrid list [[z], y, x] of source grid arrays + dstGrid list [[z], y, x] of dstination grid arrays + srcGridMask list [[z], y, x] of arrays + srcBounds list [[z], y, x] of arrays + srcGridAreas list [[z], y, x] of arrays + dstGridMask list [[z], y, x] of arrays + dstBounds list [[z], y, x] of arrays + dstGridAreas list [[z], y, x] of arrays + globalIndexing - if True array was allocated over global index space, - otherwise array was allocated over local index space on - this processor. This is only relevant if rootPe is None + if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None """ # create esmf source Grid @@ -308,12 +324,10 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): the dstData returns None. Source data mask: + + . If you provide srcDataMask in args the source grid will be masked and weights will be recomputed. - . If you provide srcDataMask in args the source grid will - be masked and weights will be recomputed. - - . Subsequently, if you do not provide a srcDataMask the last - weights will be used to regrid the source data array. + . Subsequently, if you do not provide a srcDataMask the last weights will be used to regrid the source data array. . By default, only the data are masked, but not the grid. @@ -322,13 +336,16 @@ def apply(self, srcData, dstData, rootPe, globalIndexing=False, **args): srcData array source data, shape should cover entire global index space + dstData array destination data, shape should cover entire global index space + rootPe if other than None, then data will be MPI gathered on the specified rootPe processor + globalIndexing - if True array was allocated over global index space, otherwise array was allocated - over local index space on this processor. This is only relevant if rootPe is None + if True array was allocated over global index space, otherwise array was allocated over local index space on this processor. This is only relevant if rootPe is None + **args """ @@ -407,8 +424,7 @@ def getDstAreas(self, rootPe): ---------- rootPe - root processor where data should be gathered (or None - if local areas are to be returned) + root processor where data should be gathered (or None if local areas are to be returned) _: None @@ -432,8 +448,7 @@ def getSrcAreaFractions(self, rootPe): ---------- rootPe - root processor where data should be gathered (or None if local - areas are to be returned) + root processor where data should be gathered (or None if local areas are to be returned) _: None @@ -456,8 +471,7 @@ def getDstAreaFractions(self, rootPe): ---------- rootPe - root processor where data should be gathered (or None if local - areas are to be returned) + root processor where data should be gathered (or None if local areas are to be returned) _: None @@ -586,12 +600,10 @@ def fillInDiagnosticData(self, diag, rootPe): ---------- diag - a dictionary whose entries, if present, will be filled valid entries - are: 'srcAreaFractions', 'dstAreaFractions', srcAreas', 'dstAreas' + a dictionary whose entries, if present, will be filled valid entries are: 'srcAreaFractions', 'dstAreaFractions', srcAreas', 'dstAreas' rootPe - root processor where data should be gathered (or None if local areas are - to be returned) + root processor where data should be gathered (or None if local areas are to be returned) """ oldMethods = {} oldMethods['srcAreaFractions'] = 'getSrcAreaFractions' diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index aa1aeb10..0719bd3c 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -71,26 +71,37 @@ def __init__(self, srcGrid, dstGrid, srcGrid list of numpy arrays, source horizontal coordinates + dstGrid list of numpy arrays, destination horizontal coordinate + dtype numpy data type for src/dst data + regridMethod linear (bi, tri,...) default or conservative + regridTool currently either 'libcf' or 'esmf' + srcGridMask array of same shape as srcGrid + srcBounds list of numpy arrays of same shape as srcGrid + srcGridAreas array of same shape as srcGrid + dstGridMask array of same shape as dstGrid + dstBounds list of numpy arrays of same shape as dstGrid + dstGridAreas array of same shape as dstGrid + **args additional arguments to be passed to the specific tool libcf': mkCyclic={True, False}, handleCut={True,False} @@ -193,10 +204,13 @@ def apply(self, srcData, dstData, srcData array (input) + dstData array (output) + rootPe if other than None, then results will be MPI gathered + missingValue if not None, then data mask will be interpolated and data value set to missingValue when masked @@ -338,10 +352,9 @@ def fillInDiagnosticData(self, diag, rootPe=None): ---------- diag - a dictionary whose entries, if present, will be filled - entries are tool dependent + a dictionary whose entries, if present, will be filled entries are tool dependent + rootPe - root processor where data should be gathered (or - None if local areas are to be returned) + root processor where data should be gathered (or None if local areas are to be returned) """ self.tool.fillInDiagnosticData(diag, rootPe=rootPe) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py index 79aa812a..d60107ef 100644 --- a/regrid2/Lib/mvLibCFRegrid.py +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -25,12 +25,14 @@ def __init__(self, srcGrid, dstGrid, srcGridMask=None, srcGrid array + dstGrid array + srcBounds cell boundaries - **args keyword arguments, eg mkCyclic, handleCut, ... - to be passed to gsRegrid + + **args keyword arguments, eg mkCyclic, handleCut, ...to be passed to gsRegrid """ self.regridMethodStr = 'linear' self.mkCyclic = args.get('mkCyclic', False) @@ -58,8 +60,7 @@ def computeWeights(self, **args): Parameters ---------- - **args arguments to be passed to gsRegrid, e.g. - nitermax, tolpos, ... + **args arguments to be passed to gsRegrid, e.g. nitermax, tolpos, ... """ nitermax = args.get('nitermax', 20) # make tolpos relative to the min cell size @@ -75,20 +76,19 @@ def apply(self, srcData, dstData, missingValue=None, **args): srcData array (input) + dstData array (output) + missingValue - value that should be set for points falling outside - the src domain, pass None if these should not be touched. + value that should be set for points falling outside the src domain, pass None if these should not be touched. """ self.regridObj.apply(srcData, dstData, missingValue) def getSrcGrid(self): """ - Get the grid of the src data (maybe larger than the - dst grid passed to the constructor due to column/row - padding) + Get the grid of the src data (maybe larger than the dst grid passed to the constructor due to column/row padding) Returns ------- @@ -115,8 +115,7 @@ def fillInDiagnosticData(self, diag, rootPe): ---------- diag - a dictionary whose entries, if present, will be filled - valid entries are: 'numDstPoints' and 'numValid' + a dictionary whose entries, if present, will be filled valid entries are: 'numDstPoints' and 'numValid' rootPe not used """ From 10ddc5bdccfd47c10bf5580eefc3cb689af4e02b Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 16 May 2018 12:22:25 -0700 Subject: [PATCH 126/239] Changes to API --- Lib/avariable.py | 20 +++++++++----------- Lib/axis.py | 28 +++++++++++++++------------- Lib/cache.py | 6 +++--- regrid2/Lib/esmf.py | 39 +++++++++++++++++++++------------------ 4 files changed, 48 insertions(+), 45 deletions(-) diff --git a/Lib/avariable.py b/Lib/avariable.py index f747d460..9a69d76a 100644 --- a/Lib/avariable.py +++ b/Lib/avariable.py @@ -128,22 +128,20 @@ def getNumericCompatibility(): class AbstractVariable(CdmsObj, Slab): + """Not to be called by users. + + Parameters + ---------- + variableNode + is the variable tree node, if any. + parent + is the containing dataset instance. + """ def info(self, flag=None, device=None): Slab.info(self, flag, device) def __init__(self, parent=None, variableNode=None): - """Not to be called by users. - - Parameters - ---------- - - variableNode - is the variable tree node, if any. - parent - is the containing dataset instance. - - """ if variableNode is not None and variableNode.tag != 'variable': raise CDMSError('Node is not a variable node') CdmsObj.__init__(self, variableNode) diff --git a/Lib/axis.py b/Lib/axis.py index f7eac285..a91e631e 100644 --- a/Lib/axis.py +++ b/Lib/axis.py @@ -204,8 +204,8 @@ def mapLinearIntersection(xind, yind, iind, same for right endpoint j - Returns - ------- +Returns +------- True if the coordinate interval (a,b) intersects the node nodeSubI or cell bounds [boundLeft,boundRight], where the interval (a,b) is defined by: @@ -703,11 +703,10 @@ def allclose(ax1, ax2, rtol=1.e-5, atol=1.e-8): """ Parameters ---------- - ax1, ax2: - + ax1 + array_like + ax2 array_like - - _: None Returns ------- @@ -1242,20 +1241,22 @@ def getModulo(self): return(self.getModuloCycle()) def mapInterval(self, interval, indicator='ccn', cycle=None): - """Map coordinate interval to index interval. interval has one of the forms + """Map coordinate interval to index interval. interval has one of the forms: - * `(x,y)` - * `(x,y,indicator)`: indicator overrides keywork argument - * `(x,y,indicator,cycle)`: indicator, cycle override keyword arguments - * `None`: indicates the full interval + * `(x,y)` + * `(x,y,indicator)`: indicator overrides keywork argument + * `(x,y,indicator,cycle)`: indicator, cycle override keyword arguments + * `None`: indicates the full interval - where `x` and `y` are the endpoints in coordinate space. indicator is a + Note: Where `x` and `y` are the endpoints in coordinate space. indicator is a two-character string, where the first character is `c` if the interval is closed on the left, `o` if open, and the second character has the same meaning for the right-hand point. Set cycle to a nonzero value to force wraparound. - Returns the corresponding index interval (i,j), where i. + """ + Get the file with . If the file is in the cache, read it. diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 35accdff..5a8d83f8 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -1,15 +1,16 @@ #!/usr/bin/env python -""" -Copyright (c) 2008-2012, Tech-X Corporation -All rights reserved. +# +# Copyright (c) 2008-2012, Tech-X Corporation +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the conditions +# specified in the license file 'license.txt' are met. +# +# Authors: David Kindig and Alex Pletzer +# -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the conditions -specified in the license file 'license.txt' are met. - -Authors: David Kindig and Alex Pletzer -""" import re import time import numpy @@ -36,20 +37,22 @@ class EsmfUnstructGrid: """ - Unstructured grid + + + Parameters + ---------- + + numTopoDims + number of topological dimensions + + numSpaceDims + number of space dimensions """ def __init__(self, numTopoDims, numSpaceDims): """Constructor - Parameters - ---------- - - numTopoDims - number of topological dimensions - - numSpaceDims - number of space dimensions + """ # handle to the grid object self.grid = None From 12c2f0ec91df96129e4393f51a63c548daae4a87 Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Wed, 16 May 2018 15:55:52 -0700 Subject: [PATCH 127/239] Changes to API --- Lib/convention.py | 2 +- Lib/cudsinterface.py | 22 ++++++++++--------- Lib/database.py | 51 ++++++++++++++++++++------------------------ Lib/variable.py | 44 ++++++++++++++++++++++---------------- 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/Lib/convention.py b/Lib/convention.py index ba32cbad..fa3e31e4 100644 --- a/Lib/convention.py +++ b/Lib/convention.py @@ -227,7 +227,7 @@ def axisIsLongitude(self, axis): return AbstractConvention.axisIsLongitude(self, axis) def getVariableBounds(self, dset, var): - """Get the bounds variable for the variable, from a dataset or file.""" + "Get the bounds variable for the variable, from a dataset or file." if hasattr(var, 'bounds'): boundsid = var.bounds if boundsid in dset.variables: diff --git a/Lib/cudsinterface.py b/Lib/cudsinterface.py index ace6cf94..e91ce10b 100644 --- a/Lib/cudsinterface.py +++ b/Lib/cudsinterface.py @@ -381,7 +381,10 @@ def getattribute(self, vname, attribute): return getattr(v, attribute) def getslab(self, vname, *args, **keys): - """getslab('name', arg1, arg2, ....) + """ + + + getslab ('name', arg1, arg2, ....) returns a cdms variable containing the data. @@ -467,23 +470,22 @@ def getslab(self, vname, *args, **keys): def readScripGrid(self, whichGrid="destination", checkGrid=1): """Read a SCRIP curvilinear or generic grid from the dataset. - The dataset can be a SCRIP grid file or mapping file. If a mapping file, - 'whichGrid' chooses the grid to read, either "source" or "destination". + The dataset can be a SCRIP grid file or mapping file. If a mapping file, 'whichGrid' chooses the grid to read, either "source" or "destination". If 'checkGrid' is 1 (default), the grid cells are checked for convexity, and 'repaired' if necessary. Returns the grid object. - Options + Options - whichGrid - (str) ('destination') grid to read + whichGrid + (str) ('destination') grid to read - checkGrid - (int) (1) if 1 the grid cells are checked for convexity + checkGrid + (int) (1) if 1 the grid cells are checked for convexity - Output grid - (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested + Output grid + (cdms2.hgrid.TransientCurveGrid/cdms2.gengrid.TransientGenericGrid) (0) variable requested """ diff --git a/Lib/database.py b/Lib/database.py index 68488f27..b69ee49e 100644 --- a/Lib/database.py +++ b/Lib/database.py @@ -39,27 +39,24 @@ def connect(uri=None, user="", password=""): """ - Method - ------ - connect(uri=None, user="", password="") + + Method: connect(uri=None, user="", password="") - Description - ----------- - Open a CDMS database connection. + Description: Open a CDMS database connection. Arguments --------- - uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. - user: user id - password: password + uri: Universal Resource Identifier. If unspecified, defaults to the environment variable CDMSROOT. + user: user id + password: password Returns ------- - Database instance. + Database instance. Example ------- - db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US") + db = cdms.connect("ldap://dbhost.llnl.gov/database=CDMS,ou=PCMDI,o=LLNL,c=US") """ if uri is None: try: @@ -338,19 +335,17 @@ def searchFilter(self, filter=None, tag=None, relbase=None, """ Method - searchFilter + searchFilter (filter=None, tag=None, relbase=None, scope=Subtree, attnames=None, timeout=None) Description - Search a CDMS database. + Search a CDMS database. Arguments - - filter: string search filter - Simple filters have the form "tag = value". Simple filters can be combined using - logical operators '&', '|', '!' in prefix notation. For example, - the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. + filter: string search filter + Simple filters have the form "tag = value". Simple filters can be combined using logical operators '&', '|', '!' in prefix notation. For example, the filter '(&(objectclass=variable)(id=cli))' finds all variables named cli. More formally @@ -381,27 +376,27 @@ def searchFilter(self, filter=None, tag=None, relbase=None, Onelevel searches the base object and its immediate descendants. Base searches the base object alone. Default is Subtree. - attnames: - list of attribute names. Restricts the attributes returned. + attnames: + list of attribute names. Restricts the attributes returned. - timeout: - integer number of seconds before timeout. + timeout: + integer number of seconds before timeout. Returns ------- - SearchResult instance. + SearchResult instance. Entries can be accessed sequentially. - For each entry, + For each entry, - entry.name is the name of the entry, - - entry.attributes is a dictionary of the attributes returned by the search, + entry.name is the name of the entry, - entry.getObject() returns the CDMS object associated with the entry: + entry.attributes is a dictionary of the attributes returned by the search, - for entry in result: print entry.name, entry.attributes["id"] + entry.getObject() returns the CDMS object associated with the entry: + + for entry in result: print entry.name, entry.attributes["id"] Entries can be refined with searchPredicate(). diff --git a/Lib/variable.py b/Lib/variable.py index 80028e6b..887ef32a 100644 --- a/Lib/variable.py +++ b/Lib/variable.py @@ -41,15 +41,15 @@ def timeindex(value, units, basetime, delta, delunits, calendar): class DatasetVariable(AbstractVariable): def __init__(self, parent, id, variableNode=None): - """Variable (parent, variableNode=None)" - + """Variable (parent, variableNode=None) + Parameters ---------- - variableNode - is the variable tree node, if any. + variableNode + is the variable tree node, if any. - parent - is the containing dataset instance. + parent + is the containing dataset instance. """ AbstractVariable.__init__(self, parent, variableNode) val = self.__cdms_internals__ + ['domain', 'name_in_file'] @@ -290,11 +290,10 @@ def getPartition(self, axis): Parameters ---------- - axis: - is either a time or level axis. If cdms_filemap is being used, get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. + is either a time or level axis. If cdms_filemap is being used, get the partition from the _varpart_ attribute, otherwise (for templating) use axis.partition. - _: None + _: None """ if hasattr(self.parent, 'cdms_filemap'): @@ -310,24 +309,33 @@ def getPartition(self, axis): def expertPaths(self, slist): """ + + Parameters + ---------- + expertPaths + (self, slicelist) takes a list of slices, + + _: None - expertPaths(self, slicelist) - takes a list of slices, + Returns + ------- + a 3-tuple + (npart, dimensionlist, partitionSlices) - returns a 3-tuple: - (npart, dimensionlist, partitionSlices) + Where: - where: - npart is the number of partitioned dimensions: 0, 1, or 2; + npart + is the number of partitioned dimensions: 0, 1, or 2; - dimensionlist - is a tuple of length npart, having the dimension numbers of the partitioned dimensions; + dimensionlist + is a tuple of length npart, having the dimension numbers of the partitioned dimensions; - partitionSlices + partitionSlices is the list of file-specific (filename, slice) corresponding to the paths and slices within the files to be read. The exact form of partitionSlices depends on the value of npart: + npart partitionSlices 0 (filename,slicelist) From 307496493562e419ea446cfb143534e40a97f82a Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Thu, 17 May 2018 15:30:28 -0700 Subject: [PATCH 128/239] Changes made to API --- Lib/MV2.py | 12 ++---- Lib/dataset.py | 13 +++--- Lib/forecast.py | 25 +++++++----- Lib/gengrid.py | 9 ++--- Lib/grid.py | 9 ++--- Lib/mvBaseWriter.py | 8 ++-- Lib/mvCdmsRegrid.py | 74 +++++++++++++++++----------------- Lib/mvSphereMesh.py | 8 ++-- Lib/mvVTKSGWriter.py | 8 ++-- Lib/mvVTKUGWriter.py | 13 +++--- Lib/mvVsWriter.py | 10 ++--- Lib/slabinterface.py | 14 ++++--- Lib/tvariable.py | 96 ++++++++++++++++++++++++++++---------------- regrid2/Lib/esmf.py | 16 +++----- 14 files changed, 170 insertions(+), 145 deletions(-) diff --git a/Lib/MV2.py b/Lib/MV2.py index db309613..f95d72dd 100644 --- a/Lib/MV2.py +++ b/Lib/MV2.py @@ -561,12 +561,7 @@ def choose(myindices, t): Returns ------- - an array shaped like indices containing elements chosen - from t. - If an element of t is the special element masked, any element - of the result that "chooses" that element is masked. - - The result has only the default axes. + an array shaped like indices containing elements chosen from t. If an element of t is the special element masked, any element of the result that "chooses" that element is masked. The result has only the default axes. """ maresult = numpy.ma.choose(myindices, list(map(_makeMaskedArg, t))) F = getattr(t, "fill_value", 1.e20) @@ -590,8 +585,7 @@ def masked_where(condition, x, copy=1): Returns ------- - x as an array masked where condition is true. - Also masked where x or condition masked. + x as an array masked where condition is true. Also masked where x or condition masked. """ tx = _makeMaskedArg(x) tcondition = _makeMaskedArg(condition) @@ -901,7 +895,7 @@ def asarray(data, typecode=None, dtype=None): Returns ------- - data if dtype is None or data is a MaskedArray of the same dtype. + data if dtype is None or data is a MaskedArray of the same dtype. typecode arg is for backward compatibility. """ dtype = _convdtype(dtype, typecode) diff --git a/Lib/dataset.py b/Lib/dataset.py index b1af3413..af8f9b32 100644 --- a/Lib/dataset.py +++ b/Lib/dataset.py @@ -1751,8 +1751,8 @@ def copyGrid(self, grid, newname=None): Returns ------- - file grid - (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) + file grid: + (cdms2.grid.FileRectGrid/cdms2.hgrid.FileCurveGrid/cdms2.gengrid.FileGenericGrid) """ if newname is None: @@ -2353,15 +2353,14 @@ def getVariable(self, id): Parameters ---------- - id: str - id of the variable to get + id: + str id of the variable to get - _: None + _: None Returns ------- - variable (cdms2.fvariable.FileVariable/None) - file variable + variable (cdms2.fvariable.FileVariable/None) file variable """ return self.variables.get(id) diff --git a/Lib/forecast.py b/Lib/forecast.py index e060e553..ad9aae96 100644 --- a/Lib/forecast.py +++ b/Lib/forecast.py @@ -72,11 +72,9 @@ def comptime(t): class forecast(): - """represents a forecast starting at a single time""" + """represents a forecast starting at a single time - def __init__(self, tau0time, dataset_list, path="."): - """ - Parameters + Parameters ---------- tau0time @@ -97,6 +95,11 @@ def __init__(self, tau0time, dataset_list, path="."): N.B. This is like a CdmsFile. Creating a forecast means opening a file, so later on you should call forecast.close() to close it. + """ + + def __init__(self, tau0time, dataset_list, path="."): + """ + """ self.fctl, self.fct = two_times_from_one(tau0time) @@ -146,12 +149,11 @@ def available_forecasts(dataset_file, path="."): class forecasts(): - """represents a set of forecasts""" + """represents a set of forecasts - def __init__(self, dataset_file, forecast_times, path="."): - """ - Example - ------- + + Example + ------- Creates a set of forecasts. Normally you do it by something like f = forecasts( 'file.xml', (min_time, max_time) ) @@ -191,6 +193,11 @@ def __init__(self, dataset_file, forecast_times, path="."): forecasts.close() . """ + def __init__(self, dataset_file, forecast_times, path="."): + """ + + """ + # Create dataset_list to get a forecast file from each forecast time. self.dataset = cdms2.openDataset(dataset_file, dpath=path) fm = cdms2.dataset.parseFileMap(self.dataset.cdms_filemap) diff --git a/Lib/gengrid.py b/Lib/gengrid.py index 70c29088..23c4c70c 100644 --- a/Lib/gengrid.py +++ b/Lib/gengrid.py @@ -38,13 +38,12 @@ def clone(self, copyData=1): def getMesh(self, transpose=None): """Generate a mesh array for the meshfill graphics method. - + Parameters ---------- - - 'transpose' - - is for compatibility with other grid types, is ignored.""" + 'transpose' + is for compatibility with other grid types, is ignored. + """ from . import MV2 as MV if self._mesh_ is None: diff --git a/Lib/grid.py b/Lib/grid.py index 5b68799a..9ab1c9e8 100644 --- a/Lib/grid.py +++ b/Lib/grid.py @@ -239,11 +239,11 @@ def subSlice(self, *specs, **keys): def hasCoordType(self, coordType): """ - Returns ------- - 1 iff self has the coordinate type.""" + 1 iff self has the coordinate type. + """ return 0 def getAxisList(self): @@ -655,10 +655,7 @@ def flatAxes(self): """ Returns ------- - - (flatlat, flatlon) where flatlat is a 1D NumPy array - having the same length as the number of cells in the grid, similarly - for flatlon.""" + (flatlat, flatlon) where flatlat is a 1D NumPy array having the same length as the number of cells in the grid, similarly for flatlon.""" if self._flataxes_ is None: alat = self.getLatitude()[:] diff --git a/Lib/mvBaseWriter.py b/Lib/mvBaseWriter.py index d464c940..38f76d46 100644 --- a/Lib/mvBaseWriter.py +++ b/Lib/mvBaseWriter.py @@ -1,12 +1,11 @@ #!/usr/bin/env python +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. +#Alex Pletzer, Tech-X Corp. (2011) """ Abstract class for writing data into file -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -Alex Pletzer, Tech-X Corp. (2011) """ from . import mvSphereMesh @@ -14,6 +13,7 @@ class BaseWriter: + def __init__(self, var, sphereRadius=1.0, maxElev=0.1): """ Constructor diff --git a/Lib/mvCdmsRegrid.py b/Lib/mvCdmsRegrid.py index ed3d4734..12d03901 100644 --- a/Lib/mvCdmsRegrid.py +++ b/Lib/mvCdmsRegrid.py @@ -1,9 +1,10 @@ +#David Kindig and Alex Pletzer, Tech-X Corp. (2012) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Cdms2 interface to multiple regridders -David Kindig and Alex Pletzer, Tech-X Corp. (2012) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ from __future__ import print_function import operator @@ -377,51 +378,52 @@ class CdmsRegrid: Regridding switchboard, handles CDMS variables before handing off to regridder. If a multidimensional variable is passed in, the apply step loops over the axes above the Lat (Y) -- Lon (X) coordinates - """ - def __init__(self, srcGrid, dstGrid, dtype, - regridMethod='linear', regridTool='libCF', - srcGridMask=None, srcGridAreas=None, - dstGridMask=None, dstGridAreas=None, - **args): - """ - Establish which regridding method to use, handle CDMS variables before + Establish which regridding method to use, handle CDMS variables before handing off to regridder. See specific tool for more information. - Parameters - ---------- - srcGrid - CDMS source grid + Parameters + ---------- + srcGrid + CDMS source grid - dstGrid - CDMS destination grid + dstGrid + CDMS destination grid - dtype - numpy data type for src and dst data + dtype + numpy data type for src and dst data - regridMethod - linear (all tools - bi, tri), - conserve (ESMF Only) - patch (ESMF Only) + regridMethod + linear (all tools - bi, tri), + conserve (ESMF Only) + patch (ESMF Only) - regridTool - LibCF, ESMF, ... + regridTool + LibCF, ESMF, ... - srcGridMask - array source mask, interpolation coefficients will not be computed for masked - points/cells. + srcGridMask + array source mask, interpolation coefficients will not be computed for masked + points/cells. - srcGridAreas - array destination cell areas, only needed for conservative regridding + srcGridAreas + array destination cell areas, only needed for conservative regridding - dstGridMask - array destination mask, interpolation coefficients will not be computed for masked points/cells. + dstGridMask + array destination mask, interpolation coefficients will not be computed for masked points/cells. - dstGridAreas - array destination cell areas, only needed for conservative regridding + dstGridAreas + array destination cell areas, only needed for conservative regridding + **args + additional, tool dependent arguments + """ - **args - additional, tool dependent arguments + def __init__(self, srcGrid, dstGrid, dtype, + regridMethod='linear', regridTool='libCF', + srcGridMask=None, srcGridAreas=None, + dstGridMask=None, dstGridAreas=None, + **args): + """ + """ srcBounds = None diff --git a/Lib/mvSphereMesh.py b/Lib/mvSphereMesh.py index d673bc78..c0da63e3 100644 --- a/Lib/mvSphereMesh.py +++ b/Lib/mvSphereMesh.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer, Tech-X Corp. (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Class for representing grids on the sphere -Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ from __future__ import print_function diff --git a/Lib/mvVTKSGWriter.py b/Lib/mvVTKSGWriter.py index 8dc7757c..b857e541 100644 --- a/Lib/mvVTKSGWriter.py +++ b/Lib/mvVTKSGWriter.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer, Tech-X Corp. (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Write data to VTK file format using the structured grid format -Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ from __future__ import print_function diff --git a/Lib/mvVTKUGWriter.py b/Lib/mvVTKUGWriter.py index cd877fa5..120f1549 100644 --- a/Lib/mvVTKUGWriter.py +++ b/Lib/mvVTKUGWriter.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer, Tech-X Corp. (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Write data to VTK file format using the unstructured grid format -Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ from __future__ import print_function @@ -22,7 +22,10 @@ def write(self, filename): Parameters ---------- - filename file name + filename + file name + + _:None """ f = open(filename, 'w') print('# vtk DataFile Version 2.0', file=f) diff --git a/Lib/mvVsWriter.py b/Lib/mvVsWriter.py index d18ecd27..1aff8dec 100644 --- a/Lib/mvVsWriter.py +++ b/Lib/mvVsWriter.py @@ -1,10 +1,10 @@ #!/usr/bin/env python - +#Alex Pletzer, Tech-X Corp. (2011) +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. """ Write data to VizSchema compliant file -Alex Pletzer, Tech-X Corp. (2011) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. + """ import numpy @@ -13,7 +13,7 @@ class VsWriter(mvBaseWriter.BaseWriter): - + def write(self, filename): """ Write file diff --git a/Lib/slabinterface.py b/Lib/slabinterface.py index 80c7535f..b978523f 100644 --- a/Lib/slabinterface.py +++ b/Lib/slabinterface.py @@ -11,13 +11,17 @@ class Slab: - """Slab is the cu api + """ + + Parameters + ---------- + Slab + is the cu api - This is an abstract class to inherit in AbstractVariable About axes: + _:None - weight and bounds attributes always set but may be None - if bounds are None, getdimattribute returns result of querying the - axis. + Note: This is an abstract class to inherit in AbstractVariable About axes: + weight and bounds attributes always set but may be None if bounds are None, getdimattribute returns result of querying the axis. """ std_slab_atts = ['filename', 'missing_value', diff --git a/Lib/tvariable.py b/Lib/tvariable.py index faa2f6e8..e4ab46c7 100644 --- a/Lib/tvariable.py +++ b/Lib/tvariable.py @@ -152,10 +152,12 @@ def __init__(self, data, typecode=None, copy=1, savespace=0, mask=numpy.ma.nomask, fill_value=None, grid=None, axes=None, attributes=None, id=None, copyaxes=1, dtype=None, order='C', no_update_from=False, **kargs): - """createVariable (self, data, typecode=None, copy=0, savespace=0, - mask=None, fill_value=None, grid=None, - axes=None, attributes=None, id=None, dtype=None, order='C') - The savespace argument is ignored, for backward compatibility only. + """ + Parameters + ---------- + + createVariable + (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order='C') The savespace argument is ignored, for backward compatibility only. """ try: if data.fill_value is not None: @@ -256,10 +258,13 @@ def _setmissing(self, value): def __new__(cls, data, typecode=None, copy=0, savespace=0, mask=numpy.ma.nomask, fill_value=None, grid=None, axes=None, attributes=None, id=None, copyaxes=1, dtype=None, order='C', **kargs): - """createVariable (self, data, typecode=None, copy=0, savespace=0, - mask=None, fill_value=None, grid=None, - axes=None, attributes=None, id=None, dtype=None, order='C') - The savespace argument is ignored, for backward compatibility only. + """ + + Parameters + ---------- + + createVariable + (self, data, typecode=None, copy=0, savespace=0, mask=None, fill_value=None, grid=None, axes=None, attributes=None, id=None, dtype=None, order='C') The savespace argument is ignored, for backward compatibility only. """ # Compatibility: assuming old typecode, map to new if dtype is None and typecode is not None: @@ -556,9 +561,20 @@ def setdimattribute(self, dim, field, value): setattr(d, field, value) def clone(self, copyData=1): - """clone (self, copyData=1) - Return a copy of self as a transient variable. - If copyData is 1 (default), make a separate copy of the data.""" + """ + + Parameters + ---------- + + clone + (self, copyData=1) + + _: None + + Returns + ------- + + a copy of self as a transient variable. If copyData is 1 (default), make a separate copy of the data.""" result = createVariable(self, copy=copyData) return result @@ -774,12 +790,17 @@ def getHaloEllipsis(self, side): """ Get the ellipsis for a given halo side. - side - a tuple of zeros and one +1 or -1. To access - the "north" side for instance, set side=(1, 0), - (-1, 0) to access the south side, (0, 1) the east - side, etc. This does not involve any communication. + Parameters + ---------- + + side: + a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east side, etc. This does not involve any communication. + + _:None - Return none if halo was not exposed (see exposeHalo) + Returns + ------- + none if halo was not exposed (see exposeHalo) """ if HAVE_MPI and side in self.__mpiWindows: return self.__mpiWindows[side]['slab'] @@ -788,22 +809,18 @@ def getHaloEllipsis(self, side): def fetchHaloData(self, pe, side): """ - Fetch the halo data from another processor. The halo side - is a subdomain of the halo that is exposed to other - processors. It is an error to call this method when - MPI is not enabled. This is a collective method (must - be called by all processes), which involves synchronization - of data among all processors. + Fetch the halo data from another processor. The halo side is a subdomain of the halo that is exposed to other processors. It is an error to call this method when MPI is not enabled. This is a collective method (must be called by all processes), which involves synchronization of data among all processors. - pe - processor owning the halo data. This is a no - operation when pe is None. - side - a tuple of zeros and one +1 or -1. To access - the "north" side for instance, set side=(1, 0), - (-1, 0) to access the south side, (0, 1) the east - side, etc. + Parameters + ---------- + + pe: + processor owning the halo data. This is a no operation when pe is None. - Note: collective, all procs must invoke this method. If some - processors should not fetch then pass None for pe. + side: + a tuple of zeros and one +1 or -1. To access the "north" side for instance, set side=(1, 0), (-1, 0) to access the south side, (0, 1) the east side, etc. + + Note: collective, all procs must invoke this method. If some processors should not fetch then pass None for pe. """ if HAVE_MPI: iw = self.__mpiWindows[side] @@ -833,13 +850,22 @@ def freeHalo(self): def __getSlab(self, dim, slce): """ - Get slab. A slab is a multi-dimensional slice extending in - all directions except along dim where slce applies + Parameters + ---------- + + Get slab: + A slab is a multi-dimensional slice extending in all directions except along dim where slce applies + + dim: + dimension (0=first index, 1=2nd index...) + + slce: + python slice object along dimension dim - dim - dimension (0=first index, 1=2nd index...) - slce - python slice object along dimension dim + Returns + ------- - return slab + slab """ ndims = len(self.shape) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 5a8d83f8..3a4faf94 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -76,22 +76,16 @@ def __init__(self, numTopoDims, numSpaceDims): def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): - """ - Set Cell connectivity + """Set Cell connectivity Parameters ---------- - - cell indices: - - (0-based) - + cell indices: + 0-based) cellTypes: - one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - + one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} connectivity node: - connectivity array, see below for node ordering - + connectivity array, see below for node ordering cellMask: cellAreas area (volume) of each cell From b9e04a6daf3cc3b1bc587e5549d72c20b091eb3a Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Fri, 18 May 2018 11:46:40 -0700 Subject: [PATCH 129/239] Changes made to API --- regrid2/Lib/esmf.py | 81 ++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 3a4faf94..008ce4d6 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -78,16 +78,16 @@ def setCells(self, cellIndices, cellTypes, connectivity, cellMask=None, cellAreas=None): """Set Cell connectivity - Parameters - ---------- - cell indices: - 0-based) +Parameters +---------- + cellIndices: + 0-based) cellTypes: - one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} - connectivity node: - connectivity array, see below for node ordering + one of ESMF_MESHELEMTYPE_{TRI,QUAD,TETRA,HEX} + connectivityNode: + connectivity array, see below for node ordering cellMask: - cellAreas area (volume) of each cell + cellAreas area (volume) of each cell Note ---- @@ -182,16 +182,11 @@ def __del__(self): class EsmfStructGrid: """ Structured grid - """ - def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, - periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, - hasBounds=False): - """ - Constructor - - Parameters - ---------- + Constructor + +Parameters +---------- shape Tuple of cell sizes along each axis @@ -214,6 +209,13 @@ def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, hasBounds If the grid has bounds, Run AddCoords for the bounds + """ + + def __init__(self, shape, coordSys=ESMF.CoordSys.SPH_DEG, + periodicity=0, staggerloc=ESMF.StaggerLoc.CENTER, + hasBounds=False): + """ + """ # ESMF grid object self.grid = None @@ -286,8 +288,7 @@ def getLocalSlab(self, staggerloc): def getLoHiBounds(self, staggerloc): """ - Get the local lo/hi index values for the coordinates (per processor) - (hi is not inclusive, lo <= index < hi) + Get the local lo/hi index values for the coordinates (per processor) (hi is not inclusive, lo <= index < hi) Parameters ---------- @@ -453,14 +454,11 @@ def __del__(self): class EsmfStructField: """ Structured field. - """ - def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): - """ - Creator for structured ESMF Field + Creator for structured ESMF Field - Parameters - ---------- +Parameters +---------- esmfGrid instance of an ESMF @@ -475,6 +473,11 @@ def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): staggerloc ESMF.StaggerLoc.CENTER ESMF.StaggerLoc.CORNER + """ + + def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER): + """ + """ # field object self.field = None @@ -613,21 +616,11 @@ def setLocalData(self, data, staggerloc, globalIndexing=False): class EsmfRegrid: """ Regrid source grid data to destination grid data - """ - def __init__(self, srcField, dstField, - srcFrac=None, - dstFrac=None, - srcMaskValues=None, - dstMaskValues=None, - regridMethod=BILINEAR, - ignoreDegenerate=False, - unMappedAction=IGNORE): - """ - Constuct regrid object + Constuct regrid object - Parameters - ---------- +Parameters +---------- srcField the source field object of type EsmfStructField @@ -655,6 +648,18 @@ def __init__(self, srcField, dstField, ignoreDegenerate Ignore degenerate cells when checking inputs + """ + + def __init__(self, srcField, dstField, + srcFrac=None, + dstFrac=None, + srcMaskValues=None, + dstMaskValues=None, + regridMethod=BILINEAR, + ignoreDegenerate=False, + unMappedAction=IGNORE): + """ + """ self.srcField = srcField self.dstField = dstField From 651ae1cabd13d5129b94c496a44eb8432a69634a Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Mon, 21 May 2018 14:59:02 -0700 Subject: [PATCH 130/239] Changes made to API --- regrid2/Lib/esmf.py | 4 ++- regrid2/Lib/mvESMFRegrid.py | 55 +++++++++++++++++----------------- regrid2/Lib/mvGenericRegrid.py | 39 +++++++++++++----------- regrid2/Lib/mvLibCFRegrid.py | 10 ++++--- regrid2/Lib/scrip.py | 14 +++++++-- 5 files changed, 69 insertions(+), 53 deletions(-) diff --git a/regrid2/Lib/esmf.py b/regrid2/Lib/esmf.py index 008ce4d6..f3e37936 100644 --- a/regrid2/Lib/esmf.py +++ b/regrid2/Lib/esmf.py @@ -91,7 +91,9 @@ def setCells(self, cellIndices, cellTypes, connectivity, Note ---- - +.. figure:: /images/ESMF.jpg + :scale: 95% + :alt: 3 4-------------3 /\ | | / \ | | diff --git a/regrid2/Lib/mvESMFRegrid.py b/regrid2/Lib/mvESMFRegrid.py index 58b3cf22..788928e0 100644 --- a/regrid2/Lib/mvESMFRegrid.py +++ b/regrid2/Lib/mvESMFRegrid.py @@ -1,10 +1,11 @@ -""" -ESMF regridding class +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. +# +#David Kindig and Alex Pletzer, Tech-X Corp. (2012) -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. -David Kindig and Alex Pletzer, Tech-X Corp. (2012) +""" +ESMF regridding class """ import re import numpy @@ -37,19 +38,10 @@ class ESMFRegrid(GenericRegrid): """ Regrid class for ESMF - """ - - def __init__(self, srcGridshape, dstGridshape, dtype, - regridMethod, staggerLoc, periodicity, coordSys, - srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, - dstGridMask=None, hasDstBounds=False, dstGridAreas=None, - ignoreDegenerate=False, - **args): - """ - Constructor + Constructor - Parameters - ---------- + Parameters + ---------- srcGridShape tuple source grid shape @@ -68,8 +60,8 @@ def __init__(self, srcGridshape, dstGridshape, dtype, periodicity 0 (no periodicity), - 1 (last coordinate is periodic, - 2 (both coordinates are periodic) + 1 (last coordinate is periodic, + 2 (both coordinates are periodic) coordSys 'deg', 'cart', or 'rad' @@ -82,6 +74,16 @@ def __init__(self, srcGridshape, dstGridshape, dtype, ignoreDegenerate Ignore degenerate celss when checking inputs + """ + + def __init__(self, srcGridshape, dstGridshape, dtype, + regridMethod, staggerLoc, periodicity, coordSys, + srcGridMask=None, hasSrcBounds=False, srcGridAreas=None, + dstGridMask=None, hasDstBounds=False, dstGridAreas=None, + ignoreDegenerate=False, + **args): + """ + """ # esmf grid objects (tobe constructed) @@ -305,7 +307,8 @@ def computeWeights(self, **args): Parameters ---------- - **args (not used) + **args + (not used) _: None """ @@ -396,17 +399,15 @@ def getSrcAreas(self, rootPe): """ Get the source grid cell areas - Parameters - ---------- +Parameters +---------- rootPe - root processor where data should be gathered (or None if local areas - are to be returned) + root processor where data should be gathered (or None if local areas are to be returned) _: None Returns ------- - areas or None if non-conservative interpolation """ @@ -444,8 +445,8 @@ def getSrcAreaFractions(self, rootPe): """ Get the source grid area fractions - Parameters - ---------- +Parameters +---------- rootPe root processor where data should be gathered (or None if local areas are to be returned) diff --git a/regrid2/Lib/mvGenericRegrid.py b/regrid2/Lib/mvGenericRegrid.py index 0719bd3c..ae380e4e 100644 --- a/regrid2/Lib/mvGenericRegrid.py +++ b/regrid2/Lib/mvGenericRegrid.py @@ -1,10 +1,10 @@ +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. +# +#David Kindig and Alex Pletzer, Tech-X Corp. (2012) + """ Generic interface to multiple regrid classes. No dependence on cdms2 variables. - -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) """ import operator import numpy @@ -56,25 +56,17 @@ def guessPeriodicity(srcBounds): class GenericRegrid: """ Generic Regrid class. - """ + Constructor - def __init__(self, srcGrid, dstGrid, - dtype, - regridMethod, - regridTool, - srcGridMask=None, srcBounds=None, srcGridAreas=None, - dstGridMask=None, dstBounds=None, dstGridAreas=None, - **args): - """ - Constructor +Parameters +---------- srcGrid list of numpy arrays, source horizontal coordinates dstGrid list of numpy arrays, destination horizontal coordinate - dtype numpy data type for src/dst data @@ -106,6 +98,17 @@ def __init__(self, srcGrid, dstGrid, additional arguments to be passed to the specific tool libcf': mkCyclic={True, False}, handleCut={True,False} 'esmf': periodicity={0,1}, coordSys={'deg', 'cart'}, ... + """ + + def __init__(self, srcGrid, dstGrid, + dtype, + regridMethod, + regridTool, + srcGridMask=None, srcBounds=None, srcGridAreas=None, + dstGridMask=None, dstBounds=None, dstGridAreas=None, + **args): + """ + """ self.nGridDims = len(srcGrid) @@ -199,8 +202,8 @@ def apply(self, srcData, dstData, """ Regrid source to destination - Parameters - ---------- +Parameters +---------- srcData array (input) diff --git a/regrid2/Lib/mvLibCFRegrid.py b/regrid2/Lib/mvLibCFRegrid.py index d60107ef..563cc193 100644 --- a/regrid2/Lib/mvLibCFRegrid.py +++ b/regrid2/Lib/mvLibCFRegrid.py @@ -1,10 +1,12 @@ +#This code is provided with the hope that it will be useful. +#No guarantee is provided whatsoever. Use at your own risk. +# +#David Kindig and Alex Pletzer, Tech-X Corp. (2012) + + """ LibCF regridding class -This code is provided with the hope that it will be useful. -No guarantee is provided whatsoever. Use at your own risk. - -David Kindig and Alex Pletzer, Tech-X Corp. (2012) """ from regrid2 import gsRegrid diff --git a/regrid2/Lib/scrip.py b/regrid2/Lib/scrip.py index 8af37699..6f451be2 100644 --- a/regrid2/Lib/scrip.py +++ b/regrid2/Lib/scrip.py @@ -225,9 +225,17 @@ def __init__(self, outputGrid, remapMatrix, sourceAddress, destFrac=destFrac) def __call__(self, input, gradLat, gradLon, gradLatlon): - """gradLat = df/di - gradLon = df/dj - gradLatlon = d(df)/(di)(dj) + """ + Parameters + ---------- + gradLat: + df/di + + gradLon: + df/dj + + gradLatlon: + d(df)/(di)(dj) """ import numpy.ma From 1c91ea5ff2582cd275a659861986304af7331dff Mon Sep 17 00:00:00 2001 From: Tanya Reshel Date: Tue, 22 May 2018 15:32:00 -0700 Subject: [PATCH 131/239] push latest rst files --- docs/source/CDML.rst | 7 +++++++ docs/source/CDMLParser.rst | 7 +++++++ docs/source/MV2.rst | 7 +++++++ docs/source/bindex.rst | 7 +++++++ docs/source/cache.rst | 7 +++++++ docs/source/cdmsNode.rst | 7 +++++++ docs/source/cdmsobj.rst | 7 +++++++ docs/source/cdscan.rst | 7 +++++++ docs/source/cdurllib.rst | 7 +++++++ docs/source/cdurlparse.rst | 7 +++++++ docs/source/cdxmllib.rst | 7 +++++++ docs/source/convention.rst | 7 +++++++ docs/source/coord.rst | 7 +++++++ docs/source/crossSection.rst | 7 +++++++ docs/source/cudsinterface.rst | 7 +++++++ docs/source/database.rst | 7 +++++++ docs/source/dataset .rst | 7 +++++++ docs/source/esmf.rst | 7 +++++++ docs/source/forecast.rst | 7 +++++++ docs/source/gengrid.rst | 7 +++++++ docs/source/grid.rst | 7 +++++++ docs/source/gsRegrid.rst | 7 +++++++ docs/source/gs_horizontal.rst | 7 +++++++ docs/source/hgrid.rst | 9 +++++++++ docs/source/manual/docs/vcs_quick_ref.pdf | Bin 0 -> 15875 bytes docs/source/manual/images/vcs_quick_ref.jpg | Bin 0 -> 490749 bytes docs/source/mvBaseWriter.rst | 6 ++++++ docs/source/mvCdmsRegrid.rst | 5 +++++ docs/source/mvESMFRegrid.rst | 7 +++++++ docs/source/mvGenericRegrid.rst | 7 +++++++ docs/source/mvLibCFRegrid.rst | 7 +++++++ docs/source/mvSphereMesh.rst | 6 ++++++ docs/source/mvVTKSGWriter.rst | 8 ++++++++ docs/source/mvVTKUGWriter.rst | 9 +++++++++ docs/source/mvVsWriter.rst | 7 +++++++ docs/source/mySphereMesh.rst | 6 ++++++ docs/source/pressure.rst | 7 +++++++ docs/source/restApi.rst | 9 +++++++++ docs/source/scrip.rst | 7 +++++++ docs/source/selectors.rst | 5 +++++ docs/source/slabinterface.rst | 9 +++++++++ docs/source/tanya_2.rst | 7 +++++++ docs/source/tvariable.rst | 5 +++++ docs/source/variable.rst | 7 +++++++ regrid2/Lib/mvGenericRegrid.py | 1 + 45 files changed, 295 insertions(+) create mode 100644 docs/source/CDML.rst create mode 100644 docs/source/CDMLParser.rst create mode 100644 docs/source/MV2.rst create mode 100644 docs/source/bindex.rst create mode 100644 docs/source/cache.rst create mode 100644 docs/source/cdmsNode.rst create mode 100644 docs/source/cdmsobj.rst create mode 100644 docs/source/cdscan.rst create mode 100644 docs/source/cdurllib.rst create mode 100644 docs/source/cdurlparse.rst create mode 100644 docs/source/cdxmllib.rst create mode 100644 docs/source/convention.rst create mode 100644 docs/source/coord.rst create mode 100644 docs/source/crossSection.rst create mode 100644 docs/source/cudsinterface.rst create mode 100644 docs/source/database.rst create mode 100644 docs/source/dataset .rst create mode 100644 docs/source/esmf.rst create mode 100644 docs/source/forecast.rst create mode 100644 docs/source/gengrid.rst create mode 100644 docs/source/grid.rst create mode 100644 docs/source/gsRegrid.rst create mode 100644 docs/source/gs_horizontal.rst create mode 100644 docs/source/hgrid.rst create mode 100644 docs/source/manual/docs/vcs_quick_ref.pdf create mode 100644 docs/source/manual/images/vcs_quick_ref.jpg create mode 100644 docs/source/mvBaseWriter.rst create mode 100644 docs/source/mvCdmsRegrid.rst create mode 100644 docs/source/mvESMFRegrid.rst create mode 100644 docs/source/mvGenericRegrid.rst create mode 100644 docs/source/mvLibCFRegrid.rst create mode 100644 docs/source/mvSphereMesh.rst create mode 100644 docs/source/mvVTKSGWriter.rst create mode 100644 docs/source/mvVTKUGWriter.rst create mode 100644 docs/source/mvVsWriter.rst create mode 100644 docs/source/mySphereMesh.rst create mode 100644 docs/source/pressure.rst create mode 100644 docs/source/restApi.rst create mode 100644 docs/source/scrip.rst create mode 100644 docs/source/selectors.rst create mode 100644 docs/source/slabinterface.rst create mode 100644 docs/source/tanya_2.rst create mode 100644 docs/source/tvariable.rst create mode 100644 docs/source/variable.rst diff --git a/docs/source/CDML.rst b/docs/source/CDML.rst new file mode 100644 index 00000000..109a93b0 --- /dev/null +++ b/docs/source/CDML.rst @@ -0,0 +1,7 @@ +CDML +==== + +.. automodule:: Lib.CDML + :members: + + diff --git a/docs/source/CDMLParser.rst b/docs/source/CDMLParser.rst new file mode 100644 index 00000000..259442d2 --- /dev/null +++ b/docs/source/CDMLParser.rst @@ -0,0 +1,7 @@ +CDMLParser +========== + +.. automodule:: Lib.CDMLParser + :members: + + diff --git a/docs/source/MV2.rst b/docs/source/MV2.rst new file mode 100644 index 00000000..e0ade528 --- /dev/null +++ b/docs/source/MV2.rst @@ -0,0 +1,7 @@ +MV2 +=== + +.. automodule:: Lib.MV2 + :members: + + diff --git a/docs/source/bindex.rst b/docs/source/bindex.rst new file mode 100644 index 00000000..bac32540 --- /dev/null +++ b/docs/source/bindex.rst @@ -0,0 +1,7 @@ +bindex +====== + +.. automodule:: Lib.bindex + :members: + + diff --git a/docs/source/cache.rst b/docs/source/cache.rst new file mode 100644 index 00000000..ec91bd2b --- /dev/null +++ b/docs/source/cache.rst @@ -0,0 +1,7 @@ +cache +===== + +.. automodule:: Lib.cache + :members: + + diff --git a/docs/source/cdmsNode.rst b/docs/source/cdmsNode.rst new file mode 100644 index 00000000..f67a4dd0 --- /dev/null +++ b/docs/source/cdmsNode.rst @@ -0,0 +1,7 @@ +cdmsobj +======= + +.. automodule:: Lib.cdmsobj + :members: + + diff --git a/docs/source/cdmsobj.rst b/docs/source/cdmsobj.rst new file mode 100644 index 00000000..f67a4dd0 --- /dev/null +++ b/docs/source/cdmsobj.rst @@ -0,0 +1,7 @@ +cdmsobj +======= + +.. automodule:: Lib.cdmsobj + :members: + + diff --git a/docs/source/cdscan.rst b/docs/source/cdscan.rst new file mode 100644 index 00000000..d1b0275e --- /dev/null +++ b/docs/source/cdscan.rst @@ -0,0 +1,7 @@ +cdscan +====== + +.. automodule:: Lib.cdscan + :members: + + diff --git a/docs/source/cdurllib.rst b/docs/source/cdurllib.rst new file mode 100644 index 00000000..3c886ec9 --- /dev/null +++ b/docs/source/cdurllib.rst @@ -0,0 +1,7 @@ +cdurllib +======== + +.. automodule:: Lib.cdurllib + :members: + + diff --git a/docs/source/cdurlparse.rst b/docs/source/cdurlparse.rst new file mode 100644 index 00000000..99603cb9 --- /dev/null +++ b/docs/source/cdurlparse.rst @@ -0,0 +1,7 @@ +cdurlparse +========== + +.. automodule:: Lib.cdurlparse + :members: + + diff --git a/docs/source/cdxmllib.rst b/docs/source/cdxmllib.rst new file mode 100644 index 00000000..35efb257 --- /dev/null +++ b/docs/source/cdxmllib.rst @@ -0,0 +1,7 @@ +cdxmllib +======== + +.. automodule:: Lib.cdxmllib + :members: + + diff --git a/docs/source/convention.rst b/docs/source/convention.rst new file mode 100644 index 00000000..66e90a58 --- /dev/null +++ b/docs/source/convention.rst @@ -0,0 +1,7 @@ +convention +========== + +.. automodule:: Lib.convention + :members: + + diff --git a/docs/source/coord.rst b/docs/source/coord.rst new file mode 100644 index 00000000..95c33f93 --- /dev/null +++ b/docs/source/coord.rst @@ -0,0 +1,7 @@ +coord +===== + +.. automodule:: Lib.coord + :members: + + diff --git a/docs/source/crossSection.rst b/docs/source/crossSection.rst new file mode 100644 index 00000000..9a02a523 --- /dev/null +++ b/docs/source/crossSection.rst @@ -0,0 +1,7 @@ +regrid2- crossSection +===================== + +.. automodule:: Libregrid.crossSection + :members: + + diff --git a/docs/source/cudsinterface.rst b/docs/source/cudsinterface.rst new file mode 100644 index 00000000..8d5707a4 --- /dev/null +++ b/docs/source/cudsinterface.rst @@ -0,0 +1,7 @@ +cudsinterface +============= + +.. automodule:: Lib.cudsinterface + :members: + + diff --git a/docs/source/database.rst b/docs/source/database.rst new file mode 100644 index 00000000..0eae3466 --- /dev/null +++ b/docs/source/database.rst @@ -0,0 +1,7 @@ +database +======== + +.. automodule:: Lib.database + :members: + + diff --git a/docs/source/dataset .rst b/docs/source/dataset .rst new file mode 100644 index 00000000..02698c18 --- /dev/null +++ b/docs/source/dataset .rst @@ -0,0 +1,7 @@ +dataset +======= + +.. automodule:: Lib.dataset + :members: + + diff --git a/docs/source/esmf.rst b/docs/source/esmf.rst new file mode 100644 index 00000000..8e6dd740 --- /dev/null +++ b/docs/source/esmf.rst @@ -0,0 +1,7 @@ +regrid2- esmf +============= + +.. automodule:: Libregrid.esmf + :members: + + diff --git a/docs/source/forecast.rst b/docs/source/forecast.rst new file mode 100644 index 00000000..80cd9352 --- /dev/null +++ b/docs/source/forecast.rst @@ -0,0 +1,7 @@ +forecast +======== + +.. automodule:: Lib.forecast + :members: + + diff --git a/docs/source/gengrid.rst b/docs/source/gengrid.rst new file mode 100644 index 00000000..389e5ca4 --- /dev/null +++ b/docs/source/gengrid.rst @@ -0,0 +1,7 @@ +gengrid +======= + +.. automodule:: Lib.gengrid + :members: + + diff --git a/docs/source/grid.rst b/docs/source/grid.rst new file mode 100644 index 00000000..8ae39c33 --- /dev/null +++ b/docs/source/grid.rst @@ -0,0 +1,7 @@ +grid +==== + +.. automodule:: Lib.grid + :members: + + diff --git a/docs/source/gsRegrid.rst b/docs/source/gsRegrid.rst new file mode 100644 index 00000000..495dcc07 --- /dev/null +++ b/docs/source/gsRegrid.rst @@ -0,0 +1,7 @@ +regrid2-gsRegrid +================ + +.. automodule:: Libregrid.gsRegrid + :members: + + diff --git a/docs/source/gs_horizontal.rst b/docs/source/gs_horizontal.rst new file mode 100644 index 00000000..a7b54048 --- /dev/null +++ b/docs/source/gs_horizontal.rst @@ -0,0 +1,7 @@ +regrid2-gs_horizontal +===================== + +.. automodule:: Libregrid.gs_horizontal + :members: + + diff --git a/docs/source/hgrid.rst b/docs/source/hgrid.rst new file mode 100644 index 00000000..b8d069ea --- /dev/null +++ b/docs/source/hgrid.rst @@ -0,0 +1,9 @@ +hgrid +===== + +.. automodule:: Lib.hgrid + :members: + + +.. automodule:: Lib.hgrid.AbstractHorizontalGrid + :members: \ No newline at end of file diff --git a/docs/source/manual/docs/vcs_quick_ref.pdf b/docs/source/manual/docs/vcs_quick_ref.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6356afa28881bc3f1df57c7f42185b5356bc3191 GIT binary patch literal 15875 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 w)$=Hdxm-{TWnZ&N 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